OXYGENHUB
# c8d9059e4e70 oxygen / vendor / crc-fast / src / structs.rs
5.0 KiB · Rust · last changed Strata: the cloud stores send through ureq, so every release target links 1 month ago source blame history raw
2cd40ea1 Andy McCall ↶ 1
// Copyright 2025 Don MacAskill. Licensed under MIT or Apache-2.0.
2
3
#![allow(dead_code)]
4
5
use crate::traits::{CrcCalculator, CrcWidth};
6
use 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)]
13
pub 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)]
41
pub struct Width16;
42
43
impl CrcWidth for Width16 {
44
    const WIDTH: u32 = 16;
45
    type Value = u16;
46
}
47
48
/// CRC-32 width implementation
49
#[derive(Clone, Copy)]
50
pub struct Width32;
51
52
impl CrcWidth for Width32 {
53
    const WIDTH: u32 = 32;
54
    type Value = u32;
55
}
56
57
/// CRC-64 width implementation
58
#[derive(Clone, Copy)]
59
pub struct Width64;
60
61
impl 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)]
68
pub struct CrcState<T> {
69
    pub value: T,
70
    pub reflected: bool,
71
}
72
73
pub(crate) struct Calculator {}
74
75
impl 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
82
impl 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
}