Description
Suggestion
Many Windows APIs return flexible array members. Working with them in Rust is terrible. You must only use raw pointers, as references will invalidate access to the undeclared part of the array in Stacked Borrows (rust-lang/unsafe-code-guidelines#256), and it's easy to make mistakes and cause UB.
We can generate a simple wrapper type per FAM that can simplify working with them a lot. Something along the lines of:
// Assume the following simple struct:
#[repr(C)]
pub struct Fam {
len: usize,
other: u32,
array: [i32; 1],
}
// We generate the following code:
#[repr(transparent)]
pub struct FamPtr(*mut Fam);
impl FamPtr {
pub fn as_raw(&self) -> *mut Fam { self.0 }
pub unsafe fn from_raw(raw: *mut Fam) -> Self { Self(raw) }
pub fn len(&self) -> &usize {
unsafe { &(*self.0).len }
}
// No `len_mut()`, that would be unsound.
pub fn other(&self) -> &u32 {
unsafe { &(*self.0).other }
}
pub fn other_mut(&mut self) -> &mut u32 {
unsafe { &mut (*self.0).other }
}
pub fn array(&self) -> &[i32] {
unsafe {
core::slice::from_raw_parts(
core::ptr::addr_of!((*self.0).array).cast::<i32>(),
(*self.0).len,
)
}
}
pub fn array_mut(&mut self) -> &[i32] {
unsafe {
core::slice::from_raw_parts_mut(
core::ptr::addr_of_mut!((*self.0).array).cast::<i32>(),
(*self.0).len,
)
}
}
}
There can be additional extensions (for example, supporting taking mutable references to many array members at the same time, safely allocating FAMs on the stack or the heap, or freeing them automatically) but even that alone is way better than the status quo.
Every function taking a pointer to a flexible struct will gain the ability to call it with its wrapper instead (probably with a trait).
I don't know if win32metadata marks flexible array members and their length field, so I don't know if this is possible, but if it is it can be a major improvement.