What are some good ways to return reference to a struct that is located in a byte buffer?

I'm trying to implement function similar to this one, what would be an idiomatic way to achieve this?

fn meta(buffer: &[u8]) -> &Meta {
    let ptr = buffer as *const _ as *const Meta;
    unsafe { *ptr }; // trying to return &Meta here
}

Motivation and some things to consider:

  • buffer is a huge memory-mapped file, it's contents are outside of my control, trying to work with what's available;
  • what I'm trying to do here is read Meta, and based on it's content decide what other structs to read (in a way similar to this one) and where in buffer they are located;
  • I would like to avoid copying memory: while I can construct new Meta struct and return it as owned, I would rather let it reside in the buffer and just return reference to it (there are some structs like Meta which are quite big and there can exist many of them at the same time: this takes up lots of memory and performance during copying).

You need &*ptr and remove the semicolon to make your code work. It can be written as:

unsafe fn meta(buffer: &[u8]) -> &Meta {
    &*buffer.as_ptr().cast::<Meta>()
}

but you have to be careful about alignment!

The buffer doesn't guarantee its address is aligned for anything larger than u8. Your Meta probably contains other types, and will cause Undefined Behavior if the buffer pointer isn't correctly aligned.


unsafe fn meta(buffer: &[u8]) -> &Meta {
    let (misaligned, meta, _) = buffer.align_to::<Meta>();
    assert!(misaligned.is_empty());
    &meta[0]
}

1 Like

Note that this function should probably be unsafe, since it might be UB to call it with arbitrary slice (depending on the definition of Meta).

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.