Treating a nested struct of the same leaf type as an array

In C, I can take a struct like figure here:

struct point
{
    int x, y;
};

struct box
{
    struct point left_top, right_bottom;
};

struct figure
{
    struct point points[100];
    struct box bounding_box;
};

and just treat it as an int array, which is very convenient in some cases. I wonder if Rust offers any similar facilities? If not for directly treating a nested struct as an array, then just for iteration? (For example, what if I wanted to increment all of the ints by 1?)

>Solution :

For obvious reasons this requires unsafe but sure it can be done:

#[repr(C)]
#[derive(Debug)]
struct Point {
    x: usize,
    y: usize,
}

#[repr(C)]
#[derive(Debug)]
struct Box {
    left_top: Point,
    right_bottom: Point,
}

#[repr(C)]
#[derive(Debug)]
struct Figure {
    points: [Point; 5],
    bounding_box: Box,
}

fn main() {
    let mut f = Figure {
        points: [
            Point { x: 1, y: 2 },
            Point { x: 3, y: 4 },
            Point { x: 5, y: 6 },
            Point { x: 7, y: 8 },
            Point { x: 9, y: 10 },
        ],
        bounding_box: Box {
            left_top: Point { x: 11, y: 12 },
            right_bottom: Point { x: 13, y: 14 }
        },
    };

    assert_eq!(std::mem::size_of::<[usize;14]>(), std::mem::size_of::<Figure>());

    let g: &mut [usize; 14] = unsafe { &mut *(&mut f as *mut Figure).cast() };
    for l in g {
        *l += 1;
    }

    dbg!(f);
}

Of course usually you would want to hide that away behind a safe abstraction such as AsRef or AsMut:

impl AsMut<[usize; 14]> for Figure {
    fn as_mut(&mut self) -> &mut [usize; 14] {
        assert_eq!(std::mem::size_of::<[usize;14]>(), std::mem::size_of::<Figure>());
        unsafe { &mut *(self as *mut Figure).cast() }
    }
}

Note that without #[repr(C)] the compiler is free to arrange the fields however (order, padding) it likes and thus this code would be UB.

Leave a Reply