// Copyright 2025 Don MacAskill. Licensed under MIT or Apache-2.0. #![allow(dead_code)] use crate::traits::{CrcCalculator, CrcWidth}; use crate::{arch, cache, CrcAlgorithm, CrcParams}; /// CRC algorithm parameters matching the CRC catalogue specification. /// /// This struct describes a CRC algorithm using the fields specified by the /// [Catalogue of parametrised CRC algorithms](https://reveng.sourceforge.io/crc-catalogue/all.htm). #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct Algorithm { /// The number of bit cells in the linear feedback shift register; the degree of the generator /// polynomial, minus one. pub width: u8, /// The generator polynomial that sets the feedback tap positions of the shift register. pub poly: W, /// The settings of the bit cells at the start of each calculation, before reading the first /// message bit. pub init: W, /// If `true`, characters are read bit-by-bit, least significant bit (LSB) first; /// if `false`, most significant bit (MSB) first. pub refin: bool, /// If `true`, the contents of the register after reading the last message bit are reflected /// before presentation; if `false`, they are unreflected. pub refout: bool, /// The XOR value applied to the contents of the register after the last message bit has been /// read and after the optional reflection. pub xorout: W, /// The contents of the register after initialising, reading the UTF-8 string `"123456789"`, /// optionally reflecting, and applying the final XOR. pub check: W, /// The contents of the register after initialising, reading an error-free codeword and /// optionally reflecting the register, but not applying the final XOR. pub residue: W, } /// CRC-16 width implementation #[derive(Clone, Copy)] pub struct Width16; impl CrcWidth for Width16 { const WIDTH: u32 = 16; type Value = u16; } /// CRC-32 width implementation #[derive(Clone, Copy)] pub struct Width32; impl CrcWidth for Width32 { const WIDTH: u32 = 32; type Value = u32; } /// CRC-64 width implementation #[derive(Clone, Copy)] pub struct Width64; impl CrcWidth for Width64 { const WIDTH: u32 = 64; type Value = u64; } /// CRC State wrapper to manage the SIMD operations and reflection mode #[derive(Debug, Clone, Copy)] pub struct CrcState { pub value: T, pub reflected: bool, } pub(crate) struct Calculator {} impl CrcCalculator for Calculator { #[inline(always)] fn calculate(state: u64, data: &[u8], params: &CrcParams) -> u64 { unsafe { arch::update(state, data, params) } } } impl CrcParams { /// Creates custom CRC parameters for a given set of Rocksoft CRC parameters. /// /// Uses an internal cache to avoid regenerating folding keys for identical parameter sets. /// The first call with a given set of parameters will generate and cache the keys, while /// subsequent calls with the same parameters will use the cached keys for optimal performance. /// /// Does not support mis-matched refin/refout parameters, so both must be true or both false. /// /// Rocksoft parameters for lots of variants: https://reveng.sourceforge.io/crc-catalogue/all.htm pub fn new( name: &'static str, width: u8, poly: u64, init: u64, reflected: bool, xorout: u64, check: u64, ) -> Self { let keys_array = cache::get_or_generate_keys(width, poly, reflected); let keys = crate::CrcKeysStorage::from_keys_fold_256(keys_array); // Validate width is supported if width != 16 && width != 32 && width != 64 { panic!("Unsupported width: {width}"); } // For reflected CRC-16, bit-reverse the init value for the SIMD algorithm let init_algorithm = if width == 16 && reflected { (init as u16).reverse_bits() as u64 } else { init }; Self { algorithm: CrcAlgorithm::CrcCustom, name, width, poly, init, init_algorithm, refin: reflected, refout: reflected, xorout, check, keys, } } /// Gets a key at the specified index, returning 0 if out of bounds. /// This provides safe access regardless of internal key storage format. #[inline(always)] pub fn get_key(&self, index: usize) -> u64 { self.keys.get_key(index) } /// Gets a key at the specified index, returning None if out of bounds. /// This provides optional key access for cases where bounds checking is needed. #[inline(always)] pub fn get_key_checked(&self, index: usize) -> Option { if index < self.keys.key_count() { Some(self.keys.get_key(index)) } else { None } } /// Returns the number of keys available in this CrcParams instance. #[inline(always)] pub fn key_count(&self) -> usize { self.keys.key_count() } }