Skip to content

Implement DigestOps trait for Digest across CRC types. #125

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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

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