I'm trying to migrate some C++ code to Rust. I have tried lots of different approaches but none of them compile.
I want a generic template that can handle different types and has a adjustable total size with a static field (const expression) Capacity
:
template<class KeyType, class ValueType, int PageSize>
struct BplusTreeLeaf {
static const uint16_t Capacity = (PageSize-16)/(sizeof(KeyType)+sizeof(ValueType));
KeyType keys[Capacity];
ValueType values[Capacity];
};
I want to access the capacity from outside:
for(int i = 0; i < BplusTreeLeaf<x, y, 4096>::Capacity; i ++) { ... }
It seems that there is no way to do something like this in Rust, or at least in my understanding of Rust:
static
is not allowed in a struct and the documentation tells me to use macrosThis is as far as I got:
macro_rules! BplusTreeLeaf {
($KeyType:ident, $ValueType:ident, $PageSize:expr) => {
static Capacity_: u16 = ($PageSize - 16) / (std::mem::size_of::<$KeyType>() + std::mem::size_of::<$ValueType>());
struct BplusTreeLeaf_ {
keys: [$KeyType, ..Capacity_],
values: [$ValueType, ..Capacity_],
}
}
}
BplusTreeLeaf!(u64, u64, 4096)
The compiler yields "expected constant expr for vector length" which is incorrect because I did not use "mut" for Capacity_
, so it has to be a const expression. Even if it would work, Capacity_
and BplusTreeLeaf_
would still be in the global scope/namespace.
Have I misunderstood something elementary in Rust's design or is it just impossible? If it isn't possible now, is there something planned as a future feature or should I stay with C++ 11?
6) Static variables should not be declared inside structure. The reason is C compiler requires the entire structure elements to be placed together (i.e.) memory allocation for structure members should be contiguous.
static int is a variable storing integer values which is declared static. If we declare a variable as static, it exists till the end of the program once initialized.
The reason for this is simple, static members are only declared in a class declaration, not defined. They must be explicitly defined outside the class using the scope resolution operator. If we try to access static member 'a' without an explicit definition of it, we will get a compilation error.
The primary feature you are looking for is called const generics. Basic support is available in Rust 1.51:
struct BplusTreeLeaf<K, V, const CAP: usize> {
keys: [K; CAP],
values: [V; CAP],
}
impl<K, V, const CAP: usize> BplusTreeLeaf<K, V, CAP> {
const CAPACITY: usize = CAP;
}
fn main() {
println!("{}", BplusTreeLeaf::<u8, f32, 16>::CAPACITY);
println!("{}", BplusTreeLeaf::<i32, bool, 32>::CAPACITY);
}
As you mentioned, you can create a macro for previous versions of Rust which will create one-off types with a specific capacity:
macro_rules! make_leaf {
($name:ident, $capacity:expr) => {
struct $name<K, V> {
keys: [K; $capacity],
values: [V; $capacity],
}
impl<K, V> $name<K, V> {
const CAPACITY: usize = $capacity;
}
}
}
make_leaf!(BplusTreeLeaf16, 16);
make_leaf!(BplusTreeLeaf32, 32);
fn main() {
println!("{}", BplusTreeLeaf16::<u8, f32>::CAPACITY);
println!("{}", BplusTreeLeaf32::<i32, bool>::CAPACITY);
}
See also:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With