use core::convert::Infallible;
use crate::{Error as ParserError, Event, Limit, MAX_SEQUENCE, parse_sequence};
const PREFIX: &[u8] = b"\x1b]7501;";
#[derive(Debug, thiserror::Error)]
#[error("event callback failed after {consumed} input bytes")]
pub struct Error<E> {
consumed: usize,
source: E,
}
impl<E> Error<E> {
#[must_use]
pub const fn consumed(&self) -> usize {
self.consumed
}
#[must_use]
pub const fn get_ref(&self) -> &E {
&self.source
}
#[must_use]
pub fn into_inner(self) -> E {
self.source
}
}
#[derive(Clone, Copy, Default)]
enum Phase {
#[default]
Ground,
Escape,
Prefix(u8),
Body,
BodyEscape,
Ignore,
IgnoreEscape,
}
pub struct Decoder {
buffer: [u8; MAX_SEQUENCE],
length: usize,
phase: Phase,
}
impl Default for Decoder {
fn default() -> Self {
Self::new()
}
}
impl Decoder {
#[must_use]
pub const fn new() -> Self {
Self {
buffer: [0; MAX_SEQUENCE],
length: 0,
phase: Phase::Ground,
}
}
pub fn reset(&mut self) {
self.length = 0;
self.phase = Phase::Ground;
}
pub fn feed(&mut self, input: &[u8], mut on_event: impl FnMut(Result<Event<'_>, ParserError>)) {
if let Err(failure) = self.try_feed(input, |event| {
on_event(event);
Ok::<(), Infallible>(())
}) {
match failure.source {}
}
}
pub fn try_feed<E>(
&mut self,
input: &[u8],
mut on_event: impl FnMut(Result<Event<'_>, ParserError>) -> Result<(), E>,
) -> Result<(), Error<E>> {
for (index, &byte) in input.iter().enumerate() {
let failure = |source| Error {
consumed: index + 1,
source,
};
match self.phase {
Phase::Ground => {
if byte == 0x1b {
self.phase = Phase::Escape;
}
}
Phase::Escape => match byte {
b']' => {
self.buffer[..2].copy_from_slice(&PREFIX[..2]);
self.length = 2;
self.phase = Phase::Prefix(2);
}
0x1b => {}
_ => self.phase = Phase::Ground,
},
Phase::Prefix(index) => {
if byte == PREFIX[usize::from(index)] {
self.buffer[self.length] = byte;
self.length += 1;
self.phase = if self.length == PREFIX.len() {
Phase::Body
} else {
Phase::Prefix(index + 1)
};
} else {
self.phase = skip(byte, false);
}
}
Phase::Body | Phase::BodyEscape => {
let escaped = matches!(self.phase, Phase::BodyEscape);
let terminated = byte == 0x07 || (escaped && byte == b'\\');
if self.length == MAX_SEQUENCE {
self.phase = if terminated {
Phase::Ground
} else {
skip(byte, escaped)
};
self.length = 0;
on_event(Err(ParserError::Limit(Limit::Sequence))).map_err(failure)?;
} else {
self.buffer[self.length] = byte;
self.length += 1;
if terminated {
let length = self.length;
self.reset();
match parse_sequence(&self.buffer[..length]) {
Ok(Some(event)) => on_event(Ok(event)).map_err(failure)?,
Err(error) => on_event(Err(error)).map_err(failure)?,
Ok(None) => {}
}
} else {
self.phase = if byte == 0x1b {
Phase::BodyEscape
} else {
Phase::Body
};
}
}
}
Phase::Ignore | Phase::IgnoreEscape => {
self.phase = skip(byte, matches!(self.phase, Phase::IgnoreEscape));
}
}
}
Ok(())
}
}
fn skip(byte: u8, escaped: bool) -> Phase {
if byte == 0x07 || (escaped && byte == b'\\') {
Phase::Ground
} else if byte == 0x1b {
Phase::IgnoreEscape
} else {
Phase::Ignore
}
}