#[derive(Default)]
pub(crate) struct SseTail {
pending: usize,
line_has_bytes: bool,
after_cr: bool,
bom_prefix: usize,
prefix_done: bool,
}
impl SseTail {
pub(crate) fn feed(&mut self, bytes: &[u8]) {
const BOM: [u8; 3] = [0xef, 0xbb, 0xbf];
for &byte in bytes {
if !self.prefix_done {
if BOM.get(self.bom_prefix) == Some(&byte) {
self.bom_prefix += 1;
if self.bom_prefix == BOM.len() {
self.prefix_done = true;
self.bom_prefix = 0;
}
continue;
}
self.prefix_done = true;
for &prefix in BOM.iter().take(self.bom_prefix) {
self.byte(prefix);
}
self.bom_prefix = 0;
}
self.byte(byte);
}
}
fn byte(&mut self, byte: u8) {
if self.after_cr && byte == b'\n' {
self.after_cr = false;
if self.pending != 0 {
self.pending = self.pending.saturating_add(1);
}
return;
}
self.after_cr = false;
self.pending = self.pending.saturating_add(1);
if byte == b'\r' || byte == b'\n' {
if !self.line_has_bytes {
self.pending = 0;
}
self.line_has_bytes = false;
self.after_cr = byte == b'\r';
} else {
self.line_has_bytes = true;
}
}
pub(crate) fn pending(&self) -> usize {
self.pending.saturating_add(self.bom_prefix)
}
}
#[cfg(test)]
mod tests;