pub mod checksummed;
pub mod delimiter;
pub mod length;
mod search;
pub mod varint_prefixed;
pub use checksummed::{ChecksumScope, Checksummed};
pub use delimiter::Delimited;
pub use length::{Endian, LengthPrefixed, LengthWidth};
pub use varint_prefixed::VarintPrefixed;
use crate::buf::WriteBuf;
use crate::error::Result;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Frame<'a> {
payload: &'a [u8],
consumed: usize,
}
impl<'a> Frame<'a> {
#[inline]
#[must_use]
pub const fn new(payload: &'a [u8], consumed: usize) -> Self {
debug_assert!(
consumed >= payload.len(),
"Frame::consumed must cover the payload"
);
Self { payload, consumed }
}
#[inline]
#[must_use]
pub const fn payload(&self) -> &'a [u8] {
self.payload
}
#[inline]
#[must_use]
pub const fn consumed(&self) -> usize {
self.consumed
}
}
pub trait Framer {
fn next_frame<'a>(&self, input: &'a [u8]) -> Result<Option<Frame<'a>>>;
fn write_frame(&self, payload: &[u8], out: &mut WriteBuf<'_>) -> Result<()>;
#[inline]
fn next_frame_from<'a>(
&self,
input: &'a [u8],
scanned: &mut usize,
) -> Result<Option<Frame<'a>>> {
let result = self.next_frame(input);
if let Ok(Some(_)) = result {
*scanned = 0;
}
result
}
#[inline]
fn max_frame_len(&self, payload_len: usize) -> Option<usize> {
let _ = payload_len;
None
}
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)]
pub struct StreamDecoder<F> {
framer: F,
scanned: usize,
}
impl<F: Framer> StreamDecoder<F> {
#[inline]
#[must_use]
pub const fn new(framer: F) -> Self {
Self { framer, scanned: 0 }
}
#[inline]
pub fn decode<'a>(&mut self, input: &'a [u8]) -> Result<Option<Frame<'a>>> {
let result = self.framer.next_frame_from(input, &mut self.scanned);
if result.is_err() {
self.scanned = 0;
}
result
}
#[inline]
pub fn reset(&mut self) {
self.scanned = 0;
}
#[inline]
#[must_use]
pub const fn framer(&self) -> &F {
&self.framer
}
#[inline]
#[must_use]
pub fn into_inner(self) -> F {
self.framer
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::error::Error;
struct FixedFour;
impl Framer for FixedFour {
fn next_frame<'a>(&self, input: &'a [u8]) -> Result<Option<Frame<'a>>> {
Ok(input.get(..4).map(|p| Frame::new(p, 4)))
}
fn write_frame(&self, payload: &[u8], out: &mut WriteBuf<'_>) -> Result<()> {
if payload.len() != 4 {
return Err(Error::InvalidEncoding);
}
out.write_bytes(payload)
}
}
#[test]
fn default_next_frame_from_resets_hint_on_frame() {
let mut scanned = 7;
assert_eq!(FixedFour.next_frame_from(b"ab", &mut scanned), Ok(None));
assert_eq!(scanned, 7, "hint is left alone when no frame is produced");
let frame = FixedFour
.next_frame_from(b"abcdef", &mut scanned)
.unwrap()
.unwrap();
assert_eq!(frame.payload(), b"abcd");
assert_eq!(scanned, 0);
}
#[test]
fn default_max_frame_len_is_unknown() {
assert_eq!(FixedFour.max_frame_len(4), None);
let mut out = [0u8; 4];
let mut buf = WriteBuf::new(&mut out);
FixedFour.write_frame(b"wxyz", &mut buf).unwrap();
assert_eq!(
FixedFour.write_frame(b"w", &mut buf),
Err(Error::InvalidEncoding)
);
}
#[test]
fn stream_decoder_clears_progress_on_error() {
let framer = Delimited::new(b"\n").unwrap().with_max_payload(8);
let mut decoder = StreamDecoder::new(framer);
assert_eq!(decoder.decode(b"aaaaaaa").unwrap(), None);
assert_eq!(decoder.scanned, 7);
assert!(decoder.decode(b"aaaaaaaaaaaa").is_err());
assert_eq!(decoder.scanned, 0);
let frame = decoder.decode(b"hi\nthere\n").unwrap().unwrap();
assert_eq!(frame.payload(), b"hi");
}
#[test]
fn stream_decoder_accessors_and_reset() {
let mut decoder = StreamDecoder::new(Delimited::new(b"\n").unwrap());
assert_eq!(decoder.decode(b"abc").unwrap(), None);
assert_eq!(decoder.scanned, 3);
decoder.reset();
assert_eq!(decoder.scanned, 0);
assert_eq!(decoder.framer().delimiter(), b"\n");
let framer = decoder.into_inner();
assert_eq!(framer.delimiter(), b"\n");
}
}