Skip to content

Conversation

@NickUfer
Copy link

@NickUfer NickUfer commented Jun 13, 2025

This pr adds the DigestOps trait which is implemented by all Digest types. It allows to use update and finalize of any Digest without the Implementation (Table) constraint.

This is useful for cases where code does not care about the Implementation (Table) of a digest, like a checksum function on a struct which generates a checksum for it.

Before this trait I had to use this to be able to accept digests with (almost) any table type:

use crc::NoTable;

pub enum Digest<'a, W: crc::Width> {
    NoTable(crc::Digest<'a, W, NoTable>),
    Table(crc::Digest<'a, W>)
}

impl Digest<'_, u32> {
    pub fn update(&mut self, bytes: &[u8]) {
        match self {
            Digest::NoTable(digest) => {
                digest.update(bytes)
            }
            Digest::Table(digest) => {
                digest.update(bytes)
            }
        }
    }
    
    pub fn finalize(self) -> u32 {
        match self {
            Digest::NoTable(digest) => {
                digest.finalize()
            }
            Digest::Table(digest) => {
                digest.finalize()
            }
        }
    }
}

Here is an example how this can be done better with tools in the library itself, the DigestOps trait. The Width is still relevant but the implementation detail of Implementation (Table) is gone, as it is not relevant.

use crc::NoTable;

pub struct SomeStruct {
    x: u32,
    buffer: [u8; 64],
    y: bool,
}

impl SomeStruct {
    pub fn checksum(&self, mut digest: impl crc::DigestOps<Width = u32>) -> u32 {
        digest.update(&self.x.to_le_bytes());
        digest.update(&self.buffer);

        let y_byte: u8 = if self.y { 1 } else { 0 };
        digest.update(&[y_byte]);

        digest.finalize()
    }
}

fn main() {
    let my_struct = SomeStruct {
        x: 42,
        buffer: [0; 64],
        y: true,
    };

    let crc32 = crc::Crc::<u32>::new(&crc::CRC_32_ISO_HDLC);
    let checksum = my_struct.checksum(crc32.digest());

    let crc32_no_table = crc::Crc::<u32, NoTable>::new(&crc::CRC_32_ISO_HDLC);
    let checksum_no_table = my_struct.checksum(crc32_no_table.digest());
}

The finalize function is duplicated as the trait function cannot be of type const fn and to keep backward compatibility I kept it.

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.

1 participant