Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support casting to a KnownLayout type with a user-provided length computed dynamically #1289

Open
joshlf opened this issue May 17, 2024 · 1 comment

Comments

@joshlf
Copy link
Member

joshlf commented May 17, 2024

See also: #1290, #1328, #5 (comment)

Some formats have an explicit length field, and some use cases with these formats require parsing a subset of the available bytes based on that length field. We'd like to write something like:

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

#[derive(KnownLayout, FromBytes)]
struct UdpPacket {
    header: UdpHeader,
    body: [u8],
}

Unfortunately, all of the conversions we permit today require the number of bytes to be parsed to be known ahead of time - either it's simply the entire source byte slice, or it's computed from a fixed number of trailing slice elements.

Ideally, we could support an API that permits the caller to specify how to extract the length and then use that to determine the number of bytes to parse.

One idea: Do one parsing pass, then allow the user to provide a callback which extracts the length field. Finally, re-parse using the extracted length. There may be multiple axes we need to consider:

  • What is the type of the length field? Can we just require this callback to return a usize, or do we need to support other numeric types?
  • Will the length field always describe the byte length of the trailing field? What if it's a count of elements that are larger than 1 byte in size each? What if it instead describes the overall length of the packet, including the header?
@kupiakos
Copy link
Contributor

kupiakos commented May 20, 2024

(also mentioned in #5 (comment))

This feature could be achieved rather naturally by extending the validation routine to also extract length information. What if the result of is_bit_valid isn't a simple bool, but rather:

enum BitValidity {
    /// This &T contains invalid bits for the type.
    Invalid,

    /// This `&T` contains valid bits for the type.
    Valid,

    /// This `&T` would contain valid bits if the tail slice were truncated to this many elements.
    ///
    /// If the tail slice already contains exactly this many elements, this is semantically identical to returning `Valid`.
    ValidIfTruncatedTo(usize),
}

That way ref_from_prefix and friends could consume the correct amount of data based on e.g. a length in the header of a &T. Exact-matching conversions would reject the input if the validator returns ValidIfTruncatedTo with a length different from the length derived from the bytes provided, and prefix-matching conversions would truncate the input to the given length. I can extend this design into something more detailed if desired.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants