use super::gf;
use super::version::{BYTE_MODE, Plan};
const PAD_FIRST: u8 = 0b1110_1100;
const PAD_SECOND: u8 = 0b0001_0001;
pub(super) fn stream(payload: &[u8], plan: Plan) -> Vec<bool> {
let blocks = split(&codewords(payload, plan), plan);
let checks: Vec<Vec<u8>> = blocks.iter().map(|b| gf::check(b, plan.check)).collect();
interleave(&blocks)
.into_iter()
.chain(interleave(&checks))
.flat_map(|byte| (0..8).rev().map(move |at| byte >> at & 1 == 1))
.collect()
}
fn codewords(payload: &[u8], plan: Plan) -> Vec<u8> {
let mut bits = Bits::new();
bits.push(BYTE_MODE, 4);
bits.push(
u32::try_from(payload.len()).unwrap_or(u32::MAX),
plan.count_bits(),
);
for &byte in payload {
bits.push(u32::from(byte), 8);
}
let room = plan.data * 8;
bits.push(0, 4.min(room.saturating_sub(bits.len)));
bits.pad_to_byte();
let mut out = bits.bytes;
out.truncate(plan.data);
let mut pad = [PAD_FIRST, PAD_SECOND].into_iter().cycle();
while out.len() < plan.data {
out.push(pad.next().unwrap_or(PAD_FIRST));
}
out
}
fn split(data: &[u8], plan: Plan) -> Vec<Vec<u8>> {
let mut rest = data;
plan.block_lengths()
.into_iter()
.map(|len| {
let (block, tail) = rest.split_at(len.min(rest.len()));
rest = tail;
block.to_vec()
})
.collect()
}
fn interleave(blocks: &[Vec<u8>]) -> Vec<u8> {
let longest = blocks.iter().map(Vec::len).max().unwrap_or(0);
(0..longest)
.flat_map(|at| {
blocks
.iter()
.filter_map(move |block| block.get(at).copied())
})
.collect()
}
struct Bits {
bytes: Vec<u8>,
len: usize,
}
impl Bits {
fn new() -> Self {
Self {
bytes: Vec::new(),
len: 0,
}
}
fn push(&mut self, value: u32, width: usize) {
for at in (0..width).rev() {
if self.len.is_multiple_of(8) {
self.bytes.push(0);
}
let set = u8::from(value >> at & 1 == 1) << (7 - self.len % 8);
if let Some(byte) = self.bytes.last_mut() {
*byte |= set;
}
self.len += 1;
}
}
fn pad_to_byte(&mut self) {
self.push(0, (8 - self.len % 8) % 8);
}
}