gba_compression/
lib.rs

1#![allow(unused)]
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
4#[repr(u8)]
5pub enum BitUnPackUElemSize {
6  _1 = 1,
7  _2 = 2,
8  _4 = 4,
9  _8 = 8,
10  _16 = 16,
11  _32 = 32,
12}
13impl BitUnPackUElemSize {
14  pub const fn elements_per_u32(self) -> usize {
15    32 >> (self as u32).trailing_zeros()
16  }
17}
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
20#[repr(u8)]
21pub enum BitUnPackPElemSize {
22  _1 = 1,
23  _2 = 2,
24  _4 = 4,
25  _8 = 8,
26}
27impl BitUnPackPElemSize {
28  pub const fn elements_per_u8(self) -> usize {
29    8 >> (self as u32).trailing_zeros()
30  }
31}
32
33pub const fn u32_count_to_u8_count(
34  u32_count: usize, u_elem_size: BitUnPackUElemSize,
35  p_elem_size: BitUnPackPElemSize,
36) -> BitUnpackResult<usize> {
37  let elements_per_u32 = u_elem_size.elements_per_u32();
38  let elements_per_u8 = p_elem_size.elements_per_u8();
39  let element_count = u32_count * elements_per_u32;
40  if element_count % elements_per_u8 != 0 {
41    Err(BitUnPackError::PackedElemCountSlop)
42  } else {
43    Ok(element_count / elements_per_u8)
44  }
45}
46
47pub const fn u8_count_to_u32_count(
48  u8_count: usize, p_elem_size: BitUnPackPElemSize,
49  u_elem_size: BitUnPackUElemSize,
50) -> BitUnpackResult<usize> {
51  let elements_per_u32 = u_elem_size.elements_per_u32();
52  let elements_per_u8 = p_elem_size.elements_per_u8();
53  let element_count = u8_count * elements_per_u8;
54  if element_count % elements_per_u32 != 0 {
55    Err(BitUnPackError::UnpackedElemCountSlop)
56  } else {
57    Ok(element_count / elements_per_u32)
58  }
59}
60
61/// Errors to do with `BitUnPack` related functions.
62#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
63pub enum BitUnPackError {
64  PackedElemCountSlop,
65  UnpackedElemCountSlop,
66}
67pub type BitUnpackResult<T> = Result<T, BitUnPackError>;
68
69/// Assumes that any offsets have been pre-applied to the `u32` data.
70pub fn pack_u32_to_u8(
71  u32_data: &[u32], unpack_z: BitUnPackUElemSize, pack_z: BitUnPackPElemSize,
72) -> BitUnpackResult<Vec<u8>> {
73  let req_capacity = u32_count_to_u8_count(u32_data.len(), unpack_z, pack_z)?;
74  let mut out_buffer = Vec::with_capacity(req_capacity);
75  //
76  let u_mask: u32 = ((1_u64 << (unpack_z as u32)) - 1) as u32;
77  let mut p_buffer: u8 = 0;
78  let mut p_bits: u32 = 0;
79  for mut u in u32_data.iter().copied() {
80    let mut u_bits = 32;
81    while u_bits > 0 {
82      let temp: u8 = (u & u_mask) as u8;
83      u_bits -= (unpack_z as u32);
84      u = u.wrapping_shl(unpack_z as u32);
85      //
86      p_buffer |= (temp << p_bits);
87      p_bits += pack_z as u32;
88      if p_bits == 8 {
89        out_buffer.push(p_buffer);
90        p_buffer = 0;
91        p_bits = 0;
92      }
93    }
94  }
95  debug_assert_eq!(p_buffer, 0);
96  debug_assert_eq!(p_bits, 0);
97  //
98  Ok(out_buffer)
99}