1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
/// Allows you to destructure structs that have a drop implementation.
///
/// The drop implementation will not be called for `$ty` nor for any field that is not bound.
macro_rules! destructure {
(let $ty:path {
$($field:ident $(: $field_alias:ident)?),* $(,)?
} = $value:expr) => {
let value: $ty = $value;
// errors if there are duplicates
let $ty { $($field: _,)* .. } = &value;
let value = ::core::mem::ManuallyDrop::new(value);
$(
#[allow(unused_unsafe)] // we might or might not already be in an unsafe context
let $crate::destructure::or!($($field_alias)? $field) = unsafe { ::core::ptr::read(&value.$field) };
)*
};
}
pub(crate) use destructure;
macro_rules! or {
($this:ident $that:ident) => {
$this
};
($that:ident) => {
$that
};
}
pub(crate) use or;
#[cfg(test)]
mod tests {
use std::string::String;
#[test]
fn example() {
pub struct Foo {
bar: String,
baz: String,
}
impl Drop for Foo {
fn drop(&mut self) {
unreachable!()
}
}
let foo = Foo {
bar: "bar".into(),
baz: "baz".into(),
};
// won't compile
// let Foo { bar: qux, baz } = foo;
// won't compile
// destructure!(let Foo { bar, bar } = foo);
destructure!(let Foo { bar: qux, baz } = foo);
assert_eq!(qux, "bar");
assert_eq!(baz, "baz");
}
}