How to set enum discriminate value?

I have a Node enum with a big stack allocated value. The enum needs to end up wrapped in an Arc on the heap. I'm messing around trying to see if I can do this without having to copy that big value from the stack to the heap.

I think I'm close using nightly and Arc::<Node>::new_uninit(). The problem is I don't know how to turn that uninitialized memory into a valid Node. I think I need to set the discriminant value for the enum, and then initialize the field value... but I'm stuck at that first step.

use arrayvec::ArrayVec;
use std::sync::Arc;

#[repr(C)]
#[repr(i32)]
enum Node {
    Internal,
    Leaf { items: ArrayVec<[u8; 1024]> },
}

fn heap_alloc_without_copy() {
    let mut arc = Arc::<Node>::new_uninit();
    let arc = unsafe {
        let mut node: *mut Node = Arc::get_mut_unchecked(&mut arc).as_mut_ptr();
        // At this point I think node points to unitized memory. How to I
        // set the nodes enum discriminator to ensure it matches as a Node::Leaf?
        match &mut *node {
            Node::Leaf { items } => items.set_len(0),
            Node::Internal { .. } => unreachable!(),
        }
        arc.assume_init()
    };
}


(Playground)

Try this:

std::ptr::write(node as *mut i32, 1);

Note: this relies on the unstable layout of enums, which could change on a patch bump. To fix this, you should mark your enum as #[repr(C)] or #[repr($int)] to get layout guarantees. See the rfc for layout details

2 Likes

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.