I'm trying to calculate the maximum value of a set of constants at compile time inside a Rust procedural macro (a derive macro).
The macro looks something like:
fn get_max_len() -> TokenStream {
// Each TokenStream represents a constant expression
let len: Vec<TokenStream> = get_constant_lengths();
quote! {
// #(#len),* gets expanded to #len[0], #len[1], #len[2]...
const LEN: usize = std::cmp::max(#(#len),*);
}
}
The problem is that std::cmp::max
is a function and hence can't be used inside a constant expression (at least until const fn
is stabilized - I want to keep to stable Rust if at all possible).
How can I calculate the max of a set of constants at compile-time?
I might be able to write a max!
macro that basically constructs a huge chain of if
s recursively, but I'm hoping there is a cleaner solution out there.
While constant evaluation does not support if
or other control flow, there is a way to select values depending on binary conditions:
[a, b][(a < b) as usize]
What this does is
usize
The first element is chosen if the condition is false
, the second element is chosen if the condition is true
.
While this scheme can theoretically be extended to arbitrary length arrays by computing indices via mathematical operations on multiple casted bool
s, it seems simpler to just go the functional way and nest the above expression:
const fn max(a: usize, b: usize) -> usize {
[a, b][(a < b) as usize]
}
const MAX: usize = max(max(max(5, 6), 42), 3);
Starting with Rust 1.31, const fn
is usable on the stable compiler.