Safe conversion from [Option>; 2] to &[Box]

⚓ Rust    📅 2026-03-31    👤 surdeus    👁️ 7      

surdeus

This was a little puzzle for myself that I wasn't able to solve. I was wondering whether anyone would have any solutions.

Here's some unsafe code to convert [Option<Box<i32>>; 2] to &[Box<i32>] given the layout guarantees of Option and slices:

type Foo = [Option<Box<i32>>; 2];

fn foo_as_slice(foo: &Foo) -> &[Box<i32>] {
    match foo {
        [Some(_), Some(_)] => unsafe { std::mem::transmute(foo.as_slice()) }
        [Some(b), None] | [None, Some(b)] => std::slice::from_ref(b),
        [None, None] => &[],
    }
}

fn main() {
    println!("size_of<Foo>: {}", std::mem::size_of::<Foo>());
    println!("Foo1: {:?}", foo_as_slice(&[Some(Box::new(1)), Some(Box::new(2))]));
    println!("Foo2: {:?}", foo_as_slice(&[Some(Box::new(1)), None]));
    println!("Foo3: {:?}", foo_as_slice(&[None, Some(Box::new(2))]));
    println!("Foo4: {:?}", foo_as_slice(&[None, None]));
}

This successfully prints

size_of<Foo>: 16
Foo1: [1, 2]
Foo2: [1]
Foo3: [2]
Foo4: []

I was wondering whether there was a completely safe analog for this that would also have size_of<>()=16. The naive enum variant version has size_of<>()=24:

enum Bar {
    Zero,
    OneA(Box<i32>),
    OneB(Box<i32>),
    Two([Box<i32>; 2]),
}

fn bar_as_slice(bar: &Bar) -> &[Box<i32>] {
    match bar {
        Bar::Zero => &[],
        Bar::OneA(b) | Bar::OneB(b) => std::slice::from_ref(b),
        Bar::Two(b) => b,
    }
}

fn main() {
    println!("size_of<Bar>: {}", std::mem::size_of::<Bar>());
    println!("Bar::Zero: {:?}", bar_as_slice(&Bar::Zero));
    println!("Bar::OneA: {:?}", bar_as_slice(&Bar::OneA(Box::new(1))));
    println!("Bar::OneB: {:?}", bar_as_slice(&Bar::OneB(Box::new(2))));
    println!("Bar::Two: {:?}", bar_as_slice(&Bar::Two([Box::new(1), Box::new(2)])));
}

Output:

size_of<Bar>: 24
Bar::Zero: []
Bar::OneA: [1]
Bar::OneB: [2]
Bar::Two: [1, 2]

I've not managed to figure out a nice alternative. I guess the Foo version just happen to use the only two niche bits available - one at each entry - and there's no straightforward way to get that in safe rust? But I'm just throwing this puzzle out into the void at the mercy of y'all creativity in case you have an interesting solution.

Playground

1 post - 1 participant

Read full topic

🏷️ Rust_feed