Struct tor_bytes::reader::Reader

source ·
pub struct Reader<'a> {
    b: &'a [u8],
    off: usize,
}
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 r = Reader::from_slice(&msg[..]);
// Multi-byte values are always big-endian.
assert_eq!(r.take_u32()?, 0x12345);
assert_eq!(r.take_u8()?, 0x22);

// You can check on the length of the message...
assert_eq!(r.total_len(), 8);
assert_eq!(r.consumed(), 5);
assert_eq!(r.remaining(), 3);
// then skip over a some bytes...
r.advance(3)?;
// ... and check that the message is really exhausted.
r.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 r = Reader::from_slice(&msg[..]);

let tp: u16 = r.extract()?;
let ip: Ipv4Addr = r.extract()?;
assert_eq!(tp, 4);
assert_eq!(ip, Ipv4Addr::LOCALHOST);

Fields§

§b: &'a [u8]

The underlying slice that we’re reading from

§off: usize

The next position in the slice that we intend to read from.

Implementations§

source§

impl<'a> Reader<'a>

source

pub fn from_slice(slice: &'a [u8]) -> Self

Construct a new Reader from a slice of bytes.

source

pub fn from_bytes(b: &'a Bytes) -> Self

Construct a new Reader from a ‘Bytes’ object.

source

pub fn total_len(&self) -> usize

Return the total length of the slice in this reader, including consumed bytes and remaining bytes.

source

pub fn remaining(&self) -> usize

Return the total number of bytes in this reader that have not yet been read.

source

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.

source

pub fn consumed(&self) -> usize

Return the total number of bytes in this reader that have already been read.

source

pub fn advance(&mut self, n: usize) -> Result<()>

Skip n bytes from the reader.

Returns Ok on success. Returns Err(Error::Truncated) if there were not enough bytes to skip.

source

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.

source

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.

source

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, returns Err(Error::Truncated).

source

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, returns Err(Error::Truncated).

§Example
use tor_bytes::{Reader,Result};
let m = b"Hello World";
let mut r = Reader::from_slice(m);
assert_eq!(r.take(5)?, b"Hello");
assert_eq!(r.take_u8()?, 0x20);
assert_eq!(r.take(5)?, b"World");
r.should_be_exhausted()?;
source

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 r = Reader::from_slice(m);
r.take_into(&mut v1[..])?;
assert_eq!(r.take_u8()?, b' ');
r.take_into(&mut v2[..])?;
assert_eq!(&v1[..], b"Hello");
assert_eq!(&v2[..], b"world");
r.should_be_exhausted()?;
source

pub fn take_u8(&mut self) -> Result<u8>

Try to consume and return a u8 from this reader.

source

pub fn take_u16(&mut self) -> Result<u16>

Try to consume and return a big-endian u16 from this reader.

source

pub fn take_u32(&mut self) -> Result<u32>

Try to consume and return a big-endian u32 from this reader.

source

pub fn take_u64(&mut self) -> Result<u64>

Try to consume and return a big-endian u64 from this reader.

source

pub fn take_u128(&mut self) -> Result<u128>

Try to consume and return a big-endian u128 from this reader.

source

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. Returns Err(Error::Truncated) 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 r = Reader::from_slice(m);
assert_eq!(r.take_until(0)?, b"Hello");
assert_eq!(r.into_rest(), b"wrld");
source

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.

source

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.

source

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.

source

pub fn read_nested_u8len<F, T>(&mut self, f: F) -> Result<T>
where F: FnOnce(&mut Reader<'_>) -> 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.

source

pub fn read_nested_u16len<F, T>(&mut self, f: F) -> Result<T>
where F: FnOnce(&mut Reader<'_>) -> Result<T>,

Start decoding something with a u16 length field

source

pub fn read_nested_u32len<F, T>(&mut self, f: F) -> Result<T>
where F: FnOnce(&mut Reader<'_>) -> Result<T>,

Start decoding something with a u32 length field

source

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.

source

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.

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§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> IntoEither for T

source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts 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 more
source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts 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
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more