munge_macro

Crates.iomunge_macro
lib.rsmunge_macro
version0.4.1
sourcesrc
created_at2022-08-10 22:21:08.305013
updated_at2024-08-20 19:09:46.101051
descriptionMacro for custom destructuring
homepage
repositoryhttps://github.com/djkoloski/munge
max_upload_size
id642934
size14,961
David Koloski (djkoloski)

documentation

https://docs.rs/munge_macro

README

munge

crates.io badge docs badge license badge

Munge makes it easy and safe to destructure MaybeUninits, Cells, UnsafeCells, ManuallyDrops, and more.

Documentation

Examples

Initialize MaybeUninits:

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 Cells:

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);
Commit count: 32

cargo fmt