///| CRC32 implementation for gzip

///|
let crc32_poly : UInt = (Int::reinterpret_as_uint(237) << 24) |
  (Int::reinterpret_as_uint(184) << 16) |
  (Int::reinterpret_as_uint(131) << 8) |
  Int::reinterpret_as_uint(32)

///|
fn build_crc32_table() -> FixedArray[UInt] {
  FixedArray::makei(256, fn(i) {
    let mut c = i.reinterpret_as_uint()
    for _ in 0..<8 {
      if (c & Int::reinterpret_as_uint(1)) == Int::reinterpret_as_uint(1) {
        c = (c >> 1) ^ crc32_poly
      } else {
        c = c >> 1
      }
    }
    c
  })
}

///|
let crc32_table : FixedArray[UInt] = build_crc32_table()

///|
pub fn crc32(data : Bytes) -> UInt {
  let mut crc : UInt = Int::reinterpret_as_uint(-1)
  for b in data {
    let idx = UInt::reinterpret_as_int(
      (crc ^ Int::reinterpret_as_uint(b.to_int())) &
      Int::reinterpret_as_uint(255),
    )
    crc = (crc >> 8) ^ crc32_table[idx]
  }
  crc ^ Int::reinterpret_as_uint(-1)
}

///|
pub fn crc32_fixed(data : FixedArray[Byte]) -> UInt {
  crc32(Bytes::from_array(data))
}