Rust allows conveniently querying the size of a type using std::mem::size_of, which is very helpful, but I may need to query more aspects of the memory layout of a type, for example the address and size of a private field or the address, size and value of a niche. What are the ways this could possibly be done?
This may be quite an unusual request, as rustc typically handles memory layouts automatically without any need for intervention, but for FFI it matters. Even in FFI this may be an unusual request, as
repr(C) usually is sufficient, but I want to do better than
repr(C). For my use case, the memory layout doesn't even need to be stable across compiler versions. It would be enough to have a way to query the memory layout of the current compiler version and feed this data into the program that generates the non-Rust code.
Mostly I want to pass Rust types as opaque values. The only things the non-Rust code can do with them are to move them around and pass them as arguments to functions implemented in Rust, so the only thing the non-Rust code need to know about them is their size, which I can easily query using std::mem::size_of. But for some types, I want the non-Rust code to know more about their memory representation, so it can do certain operations on its own, without calling a function implemented in Rust, for example get the length of a string or match an option and extract the contained value.
Strings I could convert using into_raw_parts and from_raw_parts into a struct with
repr(C) when passing them over the FFI boundary. If the layout of this struct is identical to the layout of
String, this conversion would hopefully be optimized away, but if for some reason the layout of
String changes, there would be a costly conversion. It would be preferable if I could skip doing the conversion in the Rust code, and instead have the non-Rust code access the fields at addresses determined by querying the memory layout of
Options I could also convert into a type with
repr(C), but this would be inefficient, as
repr(C) doesn't optimize for niches.
Option<std::io::Error> can fit in two registers, but a
repr(C) alternative to
Option cannot, and would instead be placed on the stack. If there was just a way to query the address, size and value of the niche of
std::io::Error, I could again skip doing the conversion in the Rust code, and instead have the non-Rust code use this information.
I have a few ideas what can be done:
- Ask around and see if someone has a solution.
- Parse the 'rlib' files of the standard library to figure out the memory layout of each type for the current compiler version.
- Compile probe functions such as
|x: String| string.len()and
|x: Option<std::io::Error>| x.is_none()and disassemble the compiled code.