crc_fast/
structs.rs

1// Copyright 2025 Don MacAskill. Licensed under MIT or Apache-2.0.
2
3#![allow(dead_code)]
4
5use crate::traits::{CrcCalculator, CrcWidth};
6use crate::{arch, cache, CrcAlgorithm, CrcParams};
7
8/// CRC algorithm parameters matching the CRC catalogue specification.
9///
10/// This struct describes a CRC algorithm using the fields specified by the
11/// [Catalogue of parametrised CRC algorithms](https://reveng.sourceforge.io/crc-catalogue/all.htm).
12#[derive(Clone, Copy, Debug, PartialEq, Eq)]
13pub struct Algorithm<W> {
14    /// The number of bit cells in the linear feedback shift register; the degree of the generator
15    /// polynomial, minus one.
16    pub width: u8,
17    /// The generator polynomial that sets the feedback tap positions of the shift register.
18    pub poly: W,
19    /// The settings of the bit cells at the start of each calculation, before reading the first
20    /// message bit.
21    pub init: W,
22    /// If `true`, characters are read bit-by-bit, least significant bit (LSB) first;
23    /// if `false`, most significant bit (MSB) first.
24    pub refin: bool,
25    /// If `true`, the contents of the register after reading the last message bit are reflected
26    /// before presentation; if `false`, they are unreflected.
27    pub refout: bool,
28    /// The XOR value applied to the contents of the register after the last message bit has been
29    /// read and after the optional reflection.
30    pub xorout: W,
31    /// The contents of the register after initialising, reading the UTF-8 string `"123456789"`,
32    /// optionally reflecting, and applying the final XOR.
33    pub check: W,
34    /// The contents of the register after initialising, reading an error-free codeword and
35    /// optionally reflecting the register, but not applying the final XOR.
36    pub residue: W,
37}
38
39/// CRC-16 width implementation
40#[derive(Clone, Copy)]
41pub struct Width16;
42
43impl CrcWidth for Width16 {
44    const WIDTH: u32 = 16;
45    type Value = u16;
46}
47
48/// CRC-32 width implementation
49#[derive(Clone, Copy)]
50pub struct Width32;
51
52impl CrcWidth for Width32 {
53    const WIDTH: u32 = 32;
54    type Value = u32;
55}
56
57/// CRC-64 width implementation
58#[derive(Clone, Copy)]
59pub struct Width64;
60
61impl CrcWidth for Width64 {
62    const WIDTH: u32 = 64;
63    type Value = u64;
64}
65
66/// CRC State wrapper to manage the SIMD operations and reflection mode
67#[derive(Debug, Clone, Copy)]
68pub struct CrcState<T> {
69    pub value: T,
70    pub reflected: bool,
71}
72
73pub(crate) struct Calculator {}
74
75impl CrcCalculator for Calculator {
76    #[inline(always)]
77    fn calculate(state: u64, data: &[u8], params: &CrcParams) -> u64 {
78        unsafe { arch::update(state, data, params) }
79    }
80}
81
82impl CrcParams {
83    /// Creates custom CRC parameters for a given set of Rocksoft CRC parameters.
84    ///
85    /// Uses an internal cache to avoid regenerating folding keys for identical parameter sets.
86    /// The first call with a given set of parameters will generate and cache the keys, while
87    /// subsequent calls with the same parameters will use the cached keys for optimal performance.
88    ///
89    /// Does not support mis-matched refin/refout parameters, so both must be true or both false.
90    ///
91    /// Rocksoft parameters for lots of variants: https://reveng.sourceforge.io/crc-catalogue/all.htm
92    pub fn new(
93        name: &'static str,
94        width: u8,
95        poly: u64,
96        init: u64,
97        reflected: bool,
98        xorout: u64,
99        check: u64,
100    ) -> Self {
101        let keys_array = cache::get_or_generate_keys(width, poly, reflected);
102        let keys = crate::CrcKeysStorage::from_keys_fold_256(keys_array);
103
104        // Validate width is supported
105        if width != 16 && width != 32 && width != 64 {
106            panic!("Unsupported width: {width}");
107        }
108
109        // For reflected CRC-16, bit-reverse the init value for the SIMD algorithm
110        let init_algorithm = if width == 16 && reflected {
111            (init as u16).reverse_bits() as u64
112        } else {
113            init
114        };
115
116        Self {
117            algorithm: CrcAlgorithm::CrcCustom,
118            name,
119            width,
120            poly,
121            init,
122            init_algorithm,
123            refin: reflected,
124            refout: reflected,
125            xorout,
126            check,
127            keys,
128        }
129    }
130
131    /// Gets a key at the specified index, returning 0 if out of bounds.
132    /// This provides safe access regardless of internal key storage format.
133    #[inline(always)]
134    pub fn get_key(&self, index: usize) -> u64 {
135        self.keys.get_key(index)
136    }
137
138    /// Gets a key at the specified index, returning None if out of bounds.
139    /// This provides optional key access for cases where bounds checking is needed.
140    #[inline(always)]
141    pub fn get_key_checked(&self, index: usize) -> Option<u64> {
142        if index < self.keys.key_count() {
143            Some(self.keys.get_key(index))
144        } else {
145            None
146        }
147    }
148
149    /// Returns the number of keys available in this CrcParams instance.
150    #[inline(always)]
151    pub fn key_count(&self) -> usize {
152        self.keys.key_count()
153    }
154}