Compare commits

...

9 Commits

  1. 2
      Cargo.toml
  2. 7
      README.md
  3. 80
      src/lib.rs

2
Cargo.toml

@ -1,6 +1,6 @@
[package]
name = "const-crc32"
version = "1.1.0"
version = "1.3.0"
edition = "2021"
authors = ["Jonathan Strong <jstrong@shipyard.rs>"]
license = "MIT"

7
README.md

@ -18,7 +18,10 @@ if used on dynamic data at runtime. Usage should generally be restricted to decl
## `#[const_eval_limit]`
This crate sets `#[const_eval_limit]` to 1,000,000,000 to avoid hitting the limit when
executing the `const fn`, which requires `#![feature(const_eval_limit)]`.
You may need to increase the crate-wide `const_eval_limit` setting to use `const_crc32` for larger byte slices.
Increating `const_eval_limit` requires the nightly-only `#![feature(const_eval_limit)]`.
Previously, this crate set the limit itself, however, as of the 2022-10-30 nightly, the value set in `const_crc32` does not increase the limit for crates which use the library.
Compile time for `const` data around 100k is less than 1s.

80
src/lib.rs

@ -8,12 +8,9 @@
//! assert_eq!(CKSUM, 0x414fa339_u32);
//! ```
#![feature(const_eval_limit)]
#![const_eval_limit = "1000000000"]
/// used to generate up a [u32; 256] lookup table in `crc32`. this computes
/// the table on demand for a given "index" `i`
#[rustfmt::skip]
const fn table_fn(i: u32) -> u32 {
let mut out = i;
@ -49,7 +46,46 @@ const TABLE: [u32; 256] = get_table();
/// 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 {
let mut out = !0u32;
crc32_seed(buf, 0)
}
/// Calculate crc32 checksum, using provided `seed` as the initial state, instead of the
/// default initial state of `0u32`.
///
/// # Examples
///
/// Calculating the checksum from several parts of a larger input:
///
/// ```
/// const BYTES: &[u8] = "The quick brown fox jumps over the lazy dog".as_bytes();
///
/// let mut cksum = 0u32;
///
/// cksum = const_crc32::crc32_seed(&BYTES[0..10], cksum);
/// cksum = const_crc32::crc32_seed(&BYTES[10..15], cksum);
/// cksum = const_crc32::crc32_seed(&BYTES[15..], cksum);
///
/// assert_eq!(cksum, const_crc32::crc32(BYTES));
/// ```
///
/// Using separate seeds for different kinds of data, to produce different checksums depending
/// on what kind of data the bytes represent:
///
/// ```
/// const THING_ONE_SEED: u32 = 0xbaaaaaad_u32;
/// const THING_TWO_SEED: u32 = 0x2bad2bad_u32;
///
/// let thing_one_bytes = "bump! thump!".as_bytes();
/// let thing_two_bytes = "thump! bump!".as_bytes();
///
/// let thing_one_cksum = const_crc32::crc32_seed(thing_one_bytes, THING_ONE_SEED);
/// let thing_two_cksum = const_crc32::crc32_seed(thing_two_bytes, THING_TWO_SEED);
///
/// assert_ne!(thing_one_cksum, thing_two_cksum);
/// ```
#[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];
@ -66,12 +102,10 @@ mod tests {
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,
}
for n in 0..256_u32 {
crc32_table[n as usize] = (0..8).fold(n, |acc, _| match acc & 1 {
1 => 0xedb88320 ^ (acc >> 1),
_ => acc >> 1,
});
}
@ -81,7 +115,7 @@ mod tests {
#[test]
fn check_table_fn_against_example_code() {
let table = crc32_compute_table();
for i in 0..256{
for i in 0..256 {
assert_eq!(table[i], table_fn(i as u32));
}
}
@ -93,6 +127,28 @@ mod tests {
assert_eq!(crc32(BYTES), crc32fast::hash(BYTES));
}
#[test]
fn use_seed_to_checksum_from_partial_inputs() {
const BYTES: &[u8] = "The quick brown fox jumps over the lazy dog".as_bytes();
let mut cksum = crc32(&BYTES[0..10]);
cksum = crc32_seed(&BYTES[10..], cksum);
assert_eq!(cksum, crc32(BYTES));
}
#[test]
fn use_seed_to_checksum_from_many_chunks() {
let mut buf = [0u8; 1024];
let mut rng = thread_rng();
rng.fill(&mut buf[..]);
let mut cksum = 0;
for chunk in buf[..].chunks(7) {
cksum = crc32_seed(chunk, cksum);
}
assert_eq!(cksum, crc32(&buf[..]));
}
#[test]
fn check_random_inputs_against_crc32_fast() {
const N_ITER: usize = 100;

Loading…
Cancel
Save