I'd like to write a function that takes an &ExampleStruct and produces an &ExampleStructRef (similarly to how one can go from &String to &str), but I'm not sure how this can be done, or what trait I should impl (AsRef, Borrow, Deref, or something else) to contain this conversion. (I suspect that this may require fixing the struct layouts via #[repr(C)] and doing transmutes that count on Box<T> and &T having the same representation as a pointer, but I'm hoping to avoid that unless there's no other way to do this.)
Your entire idea of converting a reference with one pointed type to a reference with a different pointed type fundamentally requires that the layout of the two types be the same. The operation that you are describing is itself a transmute, in essence.
Since the layout of fat pointers is not guaranteed, this cannot be done reliably (ie., without UB).
You could use a single struct layout for both purposes:
struct Inner {
field_1: u32,
field_2: *const [u8],
}
#[repr(transparent)]
pub struct ExampleStruct {
/// The `field_2` in this must be a `Box::into_raw()` pointer
data: Inner,
}
#[repr(transparent)]
pub struct ExampleStructRef<'a> {
data: Inner,
_phantom: PhantomData<&'a [u8]>,
}
Then you have to use unsafe in your accessor functions and Drop implementation for ExampleStruct, but it's sound to pointer-cast an &'a ExampleStruct into an &'b ExampleStructRef<'a> where 'a: 'b, as long as ExampleStructRef doesn't expose any operations that would drop or mutate the field_2 data.
Well, if we assume we are allowed to change the premise of the question, then a much better alternative is to not use any unsafe at all, lose the struct containing borrowed data, and just return a reference to the owned one. Then there could be a conversion from &'a Owned to Borrowed<'a>: