#![feature(ptr_as_uninit)]
use core::pin::Pin;
use core::mem::MaybeUninit;
pub unsafe trait Emplace<Args>: Sized {
unsafe fn emplace(place: Pin<&mut MaybeUninit<Self>>, args: Args);
}
#[macro_export]
macro_rules! emplace {
($P:ident <- $S:ident { $($fields:tt)* }) => {{
use core::pin::Pin;
use core::mem::{self, MaybeUninit};
#[allow(unused)]
use core::ptr::{self, addr_of_mut};
let mut ret = $P::pin(MaybeUninit::uninit());
let mut pret: Pin<&mut MaybeUninit<$S>> = ret.as_mut();
emplace!(@INIT [pret] $($fields)*);
let ret: Pin<$P<$S>> = unsafe { mem::transmute(ret) };
let emplace!{ @PAT $S { $($fields)* }} = ret.as_ref().get_ref();
ret
}};
(@INIT [$pret:ident]) => {};
(@INIT [$pret:ident] $field:ident <- $F:ident ( $($args:expr),* $(,)? ), $($rest:tt)*) => {
unsafe {
let pfield: Pin<&mut MaybeUninit<_>> = $pret
.as_mut()
.map_unchecked_mut(|p| {
let pfield = addr_of_mut!((*p.as_mut_ptr()).$field).as_uninit_mut();
pfield.unwrap() });
$F::emplace(pfield, ($($args),*));
}
emplace!(@INIT [$pret] $($rest)*);
};
(@INIT [$pret:ident] $field:ident : $expr:expr, $($rest:tt)*) => {
unsafe {
let pfield = addr_of_mut!((*$pret.as_mut().get_unchecked_mut().as_mut_ptr()).$field);
ptr::write(pfield, $expr);
}
emplace!(@INIT [$pret] $($rest)*);
};
(@PAT $S:ident { $( $field:ident $(:)? $(<-)? $_:expr, )* }) => {
$S { $( $field : _, )* }
}
}
#[cfg(test)]
mod tests {
use super::*;
use core::cell::Cell;
use core::marker::PhantomPinned;
struct Mutex<T> {
data: T,
name: Cell<Option<&'static str>>,
_pinned: PhantomPinned,
}
impl<T> Mutex<T> {
unsafe fn new(x: T) -> Self {
Mutex {
data: x,
name: Cell::new(None),
_pinned: PhantomPinned,
}
}
fn init(self: Pin<&mut Self>, s: &'static str) {
self.into_ref().get_ref().name.set(Some(s))
}
fn name(&self) -> &'static str {
self.name.get().unwrap()
}
}
unsafe impl<T> Emplace<(T, &'static str)> for Mutex<T> {
#[warn(unsafe_op_in_unsafe_fn)]
unsafe fn emplace(place: Pin<&mut MaybeUninit<Self>>, args: (T, &'static str)) {
let this = unsafe {
place.map_unchecked_mut(|p| p.write(Mutex::new(args.0)))
};
Mutex::init(this, args.1)
}
}
struct SharedState {
x: u32,
y: u32,
inner: Mutex<i32>,
other: Mutex<i64>,
}
impl SharedState {
fn new() -> Pin<Box<Self>> {
emplace!(Box <- Self {
other <- Mutex(0, "SharedState::other"),
x: 1,
inner <- Mutex(0, "SharedState::inner"),
y: 3,
})
}
}
#[test]
fn emplace() {
let x = SharedState::new();
let x = x.as_ref().get_ref();
assert_eq!("SharedState::inner", x.inner.name());
assert_eq!("SharedState::other", x.other.name());
let _ = x.other.data;
}
}