One of the nice things about Option is that you can put values in it:
let x = None;
*x = Some(10);
But then you pay the cost of unwrapping it every time:
println!("{}", x.unwrap());
What if you could have the best of both worlds: safe initialization, and safe unchecked unwrap?
The QCell crate brings with it a QCell type, which, while it does take up extra memory for the owner ID, it also provides a safe wrapper around UnsafeCell. What if we could similarly provide a safe wrapper around Option::unwrap_unchecked?
Transmuting MaybeUninit<T> to T is unsound as layouts can change... but we can transmute 'id and 'static. So... maybe the solution is to brand our MaybeUninit<'id, T> with a lifetime and transmute it to 'static when we know it's fully initialized? We can also still have checked unwraps during initialization, if we want them. Is this doable? cc @steffahn
It would be possible to have a method that takes a T, writes it to the MaybeUninit, and then returns a type that behaves like &mut T, except that it runs the destructor of the value when dropped.
So like, here's the use-case: we have selfref. it is slow. in particular, it is slower than C, because the way to get to the &'selfref Foo<'selfref> requires the use of foo: Cell<Option<&'selfref Foo<'selfref>>>, and foo.get().unwrap().
we want to get it to be no-slower than C. and we want it with a safe abstraction.
What we're trying to figure out is if we can have something along the lines of:
use selfref::Holder;
use bmaybeuninit::BMaybeUninit;
let holder = BMaybeUninit::factory(|factory| {
let holder = Box::pin(Holder::new_with(|foo| foo.build(Whatever(factory.new()))));
holder.as_ref().operate_in(|foo| {
foo.0.init(factory, foo)
});
holder
});
holder.operate_in(|foo| {
foo.0.get().0.get(); // no .unwrap()! and ideally we can use Option::unwrap_unchecked internally for performance.
});
edit: okay we need the factory in the init calls too but anyway.
Is that true? You can't soundly transmute OuterType<MaybeUninit<T>> to OuterType<T> for an arbitrary outer type because the layout of the outer type might use a niche of T, but if there's no outer type I'm not clear on whether that's sound or not.
The array example in the MaybeUninit docs actually transmutes from an array of MaybeUninits to an array of the inner type. If that's not sound the docs probably need to be updated.