forked from jstrong/const-crc32
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
124 lines
3.5 KiB
124 lines
3.5 KiB
//! A `const fn` crc32 checksum implementation. |
|
//! |
|
//! # Examples |
|
//! |
|
//! ``` |
|
//! const BYTES: &[u8] = "The quick brown fox jumps over the lazy dog".as_bytes(); |
|
//! const CKSUM: u32 = const_crc32::crc32(BYTES); |
|
//! assert_eq!(CKSUM, 0x414fa339_u32); |
|
//! ``` |
|
|
|
/// used to generate up a [u32; 256] lookup table in `crc32`. this computes |
|
/// the table on demand for a given "index" `i` |
|
const fn table_fn(i: u32) -> u32 { |
|
let mut out = i; |
|
|
|
out = if out & 1 == 1 { 0xedb88320 ^ (out >> 1) } else { out >> 1 }; |
|
out = if out & 1 == 1 { 0xedb88320 ^ (out >> 1) } else { out >> 1 }; |
|
out = if out & 1 == 1 { 0xedb88320 ^ (out >> 1) } else { out >> 1 }; |
|
out = if out & 1 == 1 { 0xedb88320 ^ (out >> 1) } else { out >> 1 }; |
|
out = if out & 1 == 1 { 0xedb88320 ^ (out >> 1) } else { out >> 1 }; |
|
out = if out & 1 == 1 { 0xedb88320 ^ (out >> 1) } else { out >> 1 }; |
|
out = if out & 1 == 1 { 0xedb88320 ^ (out >> 1) } else { out >> 1 }; |
|
out = if out & 1 == 1 { 0xedb88320 ^ (out >> 1) } else { out >> 1 }; |
|
|
|
out |
|
} |
|
|
|
const fn get_table() -> [u32; 256] { |
|
let mut table: [u32; 256] = [0u32; 256]; |
|
let mut i = 0; |
|
|
|
while i < 256 { |
|
table[i] = table_fn(i as u32); |
|
i += 1; |
|
} |
|
|
|
table |
|
} |
|
|
|
const TABLE: [u32; 256] = get_table(); |
|
|
|
/// A `const fn` crc32 checksum implementation. |
|
/// |
|
/// Note: this is a naive implementation that should be expected to have poor performance |
|
/// if used on dynamic data at runtime. Usage should generally be restricted to declaring |
|
/// `const` variables based on `static` or `const` data available at build time. |
|
pub const fn crc32(buf: &[u8]) -> u32 { |
|
crc32_seed(buf, 0) |
|
} |
|
|
|
#[inline] |
|
pub const fn crc32_seed(buf: &[u8], seed: u32) -> u32 { |
|
let mut out = !seed; |
|
let mut i = 0usize; |
|
while i < buf.len() { |
|
out = (out >> 8) ^ TABLE[((out & 0xff) ^ (buf[i] as u32)) as usize]; |
|
i += 1; |
|
} |
|
!out |
|
} |
|
|
|
#[cfg(test)] |
|
mod tests { |
|
use super::*; |
|
use rand::prelude::*; |
|
|
|
fn crc32_compute_table() -> [u32; 256] { |
|
let mut crc32_table = [0; 256]; |
|
|
|
for n in 0..256 { |
|
crc32_table[n as usize] = (0..8).fold(n as u32, |acc, _| { |
|
match acc & 1 { |
|
1 => 0xedb88320 ^ (acc >> 1), |
|
_ => acc >> 1, |
|
} |
|
}); |
|
} |
|
|
|
crc32_table |
|
} |
|
|
|
#[test] |
|
fn check_table_fn_against_example_code() { |
|
let table = crc32_compute_table(); |
|
for i in 0..256{ |
|
assert_eq!(table[i], table_fn(i as u32)); |
|
} |
|
} |
|
|
|
#[test] |
|
fn simple_test() { |
|
const BYTES: &[u8] = "The quick brown fox jumps over the lazy dog".as_bytes(); |
|
assert_eq!(crc32(BYTES), 0x414fa339_u32); |
|
assert_eq!(crc32(BYTES), crc32fast::hash(BYTES)); |
|
} |
|
|
|
#[test] |
|
fn check_random_inputs_against_crc32_fast() { |
|
const N_ITER: usize = 100; |
|
const BUFSIZE: usize = 4096; |
|
|
|
let mut buf = [0u8; BUFSIZE]; |
|
let mut rng = thread_rng(); |
|
|
|
for _ in 0..N_ITER { |
|
rng.fill(&mut buf[..]); |
|
assert_eq!(crc32(&buf[..]), crc32fast::hash(&buf[..])); |
|
} |
|
} |
|
|
|
#[test] |
|
fn check_const_eval_limit_not_reached_on_100k_data() { |
|
const BYTES: &[u8] = &[42u8; 1024 * 100]; |
|
const CKSUM: u32 = crc32(BYTES); |
|
assert_eq!(CKSUM, crc32fast::hash(&BYTES[..])); |
|
} |
|
|
|
// #[test] |
|
// fn check_const_eval_limit_not_reached_on_1mb_data() { |
|
// const BYTES: &[u8] = &[42u8; 1024 * 1024]; |
|
// const CKSUM: u32 = crc32(BYTES); |
|
// assert_eq!(CKSUM, crc32fast::hash(&BYTES[..])); |
|
// } |
|
}
|
|
|