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

Adds header and footer attributes and traits #106

Open
wants to merge 8 commits into
base: master
Choose a base branch
from

Conversation

JomerDev
Copy link

Hello. I do quite like this library but had a need for some more features, so I wrote a PR for them.
This PR adds attributes and traits to add static or dynamic headers and footers to a packed struct.

For static values a header and/or footer can be specified with the header and footer attributes. They will be added on pack and will be ignored on unpack. No validation is happening on unpack for either field.

#[derive(PackedStruct, Debug, Copy, Clone, PartialEq)]
#[packed_struct(bit_numbering = "msb0", endian = "msb", header = [0x80, 0x60], footer = 0x16)]
pub struct FunctionCommand {

This fixes #91

If a more dynamic value is needed for either header or footer I've added two traits, PackedStructHeader and PackedStructFooter. They each provide the get_(header/footer) and validate_(header/footer) methods, which receive the already packed structure and can be used to generate values and to validate them. Currently the size of the header or footer must be specified with an attribute ((header/footer)_size = X) because I could not find a way to get the size of the return value in the derive macro. The validation method gets called before the rest of the struct gets unpacked. I added a PackingError::UserError to allow users to easily return possible validation errors

#[derive(PackedStruct, Debug, Clone, PartialEq)]
#[packed_struct(bit_numbering = "msb0", endian = "msb", footer_size = 1)]
pub struct DynamicCommand {
    [...]
}

impl PackedStructFooter for DynamicCommand {
    type FooterByteArray = [u8; 1];

    fn get_footer(&self, data: &[u8]) -> packed_struct::PackingResult<Self::FooterByteArray> {
        let mut xor: u8 = 0;
        data.into_iter().for_each(|value| xor ^= value);
        Ok([xor])
    }

    fn validate_footer(src: &[u8]) -> packed_struct::PackingResult<()> {
        let mut xor: u8 = 0;
        // We don't want to xor the xor value at the end
        src[0..src.len()].into_iter().for_each(|value| xor ^= value);
        if src.ends_with(&[xor]) {
            Ok(())
        } else {
            Err(PackingError::UserError(format!("Invalid xor: {} to {:?}", xor, src.last().unwrap())))
        }
    }
}

I've also added tests/examples for the above. I'm currently also looking into allowing enums with structs inside to work with packed_struct as well by using PackedStructHeader but if I do this it'll be part of a separate PR

Still working on adding it to the pack call
Add header and footer attributes
Add header and footer traits
Add optional validation through header and footer
@JomerDev
Copy link
Author

The crash in the mips build is caused by the tap library, not my changes

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

Successfully merging this pull request may close these issues.

Support for reserved bit with arbitrary value
1 participant