In my crate weight_matchers, I managed to build a specialised binary tree in const Rust. As I explained in the blog, the constraints of const forced me to move part of the code out of the impl, into a macro.
This left open a back door into the data. I should close that after the constructor macro finished. To this end I’m experimenting with a simple typestate, a bool that distinguishes when I’m done with building. I move all my construction support stuff into this impl, which is fine. Only the final method barks.
// Default BUILT to the desired final state, so callers don’t need to bother with it.
pub struct Weights<W, V, const LEN: usize, const BUILT: bool = true> {
nodes: [(W, W, V); LEN],
}
impl<W: PartialOrd + Default, V, const LEN: usize> Weights<W, V, LEN, false> {
pub const fn build(self) -> Weights<W, V, LEN> {
Weights::<W, V, LEN> { nodes: self.nodes }
}
}
So, I’m removing the zero cost newtype wrapper, and replacing it with essentially the same (but for the value of the const
.) Yet the compiler complains. I wonder what drop even means in this context. Even if I had an impl Drop
, it should get optimised away, when I’m reusing the whole content?
error[E0493]: destructor of `Weights<W, V, LEN, false>` cannot be evaluated at compile-time
--> src/lib.rs:179:24
|
179 | pub const fn build(self) -> Weights<W, V, LEN> {
| ^^^^ the destructor for this type cannot be evaluated in constant functions
180 | Weights::<W, V, LEN> { nodes: self.nodes }
181 | }
| - value is dropped here
I tried a different aproach (even though unsafe
seems overblown for my purpose.)
pub const fn build2(self) -> Weights<W, V, LEN> {
unsafe { std::mem::transmute(self) }
}
All else being equal, surely the two incarnations Weights<_, _, _, false>
and Weights<_, _, _>
must have the same size. But the compiler is getting muddled about that.
error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
--> src/lib.rs:184:18
|
184 | unsafe { std::mem::transmute(self) }
| ^^^^^^^^^^^^^^^^^^^
|
= note: source type: `Weights<W, V, LEN, false>` (size can vary because of [(W, W, V); LEN])
= note: target type: `Weights<W, V, LEN>` (size can vary because of [(W, W, V); LEN])