#![doc(html_root_url = "https://briansmith.org/rustdoc/")]
#![deny(unused_qualifications)]
#![forbid(
anonymous_parameters,
box_pointers,
missing_docs,
trivial_casts,
trivial_numeric_casts,
unsafe_code,
unstable_features,
unused_extern_crates,
unused_import_braces,
unused_results,
variant_size_differences,
warnings
)]
#![no_std]
#[derive(Clone, Copy, Debug, Eq)]
pub struct Input<'a> {
value: no_panic::Slice<'a>,
}
impl<'a> Input<'a> {
pub const fn from(bytes: &'a [u8]) -> Self {
Self {
value: no_panic::Slice::new(bytes),
}
}
#[inline]
pub fn is_empty(&self) -> bool { self.value.is_empty() }
#[inline]
pub fn len(&self) -> usize { self.value.len() }
pub fn read_all<F, R, E>(&self, incomplete_read: E, read: F) -> Result<R, E>
where
F: FnOnce(&mut Reader<'a>) -> Result<R, E>,
{
let mut input = Reader::new(*self);
let result = read(&mut input)?;
if input.at_end() {
Ok(result)
} else {
Err(incomplete_read)
}
}
#[inline]
pub fn as_slice_less_safe(&self) -> &'a [u8] { self.value.as_slice_less_safe() }
}
impl<'a> From<&'a [u8]> for Input<'a> {
#[inline]
fn from(value: &'a [u8]) -> Self { Self { value: no_panic::Slice::new(value)} }
}
impl PartialEq<Input<'_>> for Input<'_> {
#[inline]
fn eq(&self, other: &Input) -> bool {
self.as_slice_less_safe() == other.as_slice_less_safe()
}
}
impl PartialEq<[u8]> for Input<'_> {
#[inline]
fn eq(&self, other: &[u8]) -> bool { self.as_slice_less_safe() == other }
}
impl PartialEq<Input<'_>> for [u8] {
#[inline]
fn eq(&self, other: &Input) -> bool { other.as_slice_less_safe() == self }
}
pub fn read_all_optional<'a, F, R, E>(
input: Option<Input<'a>>, incomplete_read: E, read: F,
) -> Result<R, E>
where
F: FnOnce(Option<&mut Reader<'a>>) -> Result<R, E>,
{
match input {
Some(input) => {
let mut input = Reader::new(input);
let result = read(Some(&mut input))?;
if input.at_end() {
Ok(result)
} else {
Err(incomplete_read)
}
},
None => read(None),
}
}
#[derive(Debug)]
pub struct Reader<'a> {
input: no_panic::Slice<'a>,
i: usize,
}
pub struct Mark {
i: usize,
}
impl<'a> Reader<'a> {
#[inline]
pub fn new(input: Input<'a>) -> Self {
Self {
input: input.value,
i: 0,
}
}
#[inline]
pub fn at_end(&self) -> bool { self.i == self.input.len() }
#[inline]
pub fn get_input_between_marks(
&self, mark1: Mark, mark2: Mark,
) -> Result<Input<'a>, EndOfInput> {
self.input
.subslice(mark1.i..mark2.i)
.map(|subslice| Input { value: subslice })
.ok_or(EndOfInput)
}
#[inline]
pub fn mark(&self) -> Mark { Mark { i: self.i } }
#[inline]
pub fn peek(&self, b: u8) -> bool {
match self.input.get(self.i) {
Some(actual_b) => b == *actual_b,
None => false,
}
}
#[inline]
pub fn read_byte(&mut self) -> Result<u8, EndOfInput> {
match self.input.get(self.i) {
Some(b) => {
self.i += 1; Ok(*b)
},
None => Err(EndOfInput),
}
}
#[inline]
pub fn read_bytes(&mut self, num_bytes: usize) -> Result<Input<'a>, EndOfInput> {
let new_i = self.i.checked_add(num_bytes).ok_or(EndOfInput)?;
let ret = self
.input
.subslice(self.i..new_i)
.map(|subslice| Input { value: subslice })
.ok_or(EndOfInput)?;
self.i = new_i;
Ok(ret)
}
#[inline]
pub fn read_bytes_to_end(&mut self) -> Input<'a> {
let to_skip = self.input.len() - self.i;
self.read_bytes(to_skip).unwrap()
}
pub fn read_partial<F, R, E>(&mut self, read: F) -> Result<(Input<'a>, R), E>
where
F: FnOnce(&mut Reader<'a>) -> Result<R, E>,
{
let start = self.i;
let r = read(self)?;
let bytes_read = Input {
value: self.input.subslice(start..self.i).unwrap()
};
Ok((bytes_read, r))
}
#[inline]
pub fn skip(&mut self, num_bytes: usize) -> Result<(), EndOfInput> {
self.read_bytes(num_bytes).map(|_| ())
}
#[inline]
pub fn skip_to_end(&mut self) -> () { let _ = self.read_bytes_to_end(); }
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct EndOfInput;
mod no_panic {
use core;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Slice<'a> {
bytes: &'a [u8],
}
impl<'a> Slice<'a> {
#[inline]
pub const fn new(bytes: &'a [u8]) -> Self { Self { bytes } }
#[inline]
pub fn get(&self, i: usize) -> Option<&u8> { self.bytes.get(i) }
#[inline]
pub fn subslice(&self, r: core::ops::Range<usize>) -> Option<Self> {
self.bytes.get(r).map(|bytes| Self { bytes })
}
#[inline]
pub fn is_empty(&self) -> bool { self.bytes.is_empty() }
#[inline]
pub fn len(&self) -> usize { self.bytes.len() }
#[inline]
pub fn as_slice_less_safe(&self) -> &'a [u8] { self.bytes }
}
}