pub struct Reader<'a> { /* private fields */ }
Expand description
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()?;
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);
Implementations§
source§impl<'a> Reader<'a>
impl<'a> Reader<'a>
sourcepub fn from_slice(slice: &'a [u8]) -> Self
pub fn from_slice(slice: &'a [u8]) -> Self
Construct a new Reader from a slice of bytes.
In tests, prefer Reader::from_slice_for_test
.
sourcepub fn from_possibly_incomplete_slice(slice: &'a [u8]) -> Self
pub fn from_possibly_incomplete_slice(slice: &'a [u8]) -> Self
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
, and so on,
will return Error::Incomplete
if the message is incomplete,
and reading more would help.
(This is achieved via 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 misformed messages
being incorrectly reported as Incomplete
.
sourcepub fn from_slice_for_test(slice: &'a [u8]) -> Self
pub fn from_slice_for_test(slice: &'a [u8]) -> Self
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.
sourcepub fn from_bytes(b: &'a Bytes) -> Self
pub fn from_bytes(b: &'a Bytes) -> Self
Construct a new Reader from a ‘Bytes’ object.
sourcepub fn total_len(&self) -> usize
pub fn total_len(&self) -> usize
Return the total length of the slice in this reader, including consumed bytes and remaining bytes.
sourcepub fn remaining(&self) -> usize
pub fn remaining(&self) -> usize
Return the total number of bytes in this reader that have not yet been read.
sourcepub fn into_rest(self) -> &'a [u8] ⓘ
pub fn into_rest(self) -> &'a [u8] ⓘ
Consume this reader, and return a slice containing the remaining bytes from its slice that it did not consume.
sourcepub fn consumed(&self) -> usize
pub fn consumed(&self) -> usize
Return the total number of bytes in this reader that have already been read.
sourcepub fn advance(&mut self, n: usize) -> Result<()>
pub fn advance(&mut self, n: usize) -> Result<()>
Skip n
bytes from the reader.
Returns Ok on success. Throws MissingData or Incomplete if there were not enough bytes to skip.
sourcepub fn should_be_exhausted(&self) -> Result<()>
pub fn should_be_exhausted(&self) -> Result<()>
Check whether this reader is exhausted (out of bytes).
Return Ok if it is, and Err(Error::ExtraneousBytes) if there were extra bytes.
sourcepub fn truncate(&mut self, n: usize)
pub fn truncate(&mut self, n: usize)
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.
sourcepub fn peek(&self, n: usize) -> Result<&'a [u8]>
pub fn peek(&self, n: usize) -> Result<&'a [u8]>
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.
sourcepub fn take(&mut self, n: usize) -> Result<&'a [u8]>
pub fn take(&mut self, n: usize) -> Result<&'a [u8]>
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()?;
sourcepub fn take_into(&mut self, buf: &mut [u8]) -> Result<()>
pub fn take_into(&mut self, buf: &mut [u8]) -> Result<()>
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()?;
sourcepub fn take_u16(&mut self) -> Result<u16>
pub fn take_u16(&mut self) -> Result<u16>
Try to consume and return a big-endian u16 from this reader.
sourcepub fn take_u32(&mut self) -> Result<u32>
pub fn take_u32(&mut self) -> Result<u32>
Try to consume and return a big-endian u32 from this reader.
sourcepub fn take_u64(&mut self) -> Result<u64>
pub fn take_u64(&mut self) -> Result<u64>
Try to consume and return a big-endian u64 from this reader.
sourcepub fn take_u128(&mut self) -> Result<u128>
pub fn take_u128(&mut self) -> Result<u128>
Try to consume and return a big-endian u128 from this reader.
sourcepub fn take_until(&mut self, term: u8) -> Result<&'a [u8]>
pub fn take_until(&mut self, term: u8) -> Result<&'a [u8]>
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");
sourcepub fn take_rest(&mut self) -> &'a [u8] ⓘ
pub fn take_rest(&mut self) -> &'a [u8] ⓘ
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.
sourcepub fn take_all_but(&mut self, n: usize) -> Result<&'a [u8]>
pub fn take_all_but(&mut self, n: usize) -> Result<&'a [u8]>
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");
sourcepub fn extract<E: Readable>(&mut self) -> Result<E>
pub fn extract<E: Readable>(&mut self) -> Result<E>
Try to decode and remove a Readable from this reader, using its take_from() method.
On failure, consumes nothing.
sourcepub fn extract_n<E: Readable>(&mut self, n: usize) -> Result<Vec<E>>
pub fn extract_n<E: Readable>(&mut self, n: usize) -> Result<Vec<E>>
Try to decode and remove n
Readables from this reader, using the
Readable’s take_from() method.
On failure, consumes nothing.
sourcepub fn read_nested_u8len<F, T>(&mut self, f: F) -> Result<T>
pub fn read_nested_u8len<F, T>(&mut self, f: F) -> Result<T>
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.
sourcepub fn read_nested_u16len<F, T>(&mut self, f: F) -> Result<T>
pub fn read_nested_u16len<F, T>(&mut self, f: F) -> Result<T>
Start decoding something with a u16 length field
sourcepub fn read_nested_u32len<F, T>(&mut self, f: F) -> Result<T>
pub fn read_nested_u32len<F, T>(&mut self, f: F) -> Result<T>
Start decoding something with a u32 length field
sourcepub fn cursor(&self) -> Cursor<'a>
pub fn cursor(&self) -> Cursor<'a>
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.
sourcepub fn range(&self, start: Cursor<'a>, end: Cursor<'a>) -> &'a [u8] ⓘ
pub fn range(&self, start: Cursor<'a>, end: Cursor<'a>) -> &'a [u8] ⓘ
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.
sourcepub fn incomplete_error(&self, deficit: NonZeroUsize) -> Error
pub fn incomplete_error(&self, deficit: NonZeroUsize) -> Error
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
.
Auto Trait Implementations§
impl<'a> Freeze for Reader<'a>
impl<'a> RefUnwindSafe for Reader<'a>
impl<'a> Send for Reader<'a>
impl<'a> Sync for Reader<'a>
impl<'a> Unpin for Reader<'a>
impl<'a> UnwindSafe for Reader<'a>
Blanket Implementations§
§impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
§impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
source§impl<T> IntoEither for T
impl<T> IntoEither for T
source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left
is true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moresource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left(&self)
returns true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read more