use crate::encode::Terminator;
use crate::error::Error;
use crate::limits::{MAX_BODY, MAX_SEQUENCE, PREFIX};
use crate::model::Message;
use crate::parse::parse_body;
const ESC: u8 = 0x1b;
const BEL: u8 = 0x07;
const CAN: u8 = 0x18;
const SUB: u8 = 0x1a;
#[derive(Debug, PartialEq, Eq)]
pub enum Event<'a> {
Passthrough(&'a [u8]),
Sequence {
message: Result<Message<'a>, Error>,
terminator: Terminator,
},
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum St {
Ground,
Prefix(usize),
Body,
BodyEsc,
}
#[derive(Clone)]
pub struct Scanner {
body: [u8; MAX_BODY],
len: usize,
overflow: bool,
state: St,
}
impl Default for Scanner {
fn default() -> Self {
Self::new()
}
}
impl core::fmt::Debug for Scanner {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Scanner")
.field("state", &self.state)
.field("len", &self.len)
.finish()
}
}
impl Scanner {
pub const fn new() -> Self {
Scanner {
body: [0; MAX_BODY],
len: 0,
overflow: false,
state: St::Ground,
}
}
pub fn is_ground(&self) -> bool {
self.state == St::Ground
}
pub fn feed(&mut self, input: &[u8], mut on: impl FnMut(Event<'_>)) {
let mut ground_from = (self.state == St::Ground).then_some(0);
let mut i = 0;
while i < input.len() {
let b = input[i];
match self.state {
St::Ground => {
if b == ESC {
if let Some(from) = ground_from.take().filter(|&from| from < i) {
on(Event::Passthrough(&input[from..i]));
}
self.state = St::Prefix(1);
}
}
St::Prefix(k) => {
if b == PREFIX[k] {
if k + 1 == PREFIX.len() {
self.state = St::Body;
self.len = 0;
self.overflow = false;
} else {
self.state = St::Prefix(k + 1);
}
} else {
on(Event::Passthrough(&PREFIX[..k]));
self.state = St::Ground;
ground_from = Some(i);
continue;
}
}
St::Body => match b {
BEL => {
self.complete(Terminator::Bel, &mut on);
ground_from = Some(i + 1);
}
ESC => self.state = St::BodyEsc,
CAN | SUB => {
self.state = St::Ground;
ground_from = Some(i + 1);
}
0x00..=0x1f => {}
_ => {
if self.len < self.body.len() {
self.body[self.len] = b;
self.len += 1;
} else {
self.overflow = true;
}
}
},
St::BodyEsc => {
if b == b'\\' {
self.complete(Terminator::St, &mut on);
ground_from = Some(i + 1);
} else {
self.state = St::Prefix(1);
continue;
}
}
}
i += 1;
}
if let Some(from) = ground_from.filter(|&from| from < input.len()) {
if self.state == St::Ground {
on(Event::Passthrough(&input[from..]));
}
}
}
pub fn finish(&mut self, mut on: impl FnMut(Event<'_>)) {
if let St::Prefix(k) = self.state {
on(Event::Passthrough(&PREFIX[..k]));
}
self.state = St::Ground;
self.len = 0;
self.overflow = false;
}
fn complete(&mut self, terminator: Terminator, on: &mut impl FnMut(Event<'_>)) {
let total = PREFIX.len() + self.len + terminator.as_str().len();
let message = if self.overflow || total > MAX_SEQUENCE {
Err(Error::SequenceTooLong)
} else {
parse_body(&self.body[..self.len])
};
on(Event::Sequence {
message,
terminator,
});
self.state = St::Ground;
self.len = 0;
self.overflow = false;
}
}