zerocopy icon indicating copy to clipboard operation
zerocopy copied to clipboard

Request: Add FromBytes::read_from_prefix_split and read_from_suffix_split

Open smalis-msft opened this issue 11 months ago • 4 comments

It would be handy to have a FromBytes::read_from_(prefix/suffix)_split that returns a tuple of the T and the unused portion of the byte slice. Ref::new_from_prefix isn't quite the same in case the byte slice is unaligned, but we don't want to derive Unaligned on the type.

smalis-msft avatar Mar 15 '24 19:03 smalis-msft

Something like this (playground)?

fn read_from_prefix_split<T>(bytes: &[u8]) -> Option<(T, &[u8])>
where
    T: Sized + FromBytes,
{
    Ref::<_, Unalign<T>>::new_unaligned_from_prefix(bytes)
        .map(|(r, s)| (r.read().into_inner(), s))
}

jswrenn avatar Mar 15 '24 19:03 jswrenn

Yeah that looks about right. I mean there's a number of ways to do it, you can just call FromBytes::read_from_prefix and then index into your byte buffer by sizeof<T>, but having it provided on FromBytes and able to be used in a small oneliner would be nice.

smalis-msft avatar Mar 15 '24 19:03 smalis-msft

In our code, we often parse structures with fixed headers and then some dynamic portion, from a potentially unaligned buffer. To support this, it has been nice to have both options readily available (both preserving the suffix bytes and not), without having to reach for Ref.

Ref is powerful, but it's certainly more tedious to use. And it's arguably more dangerous (from a correctness perspective, not a safety one): since reading from an unaligned buffer requires even more typing than reading from/aliasing an aligned one, developers get lazy and just assume their buffer is aligned. And in their testing, it is. Then something subtle changes in the code, possibly far away from the call site, and runtime checks start failing.

Or developers write something like let foo = Foo::read_from_prefix(buf)? followed by let buf = &buf[..size_of::<Foo>()], which is error prone from the type name duplication. (I guess size_of_val(&foo) would also fix this, but it's still tedious to write.)

To solve this, we have a private crate that provides these kind of extra methods for use with zerocopy, but we'd love to just standardize on a single crate. Since these methods aren't already in zerocopy, I'm curious if we're "holding it wrong"--maybe there's a better way to do this kind of parsing? Do most users have aligned buffers? Or have unaligned struct definitions?

jstarks avatar Mar 19 '24 16:03 jstarks

@jstarks Is that private crate open source? It'd be great to see what else you're needing to work around so that we can support your use cases!

joshlf avatar Mar 27 '24 19:03 joshlf

Closed in https://github.com/google/zerocopy/pull/1059

joshlf avatar Apr 24 '24 17:04 joshlf