project-uninit 0.1.1

Macros for safe references to and initialization of fields in MaybeUninit structs
Documentation
use core::mem::MaybeUninit;

use project_uninit::partial_init;

#[derive(Debug, PartialEq, Eq)]
struct Foo {
    a: usize,
    b: (i32, (u8, i8), &'static str),
}

#[test]
fn partial_init_single() {
    let mut x = MaybeUninit::new(Foo {
        a: 1,
        b: (2, (3, 4), "hey"),
    });

    let a = partial_init!(x => a = 10);
    assert_eq!(*a, 10);
    let b10 = partial_init!(x => b => 1 => 0 = 8);
    assert_eq!(*b10, 8);
    assert_eq!(
        unsafe { x.assume_init() },
        Foo {
            a: 10,
            b: (2, (8, 4), "hey"),
        }
    );
}

#[test]
fn partial_init_and_mutate_field() {
    let mut x = MaybeUninit::<Foo>::uninit();

    let (a, b10, b2) = partial_init!(x => {
        a: 7,
        b => 1 => 0: 240,
        b => 2: "hello",
    });

    assert_eq!((*a, *b10, *b2), (7, 240, "hello"));

    *a = 12;

    let (b0, b1) = partial_init!(x => {
        b => 0: -10,
        b => 1: (17, -29),
    });

    assert_eq!((*b0, *b1), (-10, (17, -29)));

    assert_eq!(
        unsafe { x.assume_init() },
        Foo {
            a: 12,
            b: (-10, (17, -29), "hello"),
        }
    );
}

#[test]
fn init_escaping_reference() {
    let mut x = MaybeUninit::uninit();

    fn inner<'a>(x: &'a mut MaybeUninit<(i32, u32)>) -> (&'a mut i32, &'a mut u32) {
        partial_init!(x => { 0: 10, 1: 20 })
    }

    let (a, b) = inner(&mut x);
    assert_eq!((*a, *b), (10, 20));

    *a = 100;
    assert_eq!(unsafe { x.assume_init() }, (100, 20));
}