use crate::{arch, math, radix::DigitCase};
use core::{convert::TryInto, fmt, str};
const BUFFER_LEN_MIN: usize = 32;
const BUFFER_LEN: usize = math::round_up_usize(BUFFER_LEN_MIN, arch::digits::DIGIT_CHUNK_LEN);
pub struct DigitWriter<'a> {
buffer: [u8; BUFFER_LEN],
buffer_len: usize,
digit_case: DigitCase,
writer: &'a mut dyn fmt::Write,
}
impl<'a> DigitWriter<'a> {
pub fn new(writer: &'a mut dyn fmt::Write, digit_case: DigitCase) -> DigitWriter {
DigitWriter {
buffer: [0; BUFFER_LEN],
buffer_len: 0,
digit_case,
writer,
}
}
pub fn write(&mut self, mut buf: &[u8]) -> fmt::Result {
while !buf.is_empty() {
let len = buf.len().min(BUFFER_LEN - self.buffer_len);
let (buf_chunk, buf_remainder) = buf.split_at(len);
buf = buf_remainder;
self.buffer[self.buffer_len..self.buffer_len + len].copy_from_slice(buf_chunk);
self.buffer_len += len;
if self.buffer_len == BUFFER_LEN {
self.flush()?;
}
}
Ok(())
}
pub fn flush(&mut self) -> fmt::Result {
let buffer_len_rounded = math::round_up(self.buffer_len, arch::digits::DIGIT_CHUNK_LEN);
self.buffer[self.buffer_len..buffer_len_rounded].fill(0);
for chunk in
self.buffer[..buffer_len_rounded].chunks_exact_mut(arch::digits::DIGIT_CHUNK_LEN)
{
arch::digits::digit_chunk_raw_to_ascii(chunk.try_into().unwrap(), self.digit_case);
}
let b = &self.buffer[..self.buffer_len];
let s = unsafe { str::from_utf8_unchecked(b) };
self.writer.write_str(s)?;
self.buffer_len = 0;
Ok(())
}
}