Create type from bytes, with validating

I have a fixed-layout binary format that I want to serialize/deserialize to native types. Not all byte combinations are well-formed, so I need to validate.

My inclination is to use zerocopy::FromBytes, but that doesn't support the validation part; it assumes that all byte combinations are valid types.

use zerocopy::FromBytes;

#[repr(u8)]
#[derive(FromBytes)]
enum MyEnum {
    A = 0,
    B = 1,
    C = 2,
}

fn foo(bytes : &[u8]) -> MyEnum {
    MyEnum::read_from(bytes).unwrap()
}

(Playground)

(this doesn't work because the Playground doesn't support zerocopy)

Any suggestions? I love Serde but it seems to mostly want to use its own data formats, where here I don't have control over the layout.

What kind of validation needs to be done?
For your snippet above, you could replace the unwrap() with reporting an error to the caller ("not one of the expected variants A, B, or C")

If you need to check other invariants that can't be encoded easily in types, then you can define 2 types: one with the serialization derives (as you showed) and another which accepts the deserialized type in a fallible constructor.
Any function accepting the second types knows that validation passed, otherwise the type couldn't be constructed.

The error I get is a compile-time one; sorry I wasn't more clear.

The two-type method is one I had considered, but it seemed like extra steps. Maybe I'm being fussy, though.

I had imagined with Rust's popularity with the embedded world, it would fairly common to "map this byte range to a data structure" but again I might be being naive.

Use the checked module of bytemuck.

3 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.