sharksforarms / deku

Declarative binary reading and writing: bit-level, symmetric, serialization/deserialization
Apache License 2.0
1.05k stars 54 forks source link

Ability to ignore excess bytes #443

Closed noahcoolboy closed 1 month ago

noahcoolboy commented 1 month ago

Hello! Deku is the perfect library for the project I'm working on, thank you for this!

However, there is one small feature I would like to request. I'm working with low-level network packets, and ethernet frames have a minimum length of 64 bytes. Payloads smaller than 64 get padded with zeroes at the end, which causes deku to throw a Parse("Too much data"). Would it be possible to add a top level attribute for ignore excess bytes, instead of throwing?

Thanks!

sharksforarms commented 1 month ago

There's actually multiple ways to do this, depending on your requirements:

use deku::prelude::*;
use std::{convert::TryFrom, io::Cursor};

fn main() {
    let test_data: &[u8] = &[0xc0, 0xfe, 0xc0, 0xfe, 0xc0, 0xfe];

    {
        #[derive(Debug, PartialEq, DekuRead, DekuWrite)]
        struct Packet {
            field: u8,
        }
        // will try to read all of test_data, fail
        let _packet = Packet::try_from(test_data).expect_err("this will fail");
    }

    {
        #[derive(Debug, PartialEq, DekuRead, DekuWrite)]
        struct Packet {
            field: u8,
        }

        let mut data = Cursor::new(test_data.to_vec());
        // read a single packet, data will contain the rest
        let (_read, packet) = Packet::from_reader((&mut data, 0)).unwrap();
    }

    {
        #[derive(Debug, PartialEq, DekuRead, DekuWrite)]
        struct Packet {
            field: u8,
        }

        // read a single packet, return the rest
        let (_packet, _rest) = Packet::from_bytes((test_data, 0)).unwrap();
    }

    {
        #[derive(Debug, PartialEq, DekuRead, DekuWrite)]
        struct Packet {
            field: u8,

            // store the rest of the data in the struct
            #[deku(read_all)]
            rest: Vec<u8>,
        }
        let _packet = Packet::try_from(test_data).unwrap();
    }

}