So the basic idea is to have as a lang item:
pub struct BrandedUninit<'brand, T: ?Sized> {
inner: MaybeUninit<T>,
}
impl<'brand, T> BrandedUninit<'brand, T> {
/// # Safety
/// Must not expose an 'static brand unless it's fully initialized.
pub unsafe fn new_uninit() -> Self;
}
// NOT 'brand!
impl<T: ?Sized> Drop for BrandedUninit<'static, T> {
...
}
This is because lifetimes are the only thing with the correct semantics, i.e. a for<'a>
is opaque to 'a
, while a 'static
is transparent to 'static
, and transmuting lifetimes is guaranteed (as per mem::transmute
documentation) not to affect layout.
Then, it is possible to have arbitrary code that contains BrandedUninit<'a, T>
similar to how BOption
is handled. E.g.
struct Foo<'a> {
x: Wrapper<'a, Something>,
}
let foo: Foo<'static> = ...;
drop(foo); // drops Something
let bar: Foo<'_> = ...;
drop(bar); // leaks Something
If you look at broption
, it relies on dropping an Option
, but what if it statically decided whether to drop something? What if initialization could be statically known?
Like uh, this would be UB, since the types are different:
trait InitState {
type Inner<T>;
}
struct Uninit;
struct Init;
impl InitState for Uninit {
type Inner<T> = MaybeUninit<T>;
}
impl InitState for Init {
type Inner<T> = T;
}
Which means we can't expose an API like:
pub fn factory<T, F>(f: F) -> T::Kind<'static, Init> where
T: Wrapper,
F: for<'id> FnOnce(&mut Factory<'id>) -> T::Kind<'id, Uninit>,
So, at least currently, we must use an Option
if we want Drop
to ever be called. We want an alternative where we can still get to call Drop
(under some circumstances) but without the overhead of Option
.
An alternative to the impl Drop for Foo<'static>
would be a pair of types (like the above trait InitState
shows) which are guaranteed to monomorphize to the same layout, despite being different types. Basically something that makes it safe to transmute between them. This would also allow getting the drop behaviour without the Option
overhead.
sorry for rambling we're just not sure how to convey the issues we ran into to others.