place/lib.rs
1//! Placement new in Rust
2#![cfg_attr(not(test), no_std)]
3
4/// Initialize a struct in-place at `buf`, and return a mutable reference
5///
6/// `buf` is a MaybeUninit of your type
7///
8/// It is your responsibility to drop your type if needed when you're done with
9/// it.
10///
11/// It is your responsibility to correctly produce the MaybeUninit
12///
13/// This macro will ensure that all fields are initialized, and is thus
14/// safe to call.
15///
16/// # Examples
17///
18/// ```rust
19/// # use place::place;
20/// # use std::mem::MaybeUninit;
21///
22/// struct MyCoolStruct {
23/// b: bool,
24/// s: String,
25/// }
26///
27/// let mut buf = MaybeUninit::uninit();
28///
29/// let x: &mut MyCoolStruct = place!(
30/// buf,
31/// MyCoolStruct {
32/// b: true,
33/// s: String::from("works"),
34/// }
35/// );
36///
37/// # // SAFETY: buf has been initialized above
38/// # unsafe { buf.assume_init_drop() };
39/// ```
40#[macro_export]
41macro_rules! place {
42 (
43 $buf:expr,
44 $typ:ident {
45 $(
46 $f:ident: $f_val:expr
47 ),*
48 $(,)?
49 }
50 ) => {{
51 use core::{mem::MaybeUninit, ptr::addr_of_mut};
52 const _: () = {
53 // Ignore useless warnings
54 #[allow(unreachable_code, clippy::diverging_sub_expression)]
55 fn _check_types() {
56 // This check means Rust will validate that all struct fields were passed in,
57 // meaning that all fields will be initialized below
58 //
59 // This check is the key to making this macro safe.
60 $typ {
61 $(
62 $f: loop {}
63 ),*
64 };
65 }
66 };
67 // Ensures types are correct
68 let buf: &mut MaybeUninit<$typ> = &mut $buf;
69 let ptr = buf.as_mut_ptr();
70 $(
71 // SAFETY: Only pointers are used, and the above compile check
72 // ensures all fields were specified
73 unsafe { addr_of_mut!((*ptr).$f).write($f_val); }
74 )*
75 // SAFETY: All fields have been initialized above
76 // The compiler ensures that all fields were used, all types were correct,
77 // and that size and alignment are correct.
78 unsafe { buf.assume_init_mut() }
79 }};
80}
81
82#[cfg(test)]
83mod tests {
84 use super::*;
85 use core::mem::MaybeUninit;
86
87 #[derive(Debug)]
88 struct MyCoolStruct {
89 b: bool,
90 s: String,
91 v: Vec<String>,
92 }
93
94 #[test]
95 fn miri() {
96 let mut buf = MaybeUninit::uninit();
97
98 let x: &mut MyCoolStruct = place!(
99 buf,
100 MyCoolStruct {
101 b: true,
102 s: String::from("works"),
103 v: vec![String::from("works")],
104 }
105 );
106 dbg!(x);
107
108 // SAFETY: buf has been initialized above
109 unsafe { buf.assume_init_drop() };
110 }
111}