use crate::result::{DecoderResult, EncoderResult};
use crate::sink::{ByteSink, DECODER_HEADROOM, ENCODER_HEADROOM};
pub(crate) const UNMAPPED: u16 = 0xFFFF;
#[derive(Debug, Clone, Copy)]
pub(crate) struct FullByteDecoder {
table: &'static [u16; 256],
}
impl FullByteDecoder {
pub(crate) fn new(table: &'static [u16; 256]) -> Self {
FullByteDecoder { table }
}
pub(crate) fn decode(&mut self, src: &[u8], sink: &mut ByteSink) -> (DecoderResult, usize) {
let mut read = 0usize;
loop {
if !sink.has_room(DECODER_HEADROOM) {
return (DecoderResult::OutputFull, read);
}
let Some(byte) = src.get(read).copied() else {
return (DecoderResult::InputEmpty, read);
};
read += 1;
let code_point = self.table[usize::from(byte)];
if code_point == UNMAPPED {
return (DecoderResult::Malformed(1), read);
}
sink.write_code_point(u32::from(code_point));
}
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct FullByteEncoder {
code_points: &'static [u16],
bytes: &'static [u8],
}
impl FullByteEncoder {
pub(crate) fn new(code_points: &'static [u16], bytes: &'static [u8]) -> Self {
debug_assert_eq!(code_points.len(), bytes.len());
FullByteEncoder { code_points, bytes }
}
pub(crate) fn encode(&mut self, src: &str, sink: &mut ByteSink) -> (EncoderResult, usize) {
let mut read = 0usize;
loop {
if !sink.has_room(ENCODER_HEADROOM) {
return (EncoderResult::OutputFull, read);
}
let Some(c) = src[read..].chars().next() else {
return (EncoderResult::InputEmpty, read);
};
read += c.len_utf8();
let scalar = u32::from(c);
if scalar > 0xFFFF {
return (EncoderResult::Unmappable(c), read);
}
match self.code_points.binary_search(&(scalar as u16)) {
Ok(i) => sink.write_byte(self.bytes[i]),
Err(_) => return (EncoderResult::Unmappable(c), read),
}
}
}
}