pub(crate) struct ByteSink<'a> {
dst: &'a mut [u8],
written: usize,
}
pub(crate) const DECODER_HEADROOM: usize = 4;
pub(crate) const ENCODER_HEADROOM: usize = 4;
impl<'a> ByteSink<'a> {
pub(crate) fn new(dst: &'a mut [u8]) -> Self {
ByteSink { dst, written: 0 }
}
pub(crate) fn written(&self) -> usize {
self.written
}
pub(crate) fn room(&self) -> usize {
self.dst.len() - self.written
}
pub(crate) fn has_room(&self, needed: usize) -> bool {
self.room() >= needed
}
pub(crate) fn write_char(&mut self, c: char) {
self.written += c.encode_utf8(&mut self.dst[self.written..]).len();
}
pub(crate) fn write_code_point(&mut self, code_point: u32) {
self.write_char(char::from_u32(code_point).unwrap_or(char::REPLACEMENT_CHARACTER));
}
pub(crate) fn write_byte(&mut self, byte: u8) {
self.dst[self.written] = byte;
self.written += 1;
}
pub(crate) fn write_slice(&mut self, bytes: &[u8]) {
self.dst[self.written..self.written + bytes.len()].copy_from_slice(bytes);
self.written += bytes.len();
}
pub(crate) fn write_slice_partial(&mut self, bytes: &[u8]) -> usize {
let n = core::cmp::min(bytes.len(), self.room());
self.write_slice(&bytes[..n]);
n
}
}
#[cfg(any(feature = "gb18030", feature = "iso-2022-jp"))]
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub(crate) struct Pushback {
buf: [u8; 2],
pos: u8,
len: u8,
}
#[cfg(any(feature = "gb18030", feature = "iso-2022-jp"))]
impl Pushback {
pub(crate) fn is_empty(&self) -> bool {
self.pos == self.len
}
pub(crate) fn set(&mut self, bytes: &[u8]) {
debug_assert!(self.is_empty() && bytes.len() <= self.buf.len());
self.buf[..bytes.len()].copy_from_slice(bytes);
self.pos = 0;
self.len = bytes.len() as u8;
}
pub(crate) fn next(&mut self) -> Option<u8> {
if self.is_empty() {
return None;
}
let byte = self.buf[self.pos as usize];
self.pos += 1;
Some(byte)
}
pub(crate) fn unread(&mut self) {
debug_assert!(self.pos > 0);
self.pos -= 1;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn sink_writes_utf8() {
let mut buf = [0u8; 8];
let mut sink = ByteSink::new(&mut buf);
sink.write_char('a');
sink.write_code_point(0x20AC);
assert_eq!(sink.written(), 4);
assert_eq!(&buf[..4], b"a\xE2\x82\xAC");
}
#[test]
fn partial_write_reports_what_fit() {
let mut buf = [0u8; 3];
let mut sink = ByteSink::new(&mut buf);
assert_eq!(sink.write_slice_partial(b"abcdef"), 3);
assert_eq!(sink.room(), 0);
}
#[cfg(any(feature = "gb18030", feature = "iso-2022-jp"))]
#[test]
fn pushback_is_fifo() {
let mut pb = Pushback::default();
assert!(pb.is_empty());
pb.set(&[0x30, 0x81]);
assert_eq!(pb.next(), Some(0x30));
assert_eq!(pb.next(), Some(0x81));
assert_eq!(pb.next(), None);
assert!(pb.is_empty());
}
}