//! Internal: Declare the Reader type for tor-bytes use tor_error::{bad_api_usage, into_internal}; use crate::{Error, Readable, Result}; use std::num::NonZeroUsize; /// A type for reading messages from a slice of bytes. /// /// Unlike io::Read, this object has a simpler error type, and is designed /// for in-memory parsing only. /// /// The methods in [`Reader`] should never panic, with one exception: /// the `extract` and `extract_n` methods will panic if the underlying /// [`Readable`] object's `take_from` method panics. /// /// # Examples /// /// You can use a Reader to extract information byte-by-byte: /// /// ``` /// use tor_bytes::{Reader,Result}; /// let msg = [ 0x00, 0x01, 0x23, 0x45, 0x22, 0x00, 0x00, 0x00 ]; /// let mut b = Reader::from_slice(&msg[..]); /// // Multi-byte values are always big-endian. /// assert_eq!(b.take_u32()?, 0x12345); /// assert_eq!(b.take_u8()?, 0x22); /// /// // You can check on the length of the message... /// assert_eq!(b.total_len(), 8); /// assert_eq!(b.consumed(), 5); /// assert_eq!(b.remaining(), 3); /// // then skip over a some bytes... /// b.advance(3)?; /// // ... and check that the message is really exhausted. /// b.should_be_exhausted()?; /// # Result::Ok(()) /// ``` /// /// You can also use a Reader to extract objects that implement Readable. /// ``` /// use tor_bytes::{Reader,Result,Readable}; /// use std::net::Ipv4Addr; /// let msg = [ 0x00, 0x04, 0x7f, 0x00, 0x00, 0x01]; /// let mut b = Reader::from_slice(&msg[..]); /// /// let tp: u16 = b.extract()?; /// let ip: Ipv4Addr = b.extract()?; /// assert_eq!(tp, 4); /// assert_eq!(ip, Ipv4Addr::LOCALHOST); /// # Result::Ok(()) /// ``` pub struct Reader<'a> { /// The underlying slice that we're reading from b: &'a [u8], /// The next position in the slice that we intend to read from. off: usize, /// What to do if we run out of data - IOW are we reading a possibly incomplete message completeness: Completeness, } /// Whether we're supposed to have the complete message, or not /// /// IOW are we reading a possibly incomplete message? /// /// Affects the error return if we run out of data /// ([`Reader::incomplete_error`]). #[derive(Copy, Clone, Debug)] enum Completeness { /// We might not have the whole message, and that is expected /// /// Throw [`Error::Incomplete`] PossiblyIncomplete, /// We ought to have the whole message /// /// Throw [`Error::MissingData`] SupposedlyComplete, } impl<'a> Reader<'a> { /// Construct a new Reader from a slice of bytes. /// /// In tests, prefer [`Reader::from_slice_for_test`]. pub fn from_slice(slice: &'a [u8]) -> Self { Reader { b: slice, off: 0, completeness: Completeness::SupposedlyComplete, } } /// Construct a new Reader from a slice of bytes which may not be complete. /// /// This can be used to try to deserialise a message received from a protocol stream, /// if we don't know how much data we needed to buffer. /// /// [`Readable`] methods, [`extract`](Reader::extract), and so on, /// will return [`Error::Incomplete`] if the message is incomplete, /// and reading more would help. /// /// (This is achieved via [`incomplete_error`](Reader::incomplete_error.) /// /// # Warning about denial of service through excessive memory use /// /// It is hazardous to use this approach unless the buffer size is limited, /// since the sender could send an apparently-very-large message. /// /// # Warning about sub-readers /// /// If you are constructing other readers from data extracted from this one, /// make sure to use [`Reader::from_slice`] instead of this method! /// This method is only for the outermost reader. /// /// Failure to follow this warning may result in malformed messages /// being incorrectly reported as `Incomplete`. // // TODO this name is quite clumsy! pub fn from_possibly_incomplete_slice(slice: &'a [u8]) -> Self { Reader { b: slice, off: 0, completeness: Completeness::PossiblyIncomplete, } } /// Construct a new Reader from a slice of bytes, in tests /// /// This is equivalent to [`Reader::from_possibly_incomplete_slice`]. /// It should be used in test cases, because that gives more precise /// testing of the generation of incomplete data errors. pub fn from_slice_for_test(slice: &'a [u8]) -> Self { Self::from_possibly_incomplete_slice(slice) } /// Construct a new Reader from a 'Bytes' object. pub fn from_bytes(b: &'a bytes::Bytes) -> Self { Self::from_slice(b.as_ref()) } /// Return the total length of the slice in this reader, including /// consumed bytes and remaining bytes. pub fn total_len(&self) -> usize { self.b.len() } /// Return the total number of bytes in this reader that have not /// yet been read. pub fn remaining(&self) -> usize { self.b.len() - self.off } /// Consume this reader, and return a slice containing the remaining /// bytes from its slice that it did not consume. pub fn into_rest(self) -> &'a [u8] { &self.b[self.off..] } /// Return the total number of bytes in this reader that have /// already been read. pub fn consumed(&self) -> usize { self.off } /// Skip `n` bytes from the reader. /// /// Returns Ok on success. Throws MissingData or Incomplete if there were /// not enough bytes to skip. pub fn advance(&mut self, n: usize) -> Result<()> { self.peek(n)?; self.off += n; Ok(()) } /// Check whether this reader is exhausted (out of bytes). /// /// Return Ok if it is, and Err(Error::ExtraneousBytes) /// if there were extra bytes. pub fn should_be_exhausted(&self) -> Result<()> { if self.remaining() != 0 { return Err(Error::ExtraneousBytes); } Ok(()) } /// Truncate this reader, so that no more than `n` bytes remain. /// /// Fewer than `n` bytes may remain if there were not enough bytes /// to begin with. pub fn truncate(&mut self, n: usize) { if n < self.remaining() { self.b = &self.b[..self.off + n]; } } /// Try to return a slice of `n` bytes from this reader without /// consuming them. /// /// On success, returns Ok(slice). If there are fewer than n /// bytes, Throws MissingData or Incomplete if there were /// not enough bytes to skip. pub fn peek(&self, n: usize) -> Result<&'a [u8]> { if let Some(deficit) = n .checked_sub(self.remaining()) .and_then(|d| d.try_into().ok()) { return Err(self.incomplete_error(deficit)); } Ok(&self.b[self.off..(n + self.off)]) } /// Try to consume and return a slice of `n` bytes from this reader. /// /// On success, returns Ok(Slice). If there are fewer than n /// bytes, Throws MissingData or Incomplete. /// /// # Example /// ``` /// use tor_bytes::{Reader,Result}; /// let m = b"Hello World"; /// let mut b = Reader::from_slice(m); /// assert_eq!(b.take(5)?, b"Hello"); /// assert_eq!(b.take_u8()?, 0x20); /// assert_eq!(b.take(5)?, b"World"); /// b.should_be_exhausted()?; /// # Result::Ok(()) /// ``` pub fn take(&mut self, n: usize) -> Result<&'a [u8]> { let b = self.peek(n)?; self.advance(n)?; Ok(b) } /// Try to fill a provided buffer with bytes consumed from this reader. /// /// On success, the buffer will be filled with data from the /// reader, the reader will advance by the length of the buffer, /// and we'll return Ok(()). On failure the buffer will be /// unchanged. /// /// # Example /// ``` /// use tor_bytes::Reader; /// let m = b"Hello world"; /// let mut v1 = vec![0; 5]; /// let mut v2 = vec![0; 5]; /// let mut b = Reader::from_slice(m); /// b.take_into(&mut v1[..])?; /// assert_eq!(b.take_u8()?, b' '); /// b.take_into(&mut v2[..])?; /// assert_eq!(&v1[..], b"Hello"); /// assert_eq!(&v2[..], b"world"); /// b.should_be_exhausted()?; /// # tor_bytes::Result::Ok(()) /// ``` pub fn take_into(&mut self, buf: &mut [u8]) -> Result<()> { let n = buf.len(); let b = self.take(n)?; buf.copy_from_slice(b); Ok(()) } /// Try to consume and return a u8 from this reader. pub fn take_u8(&mut self) -> Result { let b = self.take(1)?; Ok(b[0]) } /// Try to consume and return a big-endian u16 from this reader. pub fn take_u16(&mut self) -> Result { let b: [u8; 2] = self.extract()?; let r = u16::from_be_bytes(b); Ok(r) } /// Try to consume and return a big-endian u32 from this reader. pub fn take_u32(&mut self) -> Result { let b: [u8; 4] = self.extract()?; let r = u32::from_be_bytes(b); Ok(r) } /// Try to consume and return a big-endian u64 from this reader. pub fn take_u64(&mut self) -> Result { let b: [u8; 8] = self.extract()?; let r = u64::from_be_bytes(b); Ok(r) } /// Try to consume and return a big-endian u128 from this reader. pub fn take_u128(&mut self) -> Result { let b: [u8; 16] = self.extract()?; let r = u128::from_be_bytes(b); Ok(r) } /// Try to consume and return bytes from this buffer until we /// encounter a terminating byte equal to `term`. /// /// On success, returns Ok(Slice), where the slice does not /// include the terminating byte. Throws MissingData or Incomplete /// if we do not find the terminating bytes. /// /// Advances the reader to the point immediately after the terminating /// byte. /// /// # Example /// ``` /// use tor_bytes::{Reader,Result}; /// let m = b"Hello\0wrld"; /// let mut b = Reader::from_slice(m); /// assert_eq!(b.take_until(0)?, b"Hello"); /// assert_eq!(b.into_rest(), b"wrld"); /// # Result::Ok(()) /// ``` pub fn take_until(&mut self, term: u8) -> Result<&'a [u8]> { let pos = self.b[self.off..] .iter() .position(|b| *b == term) .ok_or(self.incomplete_error( // 1.try_into().expect("1 == 0"), ))?; let result = self.take(pos)?; self.advance(1)?; Ok(result) } /// Consume and return all the remaining bytes, but do not consume the reader /// /// This can be useful if you need to possibly read either fixed-length data, /// or variable length data eating the rest of the `Reader`. /// /// The `Reader` will be left devoid of further bytes. /// Consider using `into_rest()` instead. pub fn take_rest(&mut self) -> &'a [u8] { self.take(self.remaining()) .expect("taking remaining failed") } /// Consume and return all but the last `n` remaining bytes. /// /// Gives `Error::MissingData` if there are fewer than `n` remaining bytes. /// /// It is invalid to call this method on a `Reader` constructed with /// [`Reader::from_possibly_incomplete_slice`]. (If we don't know where the /// data actually ends, we can't take all but the last `n` bytes.) /// Such calls cause an internal error. /// /// # Example /// ``` /// use tor_bytes::{Reader,Result}; /// let m = b"Hello World"; /// let mut b = Reader::from_slice(m); /// assert_eq!(b.take_all_but(2)?, b"Hello Wor"); /// assert_eq!(b.into_rest(), b"ld"); /// # Result::Ok(()) /// ``` pub fn take_all_but(&mut self, n: usize) -> Result<&'a [u8]> { match self.completeness { Completeness::PossiblyIncomplete => { return Err(Error::Bug(bad_api_usage!( "Called take_all_but on a PossiblyIncomplete reader." ))); } Completeness::SupposedlyComplete => {} } let n_to_take = self.remaining().checked_sub(n).ok_or(Error::MissingData)?; let result = self .take(n_to_take) .map_err(into_internal!("Subtraction misled us somehow"))?; debug_assert_eq!(self.remaining(), n); Ok(result) } /// Try to decode and remove a Readable from this reader, using its /// take_from() method. /// /// On failure, consumes nothing. pub fn extract(&mut self) -> Result { let off_orig = self.off; let result = E::take_from(self); if result.is_err() { // We encountered an error; we should rewind. self.off = off_orig; } result } /// Try to decode and remove `n` Readables from this reader, using the /// Readable's take_from() method. /// /// On failure, consumes nothing. pub fn extract_n(&mut self, n: usize) -> Result> { // This `min` will help us defend against a pathological case where an // attacker tells us that there are BIGNUM elements forthcoming, and our // attempt to allocate `Vec::with_capacity(BIGNUM)` makes us panic. // // The `min` can be incorrect if E is somehow encodable in zero bytes // (!?), but that will only cause our initial allocation to be too // small. // // In practice, callers should always check that `n` is reasonable // before calling this function, and protocol designers should not // provide e.g. 32-bit counters for object types of which we should // never allocate u32::MAX. let n_alloc = std::cmp::min(n, self.remaining()); let mut result = Vec::with_capacity(n_alloc); let off_orig = self.off; for _ in 0..n { match E::take_from(self) { Ok(item) => result.push(item), Err(e) => { // Encountered an error; we should rewind. self.off = off_orig; return Err(e); } } } Ok(result) } /// Decode something with a `u8` length field /// /// Prefer to use this function, rather than ad-hoc `take_u8` /// and subsequent manual length checks. /// Using this facility eliminates the need to separately keep track of the lengths. /// /// `read_nested` consumes a length field, /// and provides the closure `f` with an inner `Reader` that /// contains precisely that many bytes - /// the bytes which follow the length field in the original reader. /// If the closure is successful, `read_nested` checks that that inner reader is exhausted, /// i.e. that the inner contents had the same length as was specified. /// /// The closure should read whatever is inside the nested structure /// from the nested reader. /// It may well want to use `take_rest`, to consume all of the counted bytes. /// /// On failure, the amount consumed is not specified. pub fn read_nested_u8len(&mut self, f: F) -> Result where F: FnOnce(&mut Reader) -> Result, { read_nested_generic::(self, f) } /// Start decoding something with a u16 length field pub fn read_nested_u16len(&mut self, f: F) -> Result where F: FnOnce(&mut Reader) -> Result, { read_nested_generic::(self, f) } /// Start decoding something with a u32 length field pub fn read_nested_u32len(&mut self, f: F) -> Result where F: FnOnce(&mut Reader) -> Result, { read_nested_generic::(self, f) } /// Return a cursor object describing the current position of this Reader /// within its underlying byte stream. /// /// The resulting [`Cursor`] can be used with `range`, but nothing else. /// /// Note that having to use a `Cursor` is typically an anti-pattern: it /// tends to indicate that whatever you're parsing could probably have a /// better design that would better separate data from metadata. /// Unfortunately, there are a few places like that in the Tor protocols. // // TODO: This could instead be a function that takes a closure, passes a // reader to that closure, and returns the closure's output along with // whatever the reader consumed. pub fn cursor(&self) -> Cursor<'a> { Cursor { pos: self.off, _phantom: std::marker::PhantomData, } } /// Return the slice of bytes between the start cursor (inclusive) and end /// cursor (exclusive). /// /// If the cursors are not in order, return an empty slice. /// /// This function is guaranteed not to panic if the inputs were generated /// from a different Reader, but if so the byte slice that it returns will /// not be meaningful. pub fn range(&self, start: Cursor<'a>, end: Cursor<'a>) -> &'a [u8] { if start.pos <= end.pos && end.pos <= self.b.len() { &self.b[start.pos..end.pos] } else { &self.b[..0] } } /// Returns the error that should be returned if we ran out of data /// /// For a usual `Reader` this is [`Error::MissingData`]. /// For a reader from /// [`Reader::from_possibly_incomplete_slice`] /// it's [`Error::Incomplete`]. pub fn incomplete_error(&self, deficit: NonZeroUsize) -> Error { use Completeness as C; use Error as E; match self.completeness { C::PossiblyIncomplete => E::Incomplete { deficit: deficit.into(), }, C::SupposedlyComplete => E::MissingData, } } } /// A reference to a position within a [`Reader`]. #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] pub struct Cursor<'a> { /// The underlying position within the reader. pos: usize, /// Used so that we can restrict the cursor to the lifetime of the /// underlying byte slice. _phantom: std::marker::PhantomData<&'a [u8]>, } /// Implementation of `read_nested_*` -- generic fn read_nested_generic(b: &mut Reader, f: F) -> Result where F: FnOnce(&mut Reader) -> Result, L: Readable + Copy + Sized + TryInto, { let length: L = b.extract()?; let length: usize = length.try_into().map_err(|_| Error::BadLengthValue)?; let slice = b.take(length)?; let mut inner = Reader::from_slice(slice); let out = f(&mut inner)?; inner.should_be_exhausted()?; Ok(out) } #[cfg(test)] mod tests { #![allow(clippy::unwrap_used)] use super::*; #[test] fn bytecursor_read_ok() { let bytes = b"On a mountain halfway between Reno and Rome"; let mut bc = Reader::from_slice(&bytes[..]); assert_eq!(bc.consumed(), 0); assert_eq!(bc.remaining(), 43); assert_eq!(bc.total_len(), 43); assert_eq!(bc.take(3).unwrap(), &b"On "[..]); assert_eq!(bc.consumed(), 3); assert_eq!(bc.take_u16().unwrap(), 0x6120); assert_eq!(bc.take_u8().unwrap(), 0x6d); assert_eq!(bc.take_u64().unwrap(), 0x6f756e7461696e20); assert_eq!(bc.take_u32().unwrap(), 0x68616c66); assert_eq!(bc.consumed(), 18); assert_eq!(bc.remaining(), 25); assert_eq!(bc.total_len(), 43); assert_eq!(bc.peek(7).unwrap(), &b"way bet"[..]); assert_eq!(bc.consumed(), 18); // no change assert_eq!(bc.remaining(), 25); // no change assert_eq!(bc.total_len(), 43); // no change assert_eq!(bc.peek(7).unwrap(), &b"way bet"[..]); assert_eq!(bc.consumed(), 18); // no change this time either. bc.advance(12).unwrap(); assert_eq!(bc.consumed(), 30); assert_eq!(bc.remaining(), 13); let rem = bc.into_rest(); assert_eq!(rem, &b"Reno and Rome"[..]); // now let's try consuming right up to the end. let mut bc = Reader::from_slice(&bytes[..]); bc.advance(22).unwrap(); assert_eq!(bc.remaining(), 21); let rem = bc.take(21).unwrap(); assert_eq!(rem, &b"between Reno and Rome"[..]); assert_eq!(bc.consumed(), 43); assert_eq!(bc.remaining(), 0); // We can still take a zero-length slice. assert_eq!(bc.take(0).unwrap(), &b""[..]); } #[test] fn read_u128() { let bytes = bytes::Bytes::from(&b"irreproducibility?"[..]); // 18 bytes let mut b = Reader::from_bytes(&bytes); assert_eq!(b.take_u8().unwrap(), b'i'); assert_eq!(b.take_u128().unwrap(), 0x72726570726f6475636962696c697479); assert_eq!(b.remaining(), 1); } #[test] fn bytecursor_read_missing() { let bytes = b"1234567"; let mut bc = Reader::from_slice_for_test(&bytes[..]); assert_eq!(bc.consumed(), 0); assert_eq!(bc.remaining(), 7); assert_eq!(bc.total_len(), 7); assert_eq!(bc.take_u64(), Err(Error::new_incomplete_for_test(1))); assert_eq!(bc.take(8), Err(Error::new_incomplete_for_test(1))); assert_eq!(bc.peek(8), Err(Error::new_incomplete_for_test(1))); assert_eq!(bc.consumed(), 0); assert_eq!(bc.remaining(), 7); assert_eq!(bc.total_len(), 7); assert_eq!(bc.take_u32().unwrap(), 0x31323334); // get 4 bytes. 3 left. assert_eq!(bc.take_u32(), Err(Error::new_incomplete_for_test(1))); assert_eq!(bc.consumed(), 4); assert_eq!(bc.remaining(), 3); assert_eq!(bc.total_len(), 7); assert_eq!(bc.take_u16().unwrap(), 0x3536); // get 2 bytes. 1 left. assert_eq!(bc.take_u16(), Err(Error::new_incomplete_for_test(1))); assert_eq!(bc.consumed(), 6); assert_eq!(bc.remaining(), 1); assert_eq!(bc.total_len(), 7); assert_eq!(bc.take_u8().unwrap(), 0x37); // get 1 byte. 0 left. assert_eq!(bc.take_u8(), Err(Error::new_incomplete_for_test(1))); assert_eq!(bc.consumed(), 7); assert_eq!(bc.remaining(), 0); assert_eq!(bc.total_len(), 7); } #[test] fn advance_too_far() { let bytes = b"12345"; let mut b = Reader::from_slice_for_test(&bytes[..]); assert_eq!(b.remaining(), 5); assert_eq!(b.advance(16), Err(Error::new_incomplete_for_test(11))); assert_eq!(b.remaining(), 5); assert_eq!(b.advance(5), Ok(())); assert_eq!(b.remaining(), 0); } #[test] fn truncate() { let bytes = b"Hello universe!!!1!"; let mut b = Reader::from_slice_for_test(&bytes[..]); assert_eq!(b.take(5).unwrap(), &b"Hello"[..]); assert_eq!(b.remaining(), 14); assert_eq!(b.consumed(), 5); b.truncate(9); assert_eq!(b.remaining(), 9); assert_eq!(b.consumed(), 5); assert_eq!(b.take_u8().unwrap(), 0x20); assert_eq!(b.into_rest(), &b"universe"[..]); } #[test] fn exhaust() { let b = Reader::from_slice_for_test(&b""[..]); assert_eq!(b.should_be_exhausted(), Ok(())); let mut b = Reader::from_slice_for_test(&b"outis"[..]); assert_eq!(b.should_be_exhausted(), Err(Error::ExtraneousBytes)); b.take(4).unwrap(); assert_eq!(b.should_be_exhausted(), Err(Error::ExtraneousBytes)); b.take(1).unwrap(); assert_eq!(b.should_be_exhausted(), Ok(())); } #[test] fn take_rest() { let mut b = Reader::from_slice_for_test(b"si vales valeo"); assert_eq!(b.take(3).unwrap(), b"si "); assert_eq!(b.take_rest(), b"vales valeo"); assert_eq!(b.take_rest(), b""); } #[test] fn take_until() { let mut b = Reader::from_slice_for_test(&b"si vales valeo"[..]); assert_eq!(b.take_until(b' ').unwrap(), &b"si"[..]); assert_eq!(b.take_until(b' ').unwrap(), &b"vales"[..]); assert_eq!(b.take_until(b' '), Err(Error::new_incomplete_for_test(1))); } #[test] fn truncate_badly() { let mut b = Reader::from_slice_for_test(&b"abcdefg"[..]); b.truncate(1000); assert_eq!(b.total_len(), 7); assert_eq!(b.remaining(), 7); } #[test] fn nested_good() { let mut b = Reader::from_slice_for_test(b"abc\0\0\x04defghijkl"); assert_eq!(b.take(3).unwrap(), b"abc"); b.read_nested_u16len(|s| { assert!(s.should_be_exhausted().is_ok()); Ok(()) }) .unwrap(); b.read_nested_u8len(|s| { assert_eq!(s.take(4).unwrap(), b"defg"); assert!(s.should_be_exhausted().is_ok()); Ok(()) }) .unwrap(); assert_eq!(b.take(2).unwrap(), b"hi"); } #[test] fn nested_bad() { let mut b = Reader::from_slice_for_test(b"................"); assert_eq!( read_nested_generic::(&mut b, |_| panic!()) .err() .unwrap(), Error::BadLengthValue ); let mut b = Reader::from_slice_for_test(b"................"); assert_eq!( b.read_nested_u32len::<_, ()>(|_| panic!()).err().unwrap(), Error::new_incomplete_for_test(774778414 - (16 - 4)) ); } #[test] fn nested_inner_bad() { let mut b = Reader::from_slice_for_test(&[1, 66]); assert_eq!( b.read_nested_u8len(|b| b.take_u32()), Err(Error::MissingData), ); } #[test] fn incomplete_slice() { // Test specifically the from_possibly_incomplete_slice constructor - // ie, deliberately don't use Reader::from_slice_for_test. let mut b = Reader::from_possibly_incomplete_slice(&[]); assert_eq!(b.take_u32(), Err(Error::new_incomplete_for_test(4))); } #[test] fn extract() { // For example purposes, declare a length-then-bytes string type. #[derive(Debug)] struct LenEnc(Vec); impl Readable for LenEnc { fn take_from(b: &mut Reader<'_>) -> Result { let length = b.take_u8()?; let content = b.take(length as usize)?.into(); Ok(LenEnc(content)) } } let bytes = b"\x04this\x02is\x09sometimes\x01a\x06string!"; let mut b = Reader::from_slice_for_test(&bytes[..]); let le: LenEnc = b.extract().unwrap(); assert_eq!(&le.0[..], &b"this"[..]); let les: Vec = b.extract_n(4).unwrap(); assert_eq!(&les[3].0[..], &b"string"[..]); assert_eq!(b.remaining(), 1); // Make sure that we don't advance on a failing extract(). let le: Result = b.extract(); assert_eq!(le.unwrap_err(), Error::new_incomplete_for_test(33)); assert_eq!(b.remaining(), 1); // Make sure that we don't advance on a failing extract_n() let mut b = Reader::from_slice_for_test(&bytes[..]); assert_eq!(b.remaining(), 28); let les: Result> = b.extract_n(10); assert_eq!(les.unwrap_err(), Error::new_incomplete_for_test(33)); assert_eq!(b.remaining(), 28); } #[test] fn cursor() -> Result<()> { let alphabet = b"abcdefghijklmnopqrstuvwxyz"; let mut b = Reader::from_slice_for_test(&alphabet[..]); let c1 = b.cursor(); let _ = b.take_u16()?; let c2 = b.cursor(); let c2b = b.cursor(); b.advance(7)?; let c3 = b.cursor(); assert_eq!(b.range(c1, c2), &b"ab"[..]); assert_eq!(b.range(c2, c3), &b"cdefghi"[..]); assert_eq!(b.range(c1, c3), &b"abcdefghi"[..]); assert_eq!(b.range(c1, c1), &b""[..]); assert_eq!(b.range(c3, c1), &b""[..]); assert_eq!(c2, c2b); assert!(c1 < c2); assert!(c2 < c3); Ok(()) } #[test] fn take_all_but() -> Result<()> { let message = b"byte manipulation for fun and (non)-profit"; // Case 1: Successful, complete reader // (Can't use from_slice_for_test here: that's a possibly-incomplete reader.) let mut b = Reader::from_slice(message); assert_eq!(b.take_all_but(6)?, b"byte manipulation for fun and (non)-"); assert_eq!(b.into_rest(), b"profit"); // Case 1b: Successful, take nothing, complete reader. let mut b = Reader::from_slice(message); assert_eq!(b.take_all_but(message.len())?, b""); assert_eq!(b.into_rest(), message); // Case 1c: Successful, take everything, complete reader. let mut b = Reader::from_slice(message); assert_eq!(b.take_all_but(0)?, message); assert_eq!(b.into_rest(), b""); // Case 2: Unsuccessful, complete reader let mut b = Reader::from_slice(message); assert!(matches!( b.take_all_but(message.len() + 1), Err(Error::MissingData) )); // Case 3: Anything, incomplete reader. let mut b = Reader::from_possibly_incomplete_slice(message); assert!(matches!(b.take_all_but(6), Err(Error::Bug(_)))); Ok(()) } }