const_destructure/lib.rs
1#[doc(hidden)]
2/// Provides access to the inner value of a ManuallyDrop<T>.
3pub const fn __manually_drop_inner_ref<T>(slot: &core::mem::ManuallyDrop<T>) -> &T {
4 // SAFETY: ManuallyDrop<T> and T are guaranteed to have the same layout
5 unsafe { core::mem::transmute(slot) }
6}
7
8#[macro_export]
9macro_rules! const_destructure_struct {
10 (let $S:ident { $($field:ident: $var:ident),* } = $value:expr) => {
11 let value = $value;
12 let __destructures_all_fields_and_fields_are_unique = || {
13 let $S { $($field: _),* } = &value;
14 };
15 let value = ::core::mem::ManuallyDrop::new($value);
16 let value = $crate::__manually_drop_inner_ref(&value);
17 // SAFETY: We avoid double free by 1) only reading each field once (since they're unique) and 2) the original is wrapped in ManuallyDrop.
18 $(
19 let $var = unsafe { ::core::ptr::addr_of!(value.$field).read() };
20 )*
21 }
22}
23
24#[macro_export]
25macro_rules! const_destructure_tuple {
26 (let ($($var:ident),*) = $value:expr) => {
27 $crate::const_destructure_tuple!(@impl ($($var),*); (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11) => (); let () = $value);
28 };
29 (@impl (); ($($index_rest:tt),*) => ($($ty:tt),*); let ($($index:tt: $var:ident),*) = $value:expr) => {
30 let value: ($($ty,)*) = $value; // asserts correct arity
31 let value = ::core::mem::ManuallyDrop::new(value);
32 let value = $crate::__manually_drop_inner_ref(&value);
33 // SAFETY: We avoid double free by 1) only reading each field once (since they're unique) and 2) the original is wrapped in ManuallyDrop.
34 $(
35 let $var = unsafe { ::core::ptr::addr_of!(value.$index).read() };
36 )*
37 };
38 (@impl ($var_head:ident $(,$var_tail:ident)*); () => ($($ty:tt),*); let ($($index:tt: $var:ident),*) = $value:expr) => {
39 compile_error!("tuple arity is larger than the maximum supported arity 12")
40 };
41 (@impl ($var_head:ident $(,$var_tail:ident)*); ($index_head:tt $(,$index_tail:tt)*) => ($($ty:tt),*); let ($($index:tt: $var:ident),*) = $value:expr) => {
42 $crate::const_destructure_tuple!(@impl ($($var_tail),*); ($($index_tail),*) => ($($ty,)* _); let ($($index: $var,)* $index_head: $var_head) = $value);
43 };
44}
45
46// const fn s() {
47// struct S<A, B>{ a: A, b: B}
48// const_destructure_struct!(let S { a: da, b: db } = S { a: 1, b: [0u8; 1] });
49// }
50
51// const fn x() {
52// let v = (1, 2);
53// const_destructure_tuple!(let (t0, t1) = v);
54// if t0 != 1 || t1 != 2 {
55// panic!()
56// }
57// }
58// const X: () = x();
59
60// const fn x13() {
61// let v = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 11);
62// const_destructure_tuple!(let (t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12) = v);
63// }
64
65// const X13: () = x13();
66
67// const fn too_many() {
68// let v = (0, 1);
69// const_destructure_tuple!(let (t0, t1, t2) = v);
70// }
71
72// const fn too_few() {
73// let v = (0, 1);
74// const_destructure_tuple!(let (t0) = v);
75// }
76
77// macro_rules! const_map {
78// ($N:tt => ($($n:ident in $a:expr),+ $(,)?) -> ($($o:ident $ot:ty => $oa:ident),+ $(,)?) $body:expr) => {{
79// $(
80// let mut $o = array_uninit::<$ot, $N>();
81// )*
82
83// $(
84// #[allow(clippy::redundant_locals)]
85// let $n: [_; $N] = $a;
86// let $n = core::mem::ManuallyDrop::new($n);
87// let $n = manually_drop_inner_ref(&$n);
88// )*
89
90// const_for!{index in 0..$N => {
91// $(
92// let $n = unsafe { core::ptr::addr_of!($n[index]).read() };
93// )*
94// let item: ($($ot),*) = $body;
95// const_destructure!(let $($o: ))
96// $(
97// $o[index].write()
98// )
99// out[index].write(item);
100// }};
101
102// unsafe { array_assume_init(out) }
103// }};
104// }
105// pub(crate) use const_map;