#![forbid(unsafe_code)]
mod escape_ascii;
pub use escape_ascii::escape_ascii;
mod deframe_crlf;
pub use deframe_crlf::deframe_crlf;
mod deframe_line;
pub use deframe_line::deframe_line;
mod read_write_chain;
pub use read_write_chain::*;
mod read_write_take;
pub use read_write_take::*;
#[cfg(test)]
mod test_utils;
#[cfg(test)]
pub use test_utils::*;
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct NotEnoughSpaceError {}
impl From<NotEnoughSpaceError> for std::io::Error {
fn from(_: NotEnoughSpaceError) -> Self {
std::io::Error::new(
std::io::ErrorKind::InvalidData,
"not enough space in buffer",
)
}
}
impl From<NotEnoughSpaceError> for String {
fn from(_: NotEnoughSpaceError) -> Self {
"not enough space in buffer".to_string()
}
}
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct MalformedInputError(String);
impl MalformedInputError {
pub fn new(msg: String) -> Self {
Self(msg)
}
}
impl From<MalformedInputError> for std::io::Error {
fn from(e: MalformedInputError) -> Self {
std::io::Error::new(
std::io::ErrorKind::InvalidData,
format!("malformed input: {}", e.0),
)
}
}
impl From<MalformedInputError> for String {
fn from(e: MalformedInputError) -> Self {
format!("malformed input: {}", e.0)
}
}
#[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct FixedBuf<const SIZE: usize> {
mem: [u8; SIZE],
read_index: usize,
write_index: usize,
}
impl<const SIZE: usize> std::panic::UnwindSafe for FixedBuf<SIZE> {}
impl<const SIZE: usize> FixedBuf<SIZE> {
pub const fn new() -> Self {
Self {
mem: [0_u8; SIZE],
write_index: 0,
read_index: 0,
}
}
pub fn empty(mem: [u8; SIZE]) -> Self {
Self {
mem,
read_index: 0,
write_index: 0,
}
}
pub fn filled(mem: [u8; SIZE]) -> Self {
Self {
mem,
read_index: 0,
write_index: SIZE,
}
}
pub fn into_inner(self) -> [u8; SIZE] {
self.mem
}
pub fn len(&self) -> usize {
self.write_index - self.read_index
}
pub fn is_empty(&self) -> bool {
self.write_index == self.read_index
}
pub fn clear(&mut self) {
self.read_index = 0;
self.write_index = 0;
}
pub fn escape_ascii(&self) -> String {
escape_ascii(self.readable())
}
pub fn mem(&self) -> &[u8] {
self.mem.as_ref()
}
pub fn readable(&self) -> &[u8] {
&self.mem.as_ref()[self.read_index..self.write_index]
}
pub fn read_byte(&mut self) -> u8 {
self.read_bytes(1)[0]
}
pub fn try_read_byte(&mut self) -> Option<u8> {
if self.is_empty() {
None
} else {
Some(self.read_byte())
}
}
pub fn read_bytes(&mut self, num_bytes: usize) -> &[u8] {
let new_read_index = self.read_index + num_bytes;
assert!(new_read_index <= self.write_index, "read would underflow");
let old_read_index = self.read_index;
self.read_index = new_read_index;
if self.read_index == self.write_index {
self.write_index = 0;
self.read_index = 0;
}
&self.mem.as_ref()[old_read_index..new_read_index]
}
pub fn try_read_bytes(&mut self, num_bytes: usize) -> Option<&[u8]> {
if self.len() < num_bytes {
None
} else {
Some(self.read_bytes(num_bytes))
}
}
pub fn read_all(&mut self) -> &[u8] {
self.read_bytes(self.len())
}
pub fn read_and_copy_bytes(&mut self, dest: &mut [u8]) -> usize {
let readable = self.readable();
let len = core::cmp::min(dest.len(), readable.len());
if len == 0 {
return 0;
}
let src = &readable[..len];
let copy_dest = &mut dest[..len];
copy_dest.copy_from_slice(src);
self.read_bytes(len);
len
}
pub fn try_read_exact(&mut self, dest: &mut [u8]) -> Option<()> {
if self.len() < dest.len() {
return None;
}
self.read_and_copy_bytes(dest);
Some(())
}
pub fn try_parse<R, F>(&mut self, f: F) -> Option<R>
where
F: FnOnce(&mut FixedBuf<SIZE>) -> Option<R>,
{
let original_read_index = self.read_index;
let original_write_index = self.write_index;
if let Some(value) = f(self) {
Some(value)
} else {
self.read_index = original_read_index;
self.write_index = original_write_index;
None
}
}
pub fn copy_once_from<R: std::io::Read>(
&mut self,
reader: &mut R,
) -> Result<usize, std::io::Error> {
let writable = self.writable();
if writable.is_empty() {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
"no empty space in buffer",
));
};
let num_read = reader.read(writable)?;
self.wrote(num_read);
Ok(num_read)
}
pub fn write_str(&mut self, s: &str) -> Result<(), NotEnoughSpaceError> {
self.write_bytes(s.as_bytes()).map(|_| ())
}
pub fn write_bytes(&mut self, data: &[u8]) -> core::result::Result<usize, NotEnoughSpaceError> {
let writable = self.writable();
if writable.len() < data.len() {
return Err(NotEnoughSpaceError {});
}
let dest = &mut writable[..data.len()];
dest.copy_from_slice(data);
self.wrote(data.len());
Ok(data.len())
}
pub fn writable(&mut self) -> &mut [u8] {
&mut self.mem.as_mut()[self.write_index..]
}
pub fn wrote(&mut self, num_bytes: usize) {
if num_bytes == 0 {
return;
}
let new_write_index = self.write_index + num_bytes;
assert!(
new_write_index <= self.mem.as_mut().len(),
"write would overflow"
);
self.write_index = new_write_index;
}
pub fn shift(&mut self) {
if self.read_index == 0 {
return;
}
self.mem
.as_mut()
.copy_within(self.read_index..self.write_index, 0);
self.write_index -= self.read_index;
self.read_index = 0;
}
pub fn deframe<F>(
&mut self,
deframer_fn: F,
) -> Result<Option<core::ops::Range<usize>>, std::io::Error>
where
F: Fn(&[u8]) -> Result<Option<(core::ops::Range<usize>, usize)>, MalformedInputError>,
{
if self.is_empty() {
return Ok(None);
}
match deframer_fn(self.readable())? {
Some((data_range, block_len)) => {
let mem_start = self.read_index + data_range.start;
let mem_end = self.read_index + data_range.end;
self.read_bytes(block_len);
Ok(Some(mem_start..mem_end))
}
None => Ok(None),
}
}
pub fn read_frame<R, F>(
&mut self,
reader: &mut R,
deframer_fn: F,
) -> Result<Option<&[u8]>, std::io::Error>
where
R: std::io::Read,
F: Fn(&[u8]) -> Result<Option<(core::ops::Range<usize>, usize)>, MalformedInputError>,
{
loop {
if !self.is_empty() {
if let Some(frame_range) = self.deframe(&deframer_fn)? {
return Ok(Some(&self.mem()[frame_range]));
}
}
self.shift();
let writable = self.writable();
if writable.is_empty() {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
"end of buffer full",
));
};
let num_read = reader.read(writable)?;
if num_read == 0 {
if self.is_empty() {
return Ok(None);
}
return Err(std::io::Error::new(
std::io::ErrorKind::UnexpectedEof,
"eof after reading part of a frame",
));
}
self.wrote(num_read);
}
}
}
impl<const SIZE: usize> std::io::Write for FixedBuf<SIZE> {
fn write(&mut self, data: &[u8]) -> std::io::Result<usize> {
Ok(self.write_bytes(data)?)
}
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}
impl<const SIZE: usize> std::io::Read for FixedBuf<SIZE> {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
Ok(self.read_and_copy_bytes(buf))
}
}
impl<const SIZE: usize> core::fmt::Debug for FixedBuf<SIZE> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::result::Result<(), core::fmt::Error> {
write!(
f,
"FixedBuf<{}>{{{} writable, {} readable: \"{}\"}}",
SIZE,
SIZE - self.write_index,
self.len(),
self.escape_ascii()
)
}
}
impl<const SIZE: usize> Default for FixedBuf<SIZE> {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
use once_cell::sync::Lazy;
use std::sync::Mutex;
static STATIC_FIXED_BUF: Lazy<Mutex<FixedBuf<131072>>> =
Lazy::new(|| Mutex::new(FixedBuf::new()));
fn deframe_line_reject_xs(
data: &[u8],
) -> Result<Option<(core::ops::Range<usize>, usize)>, MalformedInputError> {
if data.contains(&b'x') || data.contains(&b'X') {
return Err(MalformedInputError::new("err1".to_string()));
}
deframe_line(data)
}
#[test]
fn test_not_enough_space_error() {
let e = NotEnoughSpaceError {};
let io_error: std::io::Error = e.into();
assert_eq!(std::io::ErrorKind::InvalidData, io_error.kind());
assert_eq!("not enough space in buffer", &io_error.to_string());
let string: String = e.into();
assert_eq!("not enough space in buffer", &string);
}
#[test]
fn test_malformed_input_error() {
let e = MalformedInputError("err1".to_string());
let io_error: std::io::Error = e.clone().into();
assert_eq!(std::io::ErrorKind::InvalidData, io_error.kind());
assert_eq!("malformed input: err1", &io_error.to_string());
let string: String = e.into();
assert_eq!("malformed input: err1", &string);
}
#[test]
fn test_static_fixed_buf() {
let mut buf = STATIC_FIXED_BUF.lock().unwrap();
assert_eq!(0, buf.len());
buf.write_str("abc").unwrap();
assert_eq!("abc", buf.escape_ascii());
}
#[test]
fn test_new() {
let buf: FixedBuf<1> = FixedBuf::new();
assert_eq!("", buf.escape_ascii());
let _: FixedBuf<42> = FixedBuf::new();
let _: FixedBuf<262144> = FixedBuf::new();
}
#[test]
fn test_empty() {
let mut buf: FixedBuf<8> = FixedBuf::empty([48_u8; 8] );
assert_eq!("", buf.escape_ascii());
buf.write_str("aaaa").unwrap();
assert_eq!("aaaa", buf.escape_ascii());
buf.write_str("bbbb").unwrap();
assert_eq!("aaaabbbb", buf.escape_ascii());
}
#[test]
fn test_filled() {
let mut buf: FixedBuf<8> = FixedBuf::filled([97_u8; 8] );
assert_eq!("aaaaaaaa", buf.escape_ascii());
buf.read_byte();
buf.shift();
buf.write_str("b").unwrap();
assert_eq!("aaaaaaab", buf.escape_ascii());
}
#[test]
fn test_into_inner() {
let mut buf: FixedBuf<8> = FixedBuf::new();
buf.write_str("abc").unwrap();
let mem = buf.into_inner();
assert_eq!(&[97_u8, 98, 99, 0, 0, 0, 0, 0], &mem);
}
#[test]
fn test_len() {
let mut buf: FixedBuf<16> = FixedBuf::new();
assert_eq!(0, buf.len());
buf.write_str("abc").unwrap();
assert_eq!(3, buf.len());
buf.read_bytes(2);
assert_eq!(1, buf.len());
buf.shift();
assert_eq!(1, buf.len());
buf.read_all();
assert_eq!(0, buf.len());
}
#[test]
fn test_is_empty() {
let mut buf: FixedBuf<16> = FixedBuf::new();
assert!(buf.is_empty());
buf.write_str("abc").unwrap();
assert!(!buf.is_empty());
buf.read_all();
assert!(buf.is_empty());
}
#[test]
fn test_clear() {
let mut buf: FixedBuf<16> = FixedBuf::new();
buf.write_str("abc").unwrap();
assert_eq!(3, buf.len());
buf.clear();
assert!(buf.is_empty());
}
#[test]
fn test_write_str() {
let mut buf: FixedBuf<4> = FixedBuf::new();
buf.write_str("a").unwrap();
buf.write_str("bc").unwrap();
assert_eq!("abc", buf.escape_ascii());
assert_eq!(Err(NotEnoughSpaceError {}), buf.write_str("de"));
assert_eq!("abc", buf.escape_ascii());
buf.write_str("d").unwrap();
assert_eq!("abcd", buf.escape_ascii());
assert_eq!(Err(NotEnoughSpaceError {}), buf.write_str("e"));
}
#[test]
fn test_write_bytes() {
let mut buf: FixedBuf<4> = FixedBuf::new();
assert_eq!(Ok(1usize), buf.write_bytes(b"a"));
assert_eq!(Ok(2), buf.write_bytes(b"bc"));
assert_eq!("abc", buf.escape_ascii());
assert_eq!(Err(NotEnoughSpaceError {}), buf.write_bytes(b"de"));
assert_eq!(Ok(1), buf.write_bytes(b"d"));
assert_eq!("abcd", buf.escape_ascii());
assert_eq!(Err(NotEnoughSpaceError {}), buf.write_bytes(b"e"));
}
#[test]
fn test_writable_and_wrote() {
let mut buf: FixedBuf<16> = FixedBuf::new();
assert_eq!(16, buf.writable().len());
buf.writable()[0] = 'a' as u8;
buf.wrote(1);
assert_eq!("a", buf.escape_ascii());
let many_bs = "b".repeat(15);
assert_eq!(many_bs.len(), buf.writable().len());
buf.writable().copy_from_slice(many_bs.as_bytes());
buf.wrote(many_bs.len());
assert_eq!("a".to_string() + &many_bs, buf.escape_ascii());
assert!(buf.writable().is_empty());
}
#[test]
#[should_panic]
fn test_wrote_too_much() {
let mut buf: FixedBuf<16> = FixedBuf::new();
buf.wrote(17);
}
#[test]
fn test_shift_empty() {
let mut buf: FixedBuf<4> = FixedBuf::new();
buf.shift();
buf.write_str("abcd").unwrap();
assert_eq!("abcd", buf.escape_ascii());
}
#[test]
fn test_shift_half_filled() {
let mut buf: FixedBuf<6> = FixedBuf::new();
buf.write_str("abcd").unwrap();
buf.shift();
buf.read_bytes(2);
buf.write_str("ef").unwrap();
assert_eq!(NotEnoughSpaceError {}, buf.write_str("gh").unwrap_err());
buf.shift();
buf.write_str("gh").unwrap();
assert_eq!("cdefgh", buf.escape_ascii());
}
#[test]
fn test_shift_full() {
let mut buf: FixedBuf<4> = FixedBuf::new();
buf.write_str("abcd").unwrap();
buf.shift();
buf.read_bytes(2);
assert_eq!(NotEnoughSpaceError {}, buf.write_str("e").unwrap_err());
buf.shift();
buf.write_str("e").unwrap();
buf.write_str("f").unwrap();
assert_eq!(NotEnoughSpaceError {}, buf.write_str("g").unwrap_err());
assert_eq!("cdef", buf.escape_ascii());
}
#[test]
fn test_shift_read_all() {
let mut buf: FixedBuf<4> = FixedBuf::new();
buf.write_str("abcd").unwrap();
buf.read_bytes(4);
buf.shift();
buf.write_str("efgh").unwrap();
assert_eq!("efgh", buf.escape_ascii());
}
#[test]
fn test_deframe() {
let mut buf: FixedBuf<8> = FixedBuf::new();
assert_eq!(None, buf.deframe(deframe_line_reject_xs).unwrap());
buf.write_str("abc").unwrap();
assert_eq!(None, buf.deframe(deframe_line_reject_xs).unwrap());
assert_eq!("abc", buf.escape_ascii());
buf.write_str("\n").unwrap();
assert_eq!(Some(0..3), buf.deframe(deframe_line_reject_xs).unwrap());
assert_eq!("", buf.escape_ascii());
buf.write_str("x").unwrap();
assert_eq!(
std::io::ErrorKind::InvalidData,
buf.deframe(deframe_line_reject_xs).unwrap_err().kind()
);
}
#[test]
fn test_read_frame_empty_to_eof() {
let mut buf: FixedBuf<8> = FixedBuf::new();
let mut reader = std::io::Cursor::new(b"");
assert_eq!(
None,
buf.read_frame(&mut reader, deframe_line_reject_xs).unwrap()
);
assert_eq!("", buf.escape_ascii());
}
#[test]
fn test_read_frame_empty_to_incomplete() {
let mut buf: FixedBuf<8> = FixedBuf::new();
let mut reader = std::io::Cursor::new(b"abc");
assert_eq!(
std::io::ErrorKind::UnexpectedEof,
buf.read_frame(&mut reader, deframe_line_reject_xs)
.unwrap_err()
.kind()
);
assert_eq!("abc", buf.escape_ascii());
}
#[test]
fn test_read_frame_empty_to_complete() {
let mut buf: FixedBuf<8> = FixedBuf::new();
let mut reader = std::io::Cursor::new(b"abc\n");
assert_eq!(
"abc",
escape_ascii(
buf.read_frame(&mut reader, deframe_line_reject_xs)
.unwrap()
.unwrap()
)
);
assert_eq!("", buf.escape_ascii());
}
#[test]
fn test_read_frame_empty_to_complete_with_leftover() {
let mut buf: FixedBuf<8> = FixedBuf::new();
let mut reader = std::io::Cursor::new(b"abc\nde");
assert_eq!(
"abc",
escape_ascii(
buf.read_frame(&mut reader, deframe_line_reject_xs)
.unwrap()
.unwrap()
)
);
assert_eq!("de", buf.escape_ascii());
}
#[test]
fn test_read_frame_empty_to_invalid() {
let mut buf: FixedBuf<8> = FixedBuf::new();
let mut reader = std::io::Cursor::new(b"x");
assert_eq!(
std::io::ErrorKind::InvalidData,
buf.read_frame(&mut reader, deframe_line_reject_xs)
.unwrap_err()
.kind()
);
assert_eq!("x", buf.escape_ascii());
}
#[test]
fn test_read_frame_incomplete_to_eof() {
let mut buf: FixedBuf<8> = FixedBuf::new();
buf.write_str("a").unwrap();
let mut reader = std::io::Cursor::new(b"");
assert_eq!(
std::io::ErrorKind::UnexpectedEof,
buf.read_frame(&mut reader, deframe_line_reject_xs)
.unwrap_err()
.kind()
);
assert_eq!("a", buf.escape_ascii());
}
#[test]
fn test_read_frame_incomplete_to_incomplete() {
let mut buf: FixedBuf<8> = FixedBuf::new();
buf.write_str("a").unwrap();
let mut reader = std::io::Cursor::new(b"bc");
assert_eq!(
std::io::ErrorKind::UnexpectedEof,
buf.read_frame(&mut reader, deframe_line_reject_xs)
.unwrap_err()
.kind()
);
assert_eq!("abc", buf.escape_ascii());
}
#[test]
fn test_read_frame_incomplete_to_complete() {
let mut buf: FixedBuf<8> = FixedBuf::new();
buf.write_str("a").unwrap();
let mut reader = std::io::Cursor::new(b"bc\n");
assert_eq!(
"abc",
escape_ascii(
buf.read_frame(&mut reader, deframe_line_reject_xs)
.unwrap()
.unwrap()
)
);
assert_eq!("", buf.escape_ascii());
}
#[test]
fn test_read_frame_incomplete_to_complete_with_leftover() {
let mut buf: FixedBuf<8> = FixedBuf::new();
buf.write_str("a").unwrap();
let mut reader = std::io::Cursor::new(b"bc\nde");
assert_eq!(
"abc",
escape_ascii(
buf.read_frame(&mut reader, deframe_line_reject_xs)
.unwrap()
.unwrap()
)
);
assert_eq!("de", buf.escape_ascii());
}
#[test]
fn test_read_frame_complete_doesnt_read() {
let mut buf: FixedBuf<8> = FixedBuf::new();
buf.write_str("abc\n").unwrap();
assert_eq!(
"abc",
escape_ascii(
buf.read_frame(&mut FakeReadWriter::empty(), deframe_line_reject_xs)
.unwrap()
.unwrap()
)
);
assert_eq!("", buf.escape_ascii());
}
#[test]
fn test_read_frame_complete_leaves_leftovers() {
let mut buf: FixedBuf<8> = FixedBuf::new();
buf.write_str("abc\nde").unwrap();
assert_eq!(
"abc",
escape_ascii(
buf.read_frame(&mut FakeReadWriter::empty(), deframe_line_reject_xs)
.unwrap()
.unwrap()
)
);
assert_eq!("de", buf.escape_ascii());
}
#[test]
fn test_read_frame_invalid_doesnt_read() {
let mut buf: FixedBuf<8> = FixedBuf::new();
buf.write_str("x").unwrap();
assert_eq!(
std::io::ErrorKind::InvalidData,
buf.read_frame(&mut FakeReadWriter::empty(), deframe_line_reject_xs)
.unwrap_err()
.kind()
);
assert_eq!("x", buf.escape_ascii());
}
#[test]
fn test_read_frame_buffer_full() {
let mut buf: FixedBuf<8> = FixedBuf::new();
buf.write_str("abcdefgh").unwrap();
let mut reader = std::io::Cursor::new(b"bc\nde");
assert_eq!(
std::io::ErrorKind::InvalidData,
buf.read_frame(&mut reader, deframe_line_reject_xs)
.unwrap_err()
.kind()
);
assert_eq!("abcdefgh", buf.escape_ascii());
}
#[test]
fn test_readable() {
let mut buf: FixedBuf<16> = FixedBuf::new();
assert_eq!("", escape_ascii(buf.readable()));
buf.write_str("abc").unwrap();
assert_eq!("abc", escape_ascii(buf.readable()));
buf.read_bytes(2);
assert_eq!("c", escape_ascii(buf.readable()));
buf.read_bytes(1);
assert_eq!("", escape_ascii(buf.readable()));
buf.write_str("d").unwrap();
assert_eq!("d", escape_ascii(buf.readable()));
buf.shift();
assert_eq!("d", escape_ascii(buf.readable()));
}
#[test]
fn test_read_byte() {
let mut buf: FixedBuf<8> = FixedBuf::new();
buf.write_str("abc").unwrap();
assert_eq!(b'a', buf.read_byte());
assert_eq!("bc", buf.escape_ascii());
assert_eq!(b'b', buf.read_byte());
assert_eq!("c", buf.escape_ascii());
assert_eq!(b'c', buf.read_byte());
assert_eq!("", buf.escape_ascii());
}
#[test]
fn test_read_byte_mut() {
let mut buf: FixedBuf<16> = FixedBuf::new();
assert_eq!("", buf.escape_ascii());
buf.write_str("ab").unwrap();
assert_eq!(b'a', buf.read_byte());
assert_eq!("b", buf.escape_ascii());
buf.write_str("c").unwrap();
assert_eq!("bc", buf.escape_ascii());
assert_eq!(b'b', buf.read_byte());
assert_eq!("c", buf.escape_ascii());
assert_eq!(b'c', buf.read_byte());
assert_eq!("", buf.escape_ascii());
buf.write_str("d").unwrap();
assert_eq!("d", buf.escape_ascii());
assert_eq!(b'd', buf.read_byte());
assert_eq!("", buf.escape_ascii());
}
#[test]
fn test_read_bytes() {
let mut buf: FixedBuf<8> = FixedBuf::new();
buf.write_str("abc").unwrap();
assert_eq!("a", escape_ascii(buf.read_bytes(1)));
assert_eq!("bc", buf.escape_ascii());
assert_eq!("bc", escape_ascii(buf.read_bytes(2)));
assert_eq!("", buf.escape_ascii());
}
#[test]
fn test_read_bytes_mut() {
let mut buf: FixedBuf<16> = FixedBuf::new();
buf.write_str("abc").unwrap();
assert_eq!("a", escape_ascii(buf.read_bytes(1)));
assert_eq!("bc", buf.escape_ascii());
assert_eq!("bc", escape_ascii(buf.read_bytes(2)));
assert_eq!("", buf.escape_ascii());
buf.write_str("d").unwrap();
buf.shift();
buf.write_str("e").unwrap();
assert_eq!("d", escape_ascii(buf.read_bytes(1)));
assert_eq!("e", buf.escape_ascii());
}
#[test]
#[should_panic]
fn test_read_bytes_underflow() {
let mut buf: FixedBuf<16> = FixedBuf::new();
buf.write_str("a").unwrap();
buf.read_bytes(2);
}
#[test]
fn test_try_read_bytes() {
let mut buf: FixedBuf<8> = FixedBuf::new();
buf.write_str("abc").unwrap();
assert_eq!(Some("a".as_bytes()), buf.try_read_bytes(1));
assert_eq!("bc", buf.escape_ascii());
assert_eq!(None, buf.try_read_bytes(3));
assert_eq!("bc", buf.escape_ascii());
assert_eq!(Some("bc".as_bytes()), buf.try_read_bytes(2));
assert_eq!("", buf.escape_ascii());
assert_eq!(None, buf.try_read_bytes(1));
assert_eq!("", buf.escape_ascii());
}
#[test]
fn test_try_read_bytes_mut() {
let mut buf: FixedBuf<16> = FixedBuf::new();
buf.write_str("abc").unwrap();
assert_eq!(Some("a".as_bytes()), buf.try_read_bytes(1));
assert_eq!("bc", buf.escape_ascii());
assert_eq!(None, buf.try_read_bytes(3));
assert_eq!("bc", buf.escape_ascii());
assert_eq!(Some("bc".as_bytes()), buf.try_read_bytes(2));
assert_eq!("", buf.escape_ascii());
assert_eq!(None, buf.try_read_bytes(1));
assert_eq!("", buf.escape_ascii());
buf.write_str("d").unwrap();
buf.shift();
buf.write_str("e").unwrap();
assert_eq!(Some("d".as_bytes()), buf.try_read_bytes(1));
assert_eq!("e", buf.escape_ascii());
}
#[test]
fn test_read_all() {
let mut buf: FixedBuf<16> = FixedBuf::new();
assert_eq!("", escape_ascii(buf.read_all()));
buf.write_str("abc").unwrap();
assert_eq!("abc", escape_ascii(buf.read_all()));
buf.write_str("def").unwrap();
assert_eq!("def", escape_ascii(buf.read_all()));
assert_eq!("", escape_ascii(buf.read_all()));
}
#[test]
fn test_read_and_copy_bytes() {
let mut buf: FixedBuf<8> = FixedBuf::new();
buf.write_str("abc").unwrap();
let mut one = [0_u8; 1];
assert_eq!(1, buf.read_and_copy_bytes(&mut one));
assert_eq!(b"a", &one);
assert_eq!("bc", buf.escape_ascii());
let mut four = [0_u8; 4];
assert_eq!(2, buf.read_and_copy_bytes(&mut four));
assert_eq!(&[b'b', b'c', 0, 0], &four);
assert_eq!("", buf.escape_ascii());
}
#[test]
fn test_read_and_copy_bytes_mut() {
let mut buf: FixedBuf<16> = FixedBuf::new();
buf.write_str("abc").unwrap();
let mut one = [0_u8; 1];
assert_eq!(1, buf.read_and_copy_bytes(&mut one));
assert_eq!(b"a", &one);
assert_eq!("bc", buf.escape_ascii());
let mut four = [0_u8; 4];
assert_eq!(2, buf.read_and_copy_bytes(&mut four));
assert_eq!(&[b'b', b'c', 0, 0], &four);
assert_eq!("", buf.escape_ascii());
buf.write_str("d").unwrap();
buf.shift();
buf.write_str("e").unwrap();
assert_eq!(1, buf.read_and_copy_bytes(&mut one));
assert_eq!(b"d", &one);
assert_eq!("e", buf.escape_ascii());
}
#[test]
fn test_try_read_exact() {
let mut buf: FixedBuf<8> = FixedBuf::new();
buf.write_str("abc").unwrap();
let mut one = [0_u8; 1];
buf.try_read_exact(&mut one).unwrap();
assert_eq!(b"a", &one);
assert_eq!("bc", buf.escape_ascii());
let mut three = [0_u8; 3];
assert_eq!(None, buf.try_read_exact(&mut three));
assert_eq!(&[0, 0, 0], &three);
let mut two = [0_u8; 2];
buf.try_read_exact(&mut two).unwrap();
assert_eq!(b"bc", &two);
assert_eq!("", buf.escape_ascii());
}
#[test]
fn test_try_read_exact_mut() {
let mut buf: FixedBuf<16> = FixedBuf::new();
buf.write_str("abc").unwrap();
let mut one = [0_u8; 1];
buf.try_read_exact(&mut one).unwrap();
assert_eq!(b"a", &one);
assert_eq!("bc", buf.escape_ascii());
let mut three = [0_u8; 3];
assert_eq!(None, buf.try_read_exact(&mut three));
assert_eq!(&[0, 0, 0], &three);
assert_eq!("bc", buf.escape_ascii());
buf.write_str("d").unwrap();
buf.shift();
buf.write_str("e").unwrap();
buf.try_read_exact(&mut three).unwrap();
assert_eq!(b"bcd", &three);
assert_eq!("e", buf.escape_ascii());
}
#[test]
fn test_try_parse() {
#[derive(Debug, PartialEq)]
enum CountError {
BadValue,
TooShort,
TooLong,
}
impl core::fmt::Display for CountError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
core::fmt::Debug::fmt(self, f)
}
}
impl std::error::Error for CountError {}
fn count_as<const SIZE: usize>(
buf: &mut FixedBuf<SIZE>,
) -> Option<Result<usize, CountError>> {
let mut count: usize = 0;
loop {
match buf.try_read_byte()? {
b'a' => {
count += 1;
if count > 3 {
return Some(Err(CountError::TooLong));
}
}
b'b' if count < 1 => return Some(Err(CountError::TooShort)),
b'b' => return Some(Ok(count)),
_ => return Some(Err(CountError::BadValue)),
}
}
}
assert_eq!(None, FixedBuf::empty([0]).try_parse(count_as));
assert_eq!(None, FixedBuf::filled([b'a']).try_parse(count_as));
assert_eq!(None, FixedBuf::filled([b'a', b'a']).try_parse(count_as));
assert_eq!(
None,
FixedBuf::filled([b'a', b'a', b'a']).try_parse(count_as)
);
assert_eq!(
Some(Err(CountError::TooLong)),
FixedBuf::filled([b'a', b'a', b'a', b'a']).try_parse(count_as)
);
assert_eq!(
Some(Err(CountError::TooShort)),
FixedBuf::filled([b'b']).try_parse(count_as)
);
assert_eq!(
Some(Ok(1)),
FixedBuf::filled([b'a', b'b']).try_parse(count_as)
);
assert_eq!(
Some(Ok(2)),
FixedBuf::filled([b'a', b'a', b'b']).try_parse(count_as)
);
assert_eq!(
Some(Ok(3)),
FixedBuf::filled([b'a', b'a', b'a', b'b']).try_parse(count_as)
);
assert_eq!(
Some(Err(CountError::TooLong)),
FixedBuf::filled([b'a', b'a', b'a', b'a', b'b']).try_parse(count_as)
);
assert_eq!(
Some(Err(CountError::BadValue)),
FixedBuf::filled([b'a', b'c']).try_parse(count_as)
);
let mut buf: FixedBuf<16> = FixedBuf::new();
assert_eq!(None, buf.try_parse(count_as));
buf.write_str("a").unwrap();
assert_eq!(None, buf.try_parse(count_as));
assert_eq!("a", buf.escape_ascii());
buf.write_str("baaba").unwrap();
assert_eq!(Some(Ok(1)), buf.try_parse(count_as));
assert_eq!("aaba", buf.escape_ascii());
assert_eq!(Some(Ok(2)), buf.try_parse(count_as));
assert_eq!("a", buf.escape_ascii());
assert_eq!(None, buf.try_parse(count_as));
buf.write_str("cbab").unwrap();
assert_eq!(Some(Err(CountError::BadValue)), buf.try_parse(count_as));
assert_eq!("bab", buf.escape_ascii());
buf.clear();
buf.write_str("b").unwrap();
assert_eq!(Some(Err(CountError::TooShort)), buf.try_parse(count_as));
assert_eq!("", buf.escape_ascii());
}
#[test]
fn test_copy_once_from() {
let mut buf: FixedBuf<4> = FixedBuf::new();
buf.write_str("a").unwrap();
assert_eq!(
2,
buf.copy_once_from(&mut std::io::Cursor::new(b"12"))
.unwrap()
);
assert_eq!("a12", escape_ascii(buf.read_all()));
assert_eq!(
3,
buf.copy_once_from(&mut std::io::Cursor::new(b"123"))
.unwrap()
);
assert_eq!("123", escape_ascii(buf.read_all()));
assert_eq!(
4,
buf.copy_once_from(&mut std::io::Cursor::new(b"1234"))
.unwrap()
);
assert_eq!("1234", escape_ascii(buf.read_all()));
assert_eq!(
4,
buf.copy_once_from(&mut std::io::Cursor::new(b"12345"))
.unwrap()
);
assert_eq!("1234", escape_ascii(buf.read_all()));
buf.write_str("abcd").unwrap();
assert_eq!(
std::io::ErrorKind::InvalidData,
buf.copy_once_from(&mut std::io::Cursor::new(b"1"))
.unwrap_err()
.kind()
);
assert_eq!("abcd", escape_ascii(buf.read_all()));
assert_eq!(
2,
buf.copy_once_from(&mut FakeReadWriter::new(vec![Ok(2)]))
.unwrap()
);
assert_eq!("ab", escape_ascii(buf.read_all()));
}
#[test]
fn test_escape_ascii() {
assert_eq!("", FixedBuf::filled([]).escape_ascii());
assert_eq!("abc", FixedBuf::filled([b'a', b'b', b'c']).escape_ascii());
assert_eq!("\\r\\n", FixedBuf::filled([b'\r', b'\n']).escape_ascii());
let mut buf: FixedBuf<4> = FixedBuf::new();
buf.write_str("€").unwrap();
assert_eq!("\\xe2\\x82\\xac", buf.escape_ascii());
assert_eq!("\\x01", FixedBuf::filled([1]).escape_ascii());
let buf = FixedBuf::filled([b'a', b'b', b'c']);
assert_eq!("abc", buf.escape_ascii());
assert_eq!(b"abc", buf.readable());
}
#[test]
fn test_std_io_write() {
let mut buf: FixedBuf<16> = FixedBuf::new();
std::io::Write::write(&mut buf, b"abc").unwrap();
assert_eq!("abc", buf.escape_ascii());
std::io::Write::write(&mut buf, b"def").unwrap();
assert_eq!("abcdef", buf.escape_ascii());
buf.read_bytes(1);
std::io::Write::write(&mut buf, b"g").unwrap();
assert_eq!("bcdefg", buf.escape_ascii());
std::io::Write::write(&mut buf, "h".repeat(8).as_bytes()).unwrap();
std::io::Write::write(&mut buf, b"i").unwrap();
assert_eq!(
std::io::ErrorKind::InvalidData,
std::io::Write::write(&mut buf, b"def").unwrap_err().kind()
);
}
#[test]
fn test_std_io_read() {
let mut buf: FixedBuf<16> = FixedBuf::new();
let mut data = ['.' as u8; 16];
assert_eq!(0, std::io::Read::read(&mut buf, &mut data).unwrap());
assert_eq!("..........", escape_ascii(&data[..10]));
buf.write_str("abc").unwrap();
assert_eq!(3, std::io::Read::read(&mut buf, &mut data).unwrap());
assert_eq!("abc.......", escape_ascii(&data[..10]));
assert_eq!(0, std::io::Read::read(&mut buf, &mut data).unwrap());
let many_bs = "b".repeat(16);
buf.write_str(&many_bs).unwrap();
assert_eq!(16, std::io::Read::read(&mut buf, &mut data).unwrap());
assert_eq!(many_bs, escape_ascii(&data[..]));
assert_eq!(0, std::io::Read::read(&mut buf, &mut data).unwrap());
}
#[test]
fn test_default() {
let _: FixedBuf<8> = FixedBuf::default();
let _: FixedBuf<16> = FixedBuf::default();
let mut buf: FixedBuf<32> = FixedBuf::default();
buf.write_str("abc").unwrap();
assert_eq!("abc", buf.escape_ascii());
}
#[test]
fn test_debug() {
let mut buf: FixedBuf<8> = FixedBuf::new();
buf.write_str("abc").unwrap();
buf.read_bytes(1);
assert_eq!(
"FixedBuf<8>{5 writable, 2 readable: \"bc\"}",
format!("{:?}", buf)
);
}
}