#![allow(clippy::uninit_assumed_init)]
extern crate rustc_version;
use rustc_version::{version_meta, Channel};
use std::path::Path;
use std::{io, mem, ops};
pub const POLYNOMIAL: u32 = 0x82_F6_3B_78;
fn sw_table() -> [[u32; 256]; 8] {
let mut table: [[u32; 256]; 8] = unsafe { mem::MaybeUninit::uninit().assume_init() };
for n in 0..256 {
let mut crc = n;
for _ in 0..8 {
if crc % 2 == 0 {
crc /= 2;
} else {
crc /= 2;
crc ^= POLYNOMIAL;
}
}
table[0][n as usize] = crc;
}
for n in 0..256 {
let mut crc = table[0][n as usize];
for k in 1..8 {
crc = table[0][(crc as u8) as usize] ^ (crc >> 8);
table[k as usize][n as usize] = crc;
}
}
table
}
#[derive(Debug, Copy, Clone)]
pub struct Matrix([u32; 32]);
impl Matrix {
fn new() -> Self {
unsafe { mem::MaybeUninit::uninit().assume_init() }
}
fn square(self) -> Self {
let mut result = Self::new();
for i in 0..32 {
result[i] = self * self[i];
}
result
}
}
impl ops::Index<u8> for Matrix {
type Output = u32;
#[inline]
fn index(&self, i: u8) -> &Self::Output {
&self.0[i as usize]
}
}
impl ops::IndexMut<u8> for Matrix {
#[inline]
fn index_mut(&mut self, i: u8) -> &mut Self::Output {
&mut self.0[i as usize]
}
}
impl ops::Mul<u32> for Matrix {
type Output = u32;
fn mul(self, mut vec: u32) -> Self::Output {
let mut sum = 0;
let mut i = 0;
while vec != 0 {
if vec % 2 != 0 {
sum ^= self[i];
}
vec /= 2;
i += 1;
}
sum
}
}
fn create_zero_operator(mut len: usize) -> Matrix {
let mut odd = Matrix::new();
odd[0] = POLYNOMIAL;
for i in 1..32 {
odd[i] = 1 << (i - 1);
}
let mut even = odd.square();
let mut odd = even.square();
loop {
even = odd.square();
len /= 2;
if len == 0 {
return even;
}
odd = even.square();
len /= 2;
if len == 0 {
return odd;
}
}
}
fn hw_table(len: usize) -> [[u32; 256]; 4] {
let mut zeroes: [[u32; 256]; 4] = unsafe { mem::MaybeUninit::uninit().assume_init() };
let op = create_zero_operator(len);
for n in 0..256 {
for i in 0..4 {
let shift = i * 8;
zeroes[i as usize][n] = op * ((n << shift) as u32);
}
}
zeroes
}
pub const LONG: usize = 8192;
pub const SHORT: usize = 256;
fn write_table(table: &[[u32; 256]], path: &Path) -> io::Result<()> {
use std::fs;
let mut file = {
let file = fs::File::create(path)?;
io::BufWriter::new(file)
};
use std::io::Write;
write!(file, "[")?;
for row in table.iter() {
write!(file, "[")?;
for element in row.iter() {
write!(file, "{}, ", element)?;
}
write!(file, "],")?;
}
write!(file, "]")?;
Ok(())
}
fn write_tables() -> io::Result<()> {
let out_dir = std::env::var("OUT_DIR").unwrap();
let out_dir = std::path::Path::new(&out_dir);
write_table(&sw_table(), &out_dir.join("sw.table"))?;
write_table(&hw_table(LONG), &out_dir.join("hw.long.table"))?;
write_table(&hw_table(SHORT), &out_dir.join("hw.short.table"))
}
fn main() {
write_tables().expect("Failed to write CRC tables");
if let Channel::Nightly = version_meta().unwrap().channel {
println!("cargo:rustc-cfg=nightly");
}
}