crcany_core/model/
wordwise.rs1use 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 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 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 assert_eq!(word_bytes, 8);
114
115 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 _ } 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 _ } else {
229 crc << top
230 };
231 }
232 }
233 }
234}