mod alphanumeric;
mod auto;
mod byte;
mod eci;
mod encode;
mod fnc1;
mod kanji;
mod mode_indicator;
mod numeric;
mod terminator;
use alloc::vec::Vec;
use self::terminator::DATA_LENGTHS;
pub use self::{
auto::{RectMicroStrategy, encode_auto, encode_auto_micro, encode_auto_rect_micro},
mode_indicator::ExtendedMode,
};
use crate::{
cast::{As, Truncate},
error::{Error, Result},
types::{EcLevel, Version},
};
#[derive(Debug)]
pub struct Bits {
data: Vec<u8>,
bit_offset: usize,
version: Version,
}
impl Bits {
#[must_use]
pub const fn new(version: Version) -> Self {
Self {
data: Vec::new(),
bit_offset: 0,
version,
}
}
fn push_number(&mut self, n: usize, number: u16) {
debug_assert!(
n == 16 || n < 16 && number < (1 << n),
"{number} is too big as a {n}-bit number"
);
let b = self.bit_offset + n;
let last_index = self.data.len().wrapping_sub(1);
match (self.bit_offset, b) {
(0, 0..=8) => {
self.data.push((number << (8 - b)).truncate_as_u8());
}
(0, _) => {
self.data.push((number >> (b - 8)).truncate_as_u8());
self.data.push((number << (16 - b)).truncate_as_u8());
}
(_, 0..=8) => {
self.data[last_index] |= (number << (8 - b)).truncate_as_u8();
}
(_, 9..=16) => {
self.data[last_index] |= (number >> (b - 8)).truncate_as_u8();
self.data.push((number << (16 - b)).truncate_as_u8());
}
_ => {
self.data[last_index] |= (number >> (b - 8)).truncate_as_u8();
self.data.push((number >> (b - 16)).truncate_as_u8());
self.data.push((number << (24 - b)).truncate_as_u8());
}
}
self.bit_offset = b & 7;
}
pub fn push_number_checked(&mut self, n: usize, number: usize) -> Result<()> {
if n > 16 || number >= (1 << n) {
Err(Error::DataTooLong)
} else {
self.push_number(n, number.as_u16());
Ok(())
}
}
fn reserve(&mut self, n: usize) {
let extra_bytes = (n + (8 - self.bit_offset) % 8) / 8;
self.data.reserve(extra_bytes);
}
#[must_use]
pub fn into_bytes(self) -> Vec<u8> {
self.data
}
#[must_use]
pub const fn len(&self) -> usize {
if self.bit_offset == 0 {
self.data.len() * 8
} else {
(self.data.len() - 1) * 8 + self.bit_offset
}
}
#[must_use]
pub const fn is_empty(&self) -> bool {
self.data.is_empty()
}
pub fn max_len(&self, ec_level: EcLevel) -> Result<usize> {
self.version.fetch(ec_level, &DATA_LENGTHS)
}
#[must_use]
pub const fn version(&self) -> Version {
self.version
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_push_number() {
let mut bits = Bits::new(Version::Normal(1));
bits.push_number(3, 0b010);
bits.push_number(3, 0b110);
bits.push_number(3, 0b101);
bits.push_number(7, 0b001_1010);
bits.push_number(4, 0b1100);
bits.push_number(12, 0b1011_0110_1101);
bits.push_number(10, 0b01_1001_0001);
bits.push_number(15, 0b111_0010_1110_0011);
let bytes = bits.into_bytes();
assert_eq!(
bytes,
[
0b0101_1010,
0b1001_1010,
0b1100_1011,
0b0110_1101,
0b0110_0100,
0b0111_1001,
0b0111_0001,
0b1000_0000,
]
);
}
}