crcany_core/model/
wordwise.rs

1use byteorder::ByteOrder;
2
3use crate::crc::Crc;
4use crate::model::BytewiseModel;
5use crate::spec::Spec;
6use crate::util::{ones, reverse};
7
8pub struct WordwiseModel<Endianness: byteorder::ByteOrder, const WORD_BITS: u16> {
9    model: BytewiseModel,
10    // tables for word-wise calculation
11    pub table: [[u128; 256]; 8],
12    _endianness: core::marker::PhantomData<Endianness>,
13}
14
15trait TableFiller {
16    fn fill_table(&mut self);
17    fn swap(&self) -> bool;
18}
19
20impl<const WORD_BITS: u16> TableFiller for WordwiseModel<byteorder::LittleEndian, WORD_BITS> {
21    fn fill_table(&mut self) {
22        self.fill_table_kernel(self.swap());
23    }
24
25    fn swap(&self) -> bool {
26        !self.model.reflect()
27    }
28}
29
30impl<const WORD_BITS: u16> TableFiller for WordwiseModel<byteorder::BigEndian, WORD_BITS> {
31    fn fill_table(&mut self) {
32        self.fill_table_kernel(self.swap());
33    }
34
35    fn swap(&self) -> bool {
36        self.model.reflect()
37    }
38}
39
40impl<const WORD_BITS: u16> WordwiseModel<byteorder::LittleEndian, WORD_BITS> {
41    pub fn from_spec(spec: Spec) -> Self {
42        let mut me = WordwiseModel::from_spec_kernel(spec);
43        me.fill_table();
44        me
45    }
46}
47
48impl<const WORD_BITS: u16> WordwiseModel<byteorder::BigEndian, WORD_BITS> {
49    pub fn from_spec(spec: Spec) -> Self {
50        let mut me = WordwiseModel::from_spec_kernel(spec);
51        me.fill_table();
52        me
53    }
54}
55
56impl Crc for WordwiseModel<byteorder::NativeEndian, { usize::BITS as _ }> {
57    type Int = u128;
58
59    fn init(&self) -> u128 {
60        self.model.init()
61    }
62
63    fn add_bytes(&self, mut crc: u128, data: &[u8]) -> u128 {
64        if data.is_empty() {
65            return crc;
66        }
67
68        let top = self.top();
69        let shift = if self.model.width() <= 8 {
70            8 - self.model.width()
71        } else {
72            self.model.width() - 8
73        };
74
75        if self.model.reverse() {
76            crc = reverse(crc, self.model.width());
77        }
78
79        let word_bytes = usize::BITS >> 3;
80
81        let mut shifted = false;
82
83        if self.model.reflect() {
84            crc &= ones(self.model.width());
85        } else if self.model.width() <= 8 {
86            crc <<= shift;
87        }
88
89        // TODO: slice not iterate
90        let mut iter = data.iter().copied();
91
92        loop {
93            let mut next = vec![];
94
95            for _ in 0..word_bytes {
96                if let Some(c) = iter.next() {
97                    next.push(c);
98                }
99            }
100
101            if next.len() == word_bytes as _ {
102                if !shifted {
103                    crc <<= top;
104                    if self.swap() {
105                        crc = (crc as usize).swap_bytes() as _;
106                    }
107                    shifted = true;
108                }
109
110                crc ^= byteorder::NativeEndian::read_uint128(&next[..], word_bytes as _);
111
112                // TODO: FIX THIS!
113                assert_eq!(word_bytes, 8);
114
115                // TODO: THIS IS LITTLE-ENDIAN!
116                crc = self.table[(word_bytes - 1) as usize][(crc as u8) as usize]
117                    ^ self.table[(word_bytes - 2) as usize][((crc >> 8) as u8) as usize]
118                    ^ self.table[(word_bytes - 3) as usize][((crc >> 16) as u8) as usize]
119                    ^ self.table[(word_bytes - 4) as usize][((crc >> 24) as u8) as usize]
120                    ^ self.table[(word_bytes - 5) as usize][((crc >> 32) as u8) as usize]
121                    ^ self.table[(word_bytes - 6) as usize][((crc >> 40) as u8) as usize]
122                    ^ self.table[(word_bytes - 7) as usize][((crc >> 48) as u8) as usize]
123                    ^ self.table[(word_bytes - 8) as usize][((crc >> 56) as u8) as usize];
124            } else if next.is_empty() {
125                break;
126            } else {
127                if shifted {
128                    if self.swap() {
129                        crc = (crc as usize).swap_bytes() as _;
130                    }
131                    crc >>= top;
132                    shifted = false;
133                }
134
135                if self.model.reflect() {
136                    for byte in next {
137                        let byte = byte as u128;
138                        crc = (crc >> 8) ^ self.model.table[((crc ^ byte) as u8) as usize];
139                    }
140                } else if self.model.width() <= 8 {
141                    for byte in next {
142                        let byte = byte as u128;
143                        crc = self.model.table[((crc ^ byte) as u8) as usize];
144                    }
145                    crc >>= shift;
146                } else {
147                    for byte in next {
148                        let byte = byte as u128;
149                        crc =
150                            (crc << 8) ^ self.model.table[(((crc >> shift) ^ byte) as u8) as usize];
151                    }
152                    crc &= ones(self.model.width());
153                }
154
155                break;
156            }
157        }
158
159        if shifted {
160            if self.swap() {
161                crc = crc.swap_bytes();
162            }
163            crc >>= top;
164        }
165
166        if !self.model.reflect() && self.model.width() > 8 {
167            crc &= ones(self.model.width());
168        }
169
170        if self.model.reverse() {
171            crc = reverse(crc, self.model.width());
172        }
173
174        crc as _
175    }
176}
177
178impl<Endianness: byteorder::ByteOrder, const WORD_BITS: u16> WordwiseModel<Endianness, WORD_BITS> {
179    fn from_spec_kernel(spec: Spec) -> WordwiseModel<Endianness, WORD_BITS> {
180        WordwiseModel {
181            model: BytewiseModel::from_spec(spec),
182            table: [[0; 256]; 8],
183            _endianness: core::marker::PhantomData,
184        }
185    }
186
187    fn top(&self) -> u16 {
188        if self.model.reflect() {
189            0
190        } else {
191            WORD_BITS
192                - (if self.model.width() > 8 {
193                    self.model.width()
194                } else {
195                    8
196                })
197        }
198    }
199
200    fn fill_table_kernel(&mut self, swap: bool) {
201        let top = self.top();
202
203        let mut xor = self.model.xorout();
204        if self.model.width() < 8 && !self.model.reflect() {
205            xor <<= 8 - self.model.width();
206        }
207
208        for k in 0..256 {
209            let mut crc = self.model.table[k];
210            self.table[0][k] = if swap {
211                ((crc << top) as usize).swap_bytes() as _ // TODO: this is inelegant
212            } else {
213                crc << top
214            };
215            for n in 1..(WORD_BITS as usize >> 3) {
216                crc ^= xor;
217                if self.model.reflect() {
218                    crc = (crc >> 8) ^ self.model.table[(crc as u8) as usize];
219                } else if self.model.width() <= 8 {
220                    crc = self.model.table[(crc as u8) as usize];
221                } else {
222                    crc = (crc << 8)
223                        ^ self.model.table[((crc >> (self.model.width() - 8)) as u8) as usize];
224                }
225                crc ^= xor;
226                self.table[n][k] = if swap {
227                    ((crc << top) as usize).swap_bytes() as _ // TODO: this is inelegant
228                } else {
229                    crc << top
230                };
231            }
232        }
233    }
234}