1use std::sync::OnceLock;
17
18pub fn crc8(data: &[u8]) -> u8 {
20 static TABLE: OnceLock<[u8; 256]> = OnceLock::new();
21 let table = TABLE.get_or_init(|| {
22 let mut table = [0u8; 256];
23 for (index, entry) in table.iter_mut().enumerate() {
24 let mut value = index as u8;
25 for _ in 0..8 {
26 value = if value & 0x80 != 0 {
27 (value << 1) ^ 0x07
28 } else {
29 value << 1
30 };
31 }
32 *entry = value;
33 }
34 table
35 });
36
37 data.iter()
38 .fold(0u8, |crc, &byte| table[(crc ^ byte) as usize])
39}
40
41pub fn crc16(data: &[u8]) -> u16 {
43 static TABLE: OnceLock<[u16; 256]> = OnceLock::new();
44 let table = TABLE.get_or_init(|| {
45 let mut table = [0u16; 256];
46 for (index, entry) in table.iter_mut().enumerate() {
47 let mut value = (index as u16) << 8;
48 for _ in 0..8 {
49 value = if value & 0x8000 != 0 {
50 (value << 1) ^ 0x8005
51 } else {
52 value << 1
53 };
54 }
55 *entry = value;
56 }
57 table
58 });
59
60 data.iter().fold(0u16, |crc, &byte| {
61 (crc << 8) ^ table[((crc >> 8) as u8 ^ byte) as usize]
62 })
63}
64
65pub fn crc32_ogg(data: &[u8]) -> u32 {
69 crc32_ogg_bytes(data.iter().copied())
70}
71
72pub(crate) fn crc32_ogg_page(page: &[u8]) -> u32 {
74 crc32_ogg_bytes(page.iter().enumerate().map(
75 |(index, &byte)| {
76 if (22..26).contains(&index) { 0 } else { byte }
77 },
78 ))
79}
80
81fn crc32_ogg_bytes(data: impl Iterator<Item = u8>) -> u32 {
82 static TABLE: OnceLock<[u32; 256]> = OnceLock::new();
83 let table = TABLE.get_or_init(|| {
84 let mut table = [0u32; 256];
85 for (index, entry) in table.iter_mut().enumerate() {
86 let mut value = (index as u32) << 24;
87 for _ in 0..8 {
88 value = if value & 0x8000_0000 != 0 {
89 (value << 1) ^ 0x04C1_1DB7
90 } else {
91 value << 1
92 };
93 }
94 *entry = value;
95 }
96 table
97 });
98
99 data.fold(0u32, |crc, byte| {
100 (crc << 8) ^ table[((crc >> 24) as u8 ^ byte) as usize]
101 })
102}
103
104#[cfg(test)]
105#[path = "crc_tests.rs"]
106mod tests;