and let mut v = MaybeUninit::uninit();
design a macro called init, when invoked as
init!(v, T { s: S { a: f1 }, t: [f2; 5] }, f1 = foo(true), f2 = foo(false));, it gets expanded into:
{
let f1 = foo(true);
let f2 = foo(false);
let v_mut_ptr = v.as_mut_ptr();
unsafe {
// FIXME: static assert T can be initialized by initializing "s" and "t"
let s_mut_ptr = &mut (*v_mut_ptr).s as * mut S;
// FIXME: static assert S can be initialized by initializing "a"
std::ptr::write(&mut (*s_mut_ptr).a, f1);
std::ptr::write(&mut (*v_mut_ptr).t, [f2; 5]);
}
}
The key points is that there's no panicking possibility within the unsafe region. And compiler will properly check about the Copy-ability of f2.
This serves as basis of higher-level macros like boxed , boxed!(S {a: f1}, f1 = foo(true)) get expanded into:
{
let mut b = Box::new_uninit();
init!(b.as_mut(), S {a: f1}, f1 = foo(true));
unsafe { b.assume_init() }
}
I have a implementation at https://github.com/SeeSpring/placement_new_macros. I'm not sure that there's a way to make this safe since if the user passes in a packed struct the macro will create unaligned references.
Assume we have
and
let mut v = MaybeUninit::uninit();
design a macro calledinit
, when invoked asinit!(v, T { s: S { a: f1 }, t: [f2; 5] }, f1 = foo(true), f2 = foo(false));
, it gets expanded into:The key points is that there's no panicking possibility within the unsafe region. And compiler will properly check about the
Copy
-ability off2
.This serves as basis of higher-level macros like
boxed
,boxed!(S {a: f1}, f1 = foo(true))
get expanded into: