google/zerocopy

A `(Try)FromBytes` `#[length]` field attribute

jswrenn opened this issue · 2 comments

See also: #5 (comment)

Addresses #1289. Discussion of alternative solutions should occur there, or in their own issues.

Many formats include a length field in their header that describes the length of a variable-sized body; e.g., UDP:

#[derive(FromBytes, KnownLayout, Immutable)]
#[repr(C)]
struct Packet {
    src_port: [u8; 2],
    dst_port: [u8; 2],
    length: [u8; 2],
    checksum: [u8; 2],
    body: [u8],
}

Such types are inconvenient to correctly parse in zerocopy; the length must first be parsed, and only then FromBytes::try_ref_from_prefix_with_elems can be invoked with that length. Alternatively, the entire buffer can be parsed with try_ref_from_prefix, and then truncated thereafter. These approaches are inconvenient.

We could potentially simplify this with a #[length] field attribute; e.g.:

#[derive(FromBytes, KnownLayout, Immutable)]
#[repr(C)]
struct Packet {
    src_port: [u8; 2],
    dst_port: [u8; 2],
    #[zerocopy::length]
    length: [u8; 2],
    checksum: [u8; 2],
    body: [u8],
}

...such that FromBytes::ref_from_prefix would respect the length attribute.

Some considerations:

  • This attribute should accept a function for cases in which the length in bytes must be computed
  • This approach should also work on TryFromBytes, where excess data might be invalid
  • Should we attempt to support the case where the length is factored into a different, fixed-sized header type?

If the design in #1289 (comment) were to be implemented, this attribute could have the validator always return ValidIfTruncatedTo(length_specified) assuming the other fields are validated.

This should also consider:

  • Whether the length is in bytes or number of elements, and
  • Whether this length includes the size of the header itself or not.