Munge makes it easy and safe to destructure MaybeUninit
s, Cell
s,
UnsafeCell
s, ManuallyDrop
s, and more.
- munge, the core library
- munge_macro, the proc macro at the core of munge.
Initialize MaybeUninit
s:
use core::mem::MaybeUninit;
use munge::munge;
pub struct Example {
a: u32,
b: (char, f32),
}
let mut mu = MaybeUninit::<Example>::uninit();
munge!(let Example { a, b: (c, mut f) } = &mut mu);
assert_eq!(a.write(10), &10);
assert_eq!(c.write('x'), &'x');
assert_eq!(f.write(3.14), &3.14);
// Note that `mut` bindings can be reassigned like you'd expect:
f = &mut MaybeUninit::uninit();
// SAFETY: `mu` is completely initialized.
let init = unsafe { mu.assume_init() };
assert_eq!(init.a, 10);
assert_eq!(init.b.0, 'x');
assert_eq!(init.b.1, 3.14);
Destructure Cell
s:
use core::cell::Cell;
use munge::munge;
pub struct Example {
a: u32,
b: (char, f32),
}
let value = Example {
a: 10,
b: ('x', 3.14),
};
let cell = Cell::<Example>::new(value);
munge!(let Example { a, b: (c, f) } = &cell);
assert_eq!(a.get(), 10);
a.set(42);
assert_eq!(c.get(), 'x');
c.set('!');
assert_eq!(f.get(), 3.14);
f.set(1.41);
let value = cell.into_inner();
assert_eq!(value.a, 42);
assert_eq!(value.b.0, '!');
assert_eq!(value.b.1, 1.41);
You can even extend munge to work with your own types by implementing its
Destructure
and Restructure
traits:
use munge::{Destructure, Restructure, Move, munge};
pub struct Invariant<T>(T);
impl<T> Invariant<T> {
/// # Safety
///
/// `value` must uphold my custom invariant.
pub unsafe fn new_unchecked(value: T) -> Self {
Self(value)
}
pub fn unwrap(self) -> T {
self.0
}
}
// SAFETY:
// - `Invariant<T>` is destructured by move, so its `Destructuring` type is
// `Move`.
// - `underlying` returns a pointer to its inner type, so it is guaranteed
// to be non-null, properly aligned, and valid for reads.
unsafe impl<T> Destructure for Invariant<T> {
type Underlying = T;
type Destructuring = Move;
fn underlying(&mut self) -> *mut Self::Underlying {
&mut self.0 as *mut Self::Underlying
}
}
// SAFETY: `restructure` returns an `Invariant<U>` that takes ownership of
// the restructured field because `Invariant<T>` is destructured by move.
unsafe impl<T, U> Restructure<U> for Invariant<T> {
type Restructured = Invariant<U>;
unsafe fn restructure(&self, ptr: *mut U) -> Self::Restructured {
// SAFETY: The caller has guaranteed that `ptr` is a pointer to a
// subfield of some `T`, so it must be properly aligned, valid for
// reads, and initialized. We may move the fields because the
// destructuring type for `Invariant<T>` is `Move`.
let value = unsafe { ptr.read() };
Invariant(value)
}
}
// SAFETY: `(1, 2, 3)` upholds my custom invariant.
let value = unsafe { Invariant::new_unchecked((1, 2, 3)) };
munge!(let (one, two, three) = value);
assert_eq!(one.unwrap(), 1);
assert_eq!(two.unwrap(), 2);
assert_eq!(three.unwrap(), 3);