1use std::collections::HashMap;
33use std::path::Path;
34
35use serde::Serialize;
36
37use crate::codegen_sva::ddr4_jedec::Ddr4Grade;
38use crate::model::gguf::Gguf;
39use crate::model::quant::GgmlType;
40use crate::model::reference::WeightSource;
41use crate::spatial::d5005::{Beat, DDR_CHANNELS};
42use crate::spatial::decode::GgufHeader;
43
44use super::machine::Layout as MachineLayout;
45use super::model::EngineNumerics;
46use super::program::lower;
47
48pub const TILE_LINES: u64 = 512;
50pub const CHECK_BYTES: u64 = 4;
52
53#[derive(Clone, Debug, PartialEq, Eq)]
58pub struct TensorEntry {
59 pub name: String,
60 pub ty: GgmlType,
61 pub dims: Vec<u64>,
62 pub tap_major: Option<u64>,
63 pub streamed: bool,
64}
65
66impl TensorEntry {
67 pub fn rows(&self) -> u64 {
68 self.dims.iter().skip(1).product()
69 }
70
71 pub fn row_bytes(&self) -> u64 {
72 self.ty.bytes_for(self.dims[0] as usize) as u64
73 }
74}
75
76#[derive(Clone, Debug, PartialEq, Eq)]
78pub enum ImageError {
79 MissingMetadata(String),
80 UnknownType { tensor: String, id: u32 },
81 RaggedRow { tensor: String, elems: u64, block: u64 },
83 Order(String),
85 TooBig { channel: u32, lines: u64, capacity: u64 },
87 RowPastTile { tensor: String, row_bytes: u64, room: u64 },
89 EmptyStripe,
91 StreamedKernel(String),
93}
94
95#[derive(Clone, Debug, PartialEq, Eq)]
97pub struct TensorTable {
98 pub blocks: u64,
99 pub tensors: Vec<TensorEntry>,
100}
101
102const BLOCK_READS: &[&str] = &[
106 "attn_norm.weight",
107 "attn_qkv.weight",
108 "attn_gate.weight",
109 "ssm_beta.weight",
110 "ssm_alpha.weight",
111 "ssm_conv1d.weight",
112 "ssm_dt.bias",
113 "ssm_a",
114 "ssm_norm.weight",
115 "ssm_out.weight",
116 "attn_q.weight",
117 "attn_k.weight",
118 "attn_v.weight",
119 "attn_q_norm.weight",
120 "attn_k_norm.weight",
121 "attn_output.weight",
122 "post_attention_norm.weight",
123 "ffn_norm.weight",
124 "ffn_gate.weight",
125 "ffn_up.weight",
126 "ffn_down.weight",
127];
128
129impl TensorTable {
130 pub fn from_rows(blocks: u64, rows: impl IntoIterator<Item = (String, Vec<u64>, u32)>) -> Result<TensorTable, ImageError> {
132 let mut tensors = Vec::new();
133 for (name, dims, id) in rows {
134 let ty = GgmlType::from_id(id).map_err(|id| ImageError::UnknownType { tensor: name.clone(), id })?;
135 let elems = dims.first().copied().unwrap_or(0);
136 let block = ty.block_len() as u64;
137 if elems % block != 0 || dims.contains(&0) || dims.is_empty() {
138 return Err(ImageError::RaggedRow { tensor: name, elems, block });
139 }
140 tensors.push(TensorEntry { name, ty, dims, tap_major: None, streamed: false });
141 }
142 Ok(TensorTable { blocks, tensors })
143 }
144
145 pub fn of_gguf(g: &Gguf) -> Result<TensorTable, ImageError> {
147 let meta = |key: &str| g.arch_meta(key).and_then(|v| v.as_u64());
148 let blocks = meta("block_count").ok_or_else(|| ImageError::MissingMetadata("block_count".into()))?;
149 TensorTable::from_rows(blocks.saturating_sub(meta("nextn_predict_layers").unwrap_or(0)), g.tensor_names())
150 }
151
152 pub fn of_header(h: &GgufHeader) -> Result<TensorTable, ImageError> {
154 let blocks = h.meta_u64("block_count").ok_or_else(|| ImageError::MissingMetadata("block_count".into()))?;
155 let rows = h.tensors.iter().map(|t| (t.name.clone(), t.dims.clone(), t.type_id));
156 TensorTable::from_rows(blocks.saturating_sub(h.meta_u64("nextn_predict_layers").unwrap_or(0)), rows)
157 }
158
159 pub fn read_order(&self) -> Vec<usize> {
163 let at: HashMap<&str, usize> = self.tensors.iter().enumerate().map(|(i, t)| (t.name.as_str(), i)).collect();
164 let mut order = Vec::with_capacity(self.tensors.len());
165 let push = |name: &str, order: &mut Vec<usize>| {
166 if let Some(&i) = at.get(name) {
167 order.push(i);
168 }
169 };
170 push("token_embd.weight", &mut order);
171 for b in 0..self.blocks {
172 for key in BLOCK_READS {
173 push(&format!("blk.{b}.{key}"), &mut order);
174 }
175 }
176 push("output_norm.weight", &mut order);
177 push("output.weight", &mut order);
178 let mut placed = vec![false; self.tensors.len()];
179 for &i in &order {
180 placed[i] = true;
181 }
182 order.extend((0..self.tensors.len()).filter(|&i| !placed[i]));
183 order
184 }
185}
186
187#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
194pub struct ImageLayout {
195 pub channels: u32,
196 pub line_bytes: u64,
197 pub tile_lines: u64,
198 pub capacity_lines: u64,
199 pub check: bool,
200 #[serde(skip_serializing_if = "Option::is_none")]
201 pub stripe: Option<u64>,
202 #[serde(skip_serializing_if = "std::ops::Not::not")]
203 pub octets: bool,
204 #[serde(skip_serializing_if = "packed")]
205 pub slot: u64,
206}
207
208fn packed(slot: &u64) -> bool {
209 *slot == 1
210}
211
212impl ImageLayout {
213 pub fn d5005(beat: Beat) -> ImageLayout {
215 let ddr = Ddr4Grade::D5005_EMIF.at();
216 let (line_bytes, check) = match beat {
217 Beat::Data64 => (64, false),
218 Beat::Full72 => (ddr.burst_bits() / 8, true),
219 };
220 ImageLayout { channels: DDR_CHANNELS, line_bytes, tile_lines: TILE_LINES, capacity_lines: ddr.lines(), check, stripe: None, octets: false, slot: 1 }
221 }
222
223 fn check_bytes(&self) -> u64 {
224 if self.check {
225 CHECK_BYTES
226 } else {
227 0
228 }
229 }
230
231 pub fn lines_for(&self, bytes: u64) -> u64 {
233 (bytes + self.check_bytes()).div_ceil(self.line_bytes)
234 }
235}
236
237#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
244pub struct Placement {
245 pub name: String,
246 pub ty: &'static str,
247 pub dims: Vec<u64>,
248 pub rows: u64,
249 pub row_bytes: u64,
250 pub pieces: u64,
251 pub rows_per_tile: u64,
252 pub tile_lines: u64,
253 pub channels: Vec<u32>,
254 pub first_line: Vec<u64>,
255 pub first_tile: usize,
256 pub tile_count: usize,
257 pub tap_major: Option<u64>,
258 pub block_bytes: u64,
259 pub block_major: bool,
260 #[serde(skip_serializing_if = "unpadded")]
262 pub pad: u64,
263}
264
265fn unpadded(pad: &u64) -> bool {
266 *pad == 0
267}
268
269impl Placement {
270 pub fn slot_bytes(&self) -> u64 {
272 self.block_bytes + self.pad
273 }
274
275 pub fn image_row_bytes(&self) -> u64 {
277 if self.pad == 0 {
278 self.row_bytes
279 } else {
280 self.row_bytes / self.block_bytes * self.slot_bytes()
281 }
282 }
283}
284
285#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
287pub struct Tile {
288 pub tensor: usize,
289 pub first_row: u64,
290 pub end_row: u64,
291 pub channel: u32,
292 pub line: u64,
293 pub lines: u64,
294}
295
296#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
299pub struct Image {
300 pub layout: ImageLayout,
301 pub tensors: Vec<Placement>,
302 pub tiles: Vec<Tile>,
303 pub channel_lines: Vec<u64>,
304}
305
306pub fn weight_image(table: &TensorTable, order: &[usize], layout: &ImageLayout) -> Result<Image, ImageError> {
308 let mut seen = vec![false; table.tensors.len()];
309 for &i in order {
310 match seen.get_mut(i) {
311 None => return Err(ImageError::Order(format!("index {i} of {} tensors", table.tensors.len()))),
312 Some(true) => return Err(ImageError::Order(format!("`{}` twice", table.tensors[i].name))),
313 Some(s) => *s = true,
314 }
315 }
316 if let Some(i) = seen.iter().position(|s| !s) {
317 return Err(ImageError::Order(format!("`{}` left out", table.tensors[i].name)));
318 }
319 if layout.stripe == Some(0) {
320 return Err(ImageError::EmptyStripe);
321 }
322 let c = layout.channels as usize;
323 let room = (layout.tile_lines * layout.line_bytes).saturating_sub(layout.check_bytes());
324 let mut loads = vec![0u64; c];
325 let mut tensors = Vec::with_capacity(order.len());
326 let mut tiles = Vec::new();
327 for &i in order {
328 let e = &table.tensors[i];
329 let stripe = layout.stripe.filter(|_| e.streamed);
330 if stripe.is_some() && e.tap_major.is_some() {
331 return Err(ImageError::StreamedKernel(e.name.clone()));
332 }
333 let pieces = pieces_of(e, room)?;
334 let (rows, row_bytes) = (e.rows() * pieces, e.row_bytes() / pieces);
335 if stripe.is_some() && layout.octets && e.ty == GgmlType::Q8_0 && e.dims[0] % 256 != 0 {
336 return Err(ImageError::RaggedRow { tensor: e.name.clone(), elems: e.dims[0], block: 256 });
337 }
338 let block_bytes = e.ty.block_bytes() as u64 * if stripe.is_some() && layout.octets && e.ty == GgmlType::Q8_0 { 8 } else { 1 };
339 let pad = if stripe.is_some() { block_bytes.next_multiple_of(layout.slot) - block_bytes } else { 0 };
340 let image_row = row_bytes / block_bytes * (block_bytes + pad);
341 let rows_per_tile = match stripe {
342 Some(pairs) => 2 * pairs,
343 None => room / row_bytes,
344 }
345 .max(1)
346 .min(rows.max(1));
347 let tile_lines = layout.lines_for(rows_per_tile * image_row);
348 let mut channels: Vec<u32> = (0..layout.channels).collect();
349 channels.sort_by_key(|&ch| (loads[ch as usize], ch));
350 let first_line: Vec<u64> = channels.iter().map(|&ch| loads[ch as usize]).collect();
351 let first_tile = tiles.len();
352 let mut first_row = 0;
353 let mut turn = 0;
354 while first_row < rows {
355 let end_row = (first_row + rows_per_tile).min(rows);
356 let channel = channels[turn % c];
357 let lines = layout.lines_for((end_row - first_row) * image_row);
358 tiles.push(Tile { tensor: tensors.len(), first_row, end_row, channel, line: loads[channel as usize], lines });
359 loads[channel as usize] += lines;
360 first_row = end_row;
361 turn += 1;
362 }
363 tensors.push(Placement {
364 name: e.name.clone(),
365 ty: e.ty.name(),
366 dims: e.dims.clone(),
367 rows,
368 row_bytes,
369 pieces,
370 rows_per_tile,
371 tile_lines,
372 channels,
373 first_line,
374 first_tile,
375 tile_count: tiles.len() - first_tile,
376 tap_major: e.tap_major,
377 block_bytes,
378 block_major: stripe.is_some(),
379 pad,
380 });
381 }
382 for (ch, &lines) in loads.iter().enumerate() {
383 if lines > layout.capacity_lines {
384 return Err(ImageError::TooBig { channel: ch as u32, lines, capacity: layout.capacity_lines });
385 }
386 }
387 Ok(Image { layout: *layout, tensors, tiles, channel_lines: loads })
388}
389
390fn pieces_of(e: &TensorEntry, room: u64) -> Result<u64, ImageError> {
393 let row_bytes = e.row_bytes();
394 if e.tap_major.is_none() || row_bytes <= room {
395 return Ok(1);
396 }
397 let blocks = e.dims[0] / e.ty.block_len() as u64;
398 let block_bytes = row_bytes / blocks;
399 (row_bytes.div_ceil(room)..=blocks)
400 .find(|&p| blocks % p == 0 && blocks / p * block_bytes <= room)
401 .ok_or(ImageError::RowPastTile { tensor: e.name.clone(), row_bytes, room })
402}
403
404pub fn image_of(machine: &MachineLayout, layout: &ImageLayout) -> Result<Image, ImageError> {
407 let mut tensors = Vec::with_capacity(machine.tensors.len());
408 for p in &machine.tensors {
409 let entry = match p.taps {
410 None => TensorEntry { name: p.name.clone(), ty: p.ty, dims: p.dims.clone(), tap_major: None, streamed: p.streamed },
411 Some(taps) => {
412 if p.dims.len() != 2 || p.dims[0] != taps as u64 {
413 return Err(ImageError::RaggedRow { tensor: p.name.clone(), elems: p.dims[0], block: taps as u64 });
414 }
415 TensorEntry { name: p.name.clone(), ty: p.ty, dims: vec![p.dims[1], taps as u64], tap_major: Some(taps as u64), streamed: p.streamed }
416 }
417 };
418 tensors.push(entry);
419 }
420 let order: Vec<usize> = (0..tensors.len()).collect();
421 weight_image(&TensorTable { blocks: 0, tensors }, &order, layout)
422}
423
424pub fn streamed_image_of(machine: &MachineLayout, layout: &ImageLayout) -> Result<(Image, Vec<usize>), ImageError> {
428 let indices: Vec<usize> = (0..machine.tensors.len()).filter(|&i| machine.tensors[i].streamed).collect();
429 let tensors = indices
430 .iter()
431 .map(|&i| {
432 let p = &machine.tensors[i];
433 TensorEntry { name: p.name.clone(), ty: p.ty, dims: p.dims.clone(), tap_major: None, streamed: true }
434 })
435 .collect();
436 let order: Vec<usize> = (0..indices.len()).collect();
437 Ok((weight_image(&TensorTable { blocks: 0, tensors }, &order, layout)?, indices))
438}
439
440struct Described<'a>(&'a TensorTable);
443
444impl WeightSource for Described<'_> {
445 fn describe(&self, name: &str) -> std::io::Result<(GgmlType, Vec<u64>)> {
446 self.0
447 .tensors
448 .iter()
449 .find(|t| t.name == name)
450 .map(|t| (t.ty, t.dims.clone()))
451 .ok_or_else(|| std::io::Error::new(std::io::ErrorKind::NotFound, format!("no tensor {name}")))
452 }
453 fn row_bytes(&mut self, name: &str, _: usize, _: usize) -> std::io::Result<Vec<u8>> {
454 Err(std::io::Error::new(std::io::ErrorKind::Unsupported, format!("a header holds no bytes of {name}")))
455 }
456 fn has(&self, name: &str) -> bool {
457 self.0.tensors.iter().any(|t| t.name == name)
458 }
459}
460
461pub fn machine_of(h: &GgufHeader) -> Result<MachineLayout, String> {
464 let table = TensorTable::of_header(h).map_err(|e| format!("{e:?}"))?;
465 let spec = h.spec().map_err(|e| format!("{e:?}"))?;
466 let numerics = EngineNumerics::fastest();
467 let program = lower(&spec, numerics, 1).map_err(|e| format!("{}: {e}", spec.arch))?.program;
468 MachineLayout::of(&spec, numerics, &program, &Described(&table), 1, 1).map_err(|e| format!("{e:?}"))
469}
470
471impl Image {
472 pub fn channel_bytes(&self) -> Vec<u64> {
474 self.channel_lines.iter().map(|l| l * self.layout.line_bytes).collect()
475 }
476
477 pub fn locate(&self, tensor: usize, row: u64) -> (u32, u64) {
480 self.locate_block(tensor, row, 0)
481 }
482
483 pub fn locate_block(&self, tensor: usize, row: u64, block: u64) -> (u32, u64) {
487 let p = &self.tensors[tensor];
488 let tile = row / p.rows_per_tile;
489 let turn = (tile % p.channels.len() as u64) as usize;
490 let line = p.first_line[turn] + tile / p.channels.len() as u64 * p.tile_lines;
491 let (r, held) = (row % p.rows_per_tile, p.rows_per_tile.min(p.rows - tile * p.rows_per_tile));
492 let within = if p.block_major { (block * held + r) * p.slot_bytes() } else { r * p.row_bytes + block * p.block_bytes };
493 (p.channels[turn], line * self.layout.line_bytes + within)
494 }
495
496 pub fn stored_rows(&self, tensor: usize, source: &mut dyn WeightSource, first: u64, count: u64) -> std::io::Result<Vec<u8>> {
499 let p = &self.tensors[tensor];
500 let (lo, hi) = (first / p.pieces, (first + count).div_ceil(p.pieces));
501 let whole = self.whole_rows(tensor, source, lo, hi - lo)?;
502 let skip = ((first - lo * p.pieces) * p.row_bytes) as usize;
503 Ok(whole[skip..skip + (count * p.row_bytes) as usize].to_vec())
504 }
505
506 fn whole_rows(&self, tensor: usize, source: &mut dyn WeightSource, first: u64, count: u64) -> std::io::Result<Vec<u8>> {
509 let p = &self.tensors[tensor];
510 let Some(taps) = p.tap_major else {
511 return source.row_bytes(&p.name, first as usize, count as usize);
512 };
513 let channels = p.dims[0];
514 let element = p.row_bytes * p.pieces / channels;
515 let checkpoint = source.row_bytes(&p.name, 0, channels as usize)?;
516 let mut out = Vec::with_capacity((count * p.row_bytes * p.pieces) as usize);
517 for tap in first..first + count {
518 for c in 0..channels {
519 let at = ((c * taps + tap) * element) as usize;
520 out.extend_from_slice(&checkpoint[at..at + element as usize]);
521 }
522 }
523 Ok(out)
524 }
525
526 fn tile_bytes(&self, t: &Tile, source: &mut dyn WeightSource) -> std::io::Result<Vec<u8>> {
529 let held = t.end_row - t.first_row;
530 let mut rows = self.stored_rows(t.tensor, source, t.first_row, held)?;
531 let p = &self.tensors[t.tensor];
532 if p.block_major {
533 let (bb, pad, row_bytes) = (p.block_bytes as usize, p.pad as usize, p.row_bytes as usize);
534 let mut out = Vec::with_capacity(rows.len() / bb * (bb + pad));
535 for b in 0..row_bytes / bb {
536 for r in 0..held as usize {
537 out.extend_from_slice(&rows[r * row_bytes + b * bb..r * row_bytes + (b + 1) * bb]);
538 out.resize(out.len() + pad, 0);
539 }
540 }
541 rows = out;
542 }
543 let mut span = vec![0u8; (t.lines * self.layout.line_bytes) as usize];
544 span[..rows.len()].copy_from_slice(&rows);
545 if self.layout.check {
546 let body = span.len() - CHECK_BYTES as usize;
547 let word = crc32c(&span[..body]);
548 span[body..].copy_from_slice(&word.to_le_bytes());
549 }
550 Ok(span)
551 }
552
553 pub fn fill(&self, source: &mut dyn WeightSource) -> std::io::Result<Vec<Vec<u8>>> {
555 let lb = self.layout.line_bytes;
556 let mut channels: Vec<Vec<u8>> = self.channel_lines.iter().map(|&l| vec![0u8; (l * lb) as usize]).collect();
557 for t in &self.tiles {
558 let at = (t.line * lb) as usize;
559 let span = self.tile_bytes(t, source)?;
560 channels[t.channel as usize][at..at + span.len()].copy_from_slice(&span);
561 }
562 Ok(channels)
563 }
564
565 pub fn write_channels(&self, source: &mut dyn WeightSource, out: &mut [&mut dyn std::io::Write]) -> std::io::Result<()> {
568 if out.len() != self.channel_lines.len() {
569 return Err(std::io::Error::new(std::io::ErrorKind::InvalidInput, format!("{} writers for {} channels", out.len(), self.channel_lines.len())));
570 }
571 let mut next = vec![0u64; out.len()];
572 for t in &self.tiles {
573 let ch = t.channel as usize;
574 if t.line != next[ch] {
575 return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, format!("channel {ch}'s tile at line {} after line {}", t.line, next[ch])));
576 }
577 out[ch].write_all(&self.tile_bytes(t, source)?)?;
578 next[ch] += t.lines;
579 }
580 Ok(())
581 }
582
583 pub fn tile_table(&self) -> Vec<u8> {
587 let mut words = vec![1, self.layout.line_bytes, u64::from(self.layout.check), self.channel_lines.len() as u64];
588 words.extend(&self.channel_lines);
589 words.push(self.tiles.len() as u64);
590 for t in &self.tiles {
591 words.extend([u64::from(t.channel), t.line, t.lines]);
592 }
593 let mut out = b"LOGOSIMG".to_vec();
594 for w in words {
595 out.extend(w.to_le_bytes());
596 }
597 out
598 }
599
600 pub fn first_bad_tile(&self, channels: &[Vec<u8>]) -> Option<usize> {
603 if !self.layout.check {
604 return None;
605 }
606 let lb = self.layout.line_bytes as usize;
607 self.tiles.iter().position(|t| {
608 let at = t.line as usize * lb;
609 let span = &channels[t.channel as usize][at..at + t.lines as usize * lb];
610 let body = span.len() - CHECK_BYTES as usize;
611 crc32c(&span[..body]).to_le_bytes() != span[body..]
612 })
613 }
614}
615
616pub const HEADERS: &[&str] = &[
618 "qwen3.8-27b-iq4_xs",
619 "qwen3.8-27b-q3_k_m",
620 "qwen3.8-27b-q4_0",
621 "qwen3.8-27b-q4_k_m",
622 "qwen3.8-27b-q5_k_m",
623 "qwen3.8-27b-q6_k",
624 "qwen3.8-27b-q8_0",
625];
626
627#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
630pub struct ImageRow {
631 pub header: &'static str,
632 pub beat: Beat,
633 pub layout: ImageLayout,
634 pub tensors: usize,
635 pub tiles: usize,
636 pub data_bytes: u64,
637 pub padding_bytes: u64,
638 pub check_bytes: u64,
639 pub channel_lines: Vec<u64>,
640 pub spread_lines: u64,
641 pub largest_tile_lines: u64,
642}
643
644#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
645pub struct ImageLedger {
646 pub rows: Vec<ImageRow>,
647}
648
649impl Image {
650 pub fn row(&self, header: &'static str, beat: Beat) -> ImageRow {
652 let data_bytes: u64 = self.tiles.iter().map(|t| (t.end_row - t.first_row) * self.tensors[t.tensor].row_bytes).sum();
653 let check_bytes = if self.layout.check { CHECK_BYTES * self.tiles.len() as u64 } else { 0 };
654 let total: u64 = self.channel_bytes().iter().sum();
655 let (most, least) = (self.channel_lines.iter().max(), self.channel_lines.iter().min());
656 ImageRow {
657 header,
658 beat,
659 layout: self.layout,
660 tensors: self.tensors.len(),
661 tiles: self.tiles.len(),
662 data_bytes,
663 padding_bytes: total - data_bytes - check_bytes,
664 check_bytes,
665 channel_lines: self.channel_lines.clone(),
666 spread_lines: most.zip(least).map_or(0, |(m, l)| m - l),
667 largest_tile_lines: self.tiles.iter().map(|t| t.lines).max().unwrap_or(0),
668 }
669 }
670}
671
672pub fn image_ledger(decode_dir: &Path) -> Result<ImageLedger, String> {
674 let mut rows = Vec::new();
675 for &header in HEADERS {
676 let h = GgufHeader::read_ledger(&decode_dir.join(format!("headers/{header}.json")))?;
677 let machine = machine_of(&h).map_err(|e| format!("{header}: {e}"))?;
678 for beat in [Beat::Data64, Beat::Full72] {
679 let image = image_of(&machine, &ImageLayout::d5005(beat)).map_err(|e| format!("{header} {beat:?}: {e:?}"))?;
680 rows.push(image.row(header, beat));
681 }
682 }
683 Ok(ImageLedger { rows })
684}
685
686pub fn crc32c(bytes: &[u8]) -> u32 {
688 const TABLE: [u32; 256] = {
689 let mut t = [0u32; 256];
690 let mut i = 0;
691 while i < 256 {
692 let mut c = i as u32;
693 let mut k = 0;
694 while k < 8 {
695 c = if c & 1 != 0 { 0x82F6_3B78 ^ (c >> 1) } else { c >> 1 };
696 k += 1;
697 }
698 t[i] = c;
699 i += 1;
700 }
701 t
702 };
703 !bytes.iter().fold(!0u32, |c, &b| TABLE[((c ^ b as u32) & 0xFF) as usize] ^ (c >> 8))
704}