Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

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?)

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>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.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading