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.