#![doc(html_root_url="https://briansmith.org/rustdoc/")]
#![no_std]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Input<'a> {
value: no_panic::NoPanicSlice<'a>
}
impl<'a> Input<'a> {
pub fn from(bytes: &'a [u8]) -> Input<'a> {
debug_assert!(bytes.len() < core::usize::MAX);
Input { value: no_panic::NoPanicSlice::new(bytes) }
}
#[inline]
pub fn is_empty(&self) -> bool { self.value.len() == 0 }
#[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 = try!(read(&mut input));
if input.at_end() {
Ok(result)
} else {
Err(incomplete_read)
}
}
pub fn read_all_mut<F, R, E>(&self, incomplete_read: E, mut read: F)
-> Result<R, E>
where F: FnMut(&mut Reader<'a>)
-> Result<R, E> {
let mut input = Reader::new(*self);
let result = try!(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, 'b> PartialEq<&'b [u8]> for Input<'a> {
fn eq(&self, other: &&'b [u8]) -> bool {
self.as_slice_less_safe() == *other
}
}
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>)
-> Result<R, E> {
match input {
Some(input) => {
let mut input = Reader::new(input);
let result = try!(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::NoPanicSlice<'a>,
i: usize
}
pub struct Mark {
i: usize
}
impl<'a> Reader<'a> {
#[inline]
pub fn new(input: Input<'a>) -> Reader<'a> {
Reader { 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 } }
pub fn peek(&self, b: u8) -> bool {
match self.input.get(self.i) {
Some(actual_b) => return b == *actual_b,
None => false
}
}
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)
}
}
pub fn skip(&mut self, num_bytes: usize) -> Result<(), EndOfInput> {
self.skip_and_get_input(num_bytes).map(|_| ())
}
pub fn skip_and_get_input(&mut self, num_bytes: usize)
-> Result<Input<'a>, EndOfInput> {
let new_i = try!(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;
ret
}
pub fn skip_to_end(&mut self) -> Input<'a> {
let to_skip = self.input.len() - self.i;
self.skip_and_get_input(to_skip).unwrap()
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct EndOfInput;
mod no_panic {
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct NoPanicSlice<'a> {
bytes: &'a [u8]
}
impl<'a> NoPanicSlice<'a> {
#[inline]
pub fn new(bytes: &'a [u8]) -> NoPanicSlice<'a> {
NoPanicSlice { bytes: bytes }
}
#[inline]
pub fn get(&self, i: usize) -> Option<&u8> { self.bytes.get(i) }
#[inline]
pub fn len(&self) -> usize { self.bytes.len() }
#[inline]
pub fn subslice(&self, start: usize, end: usize) -> Option<NoPanicSlice<'a>> {
if start <= end && end <= self.bytes.len() {
Some(NoPanicSlice::new(&self.bytes[start..end]))
} else {
None
}
}
#[inline]
pub fn as_slice_less_safe(&self) -> &'a [u8] { self.bytes }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_input_from() {
let _ = Input::from(b"foo");
}
#[test]
fn test_input_is_empty() {
let input = Input::from(b"");
assert!(input.is_empty());
let input = Input::from(b"foo");
assert!(!input.is_empty());
}
#[test]
fn test_input_len() {
let input = Input::from(b"foo");
assert_eq!(input.len(), 3);
}
#[test]
fn test_input_read_all() {
let input = Input::from(b"foo");
let result = input.read_all(EndOfInput, |input| {
assert_eq!(b'f', try!(input.read_byte()));
assert_eq!(b'o', try!(input.read_byte()));
assert_eq!(b'o', try!(input.read_byte()));
assert!(input.at_end());
Ok(())
});
assert_eq!(result, Ok(()));
}
#[test]
fn test_input_read_all_unconsume() {
let input = Input::from(b"foo");
let result = input.read_all(EndOfInput, |input| {
assert_eq!(b'f', try!(input.read_byte()));
assert!(!input.at_end());
Ok(())
});
assert_eq!(result, Err(EndOfInput));
}
#[test]
fn test_input_as_slice_less_safe() {
let slice = b"foo";
let input = Input::from(slice);
assert_eq!(input.as_slice_less_safe(), slice);
}
}