blob: 62f0bd1ae007c6c06060d044438cf53f41df69bb [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//! Parsing and serialization of (network) packets.
//!
//! `packet` is a library to help with the parsing and serialization of nested
//! packets. Network packets are the most common use case, but it supports any
//! packet structure with headers, footers, and nesting.
//!
//! # Model
//!
//! The core components of `packet` are the various buffer traits (`XxxBuffer`
//! and `XxxBufferMut`). A buffer is a byte buffer with a prefix, a body, and a
//! suffix. The size of the buffer is referred to as its "capacity", and the
//! size of the body is referred to as its "length". Depending on which traits
//! are implemented, the body of the buffer may be able to shrink or grow as
//! allowed by the capacity as packets are parsed or serialized.
//!
//! ## Parsing
//!
//! When parsing packets, the body of the buffer stores the next packet to be
//! parsed. When a packet is parsed from the buffer, any headers, footers, and
//! padding are "consumed" from the buffer. Thus, after a packet has been
//! parsed, the body of the buffer is equal to the body of the packet, and the
//! next call to `parse` will pick up where the previous call left off, parsing
//! the next encapsulated packet.
//!
//! Packet objects - the Rust objects which are the result of a successful
//! parsing operation - are advised to simply keep references into the buffer
//! for the header, footer, and body. This avoids any unnecessary copying.
//!
//! For example, consider the following packet structure, in which a TCP segment
//! is encapsulated in an IPv4 packet, which is encapsulated in an Ethernet
//! frame. In this example, we omit the Ethernet Frame Check Sequence (FCS)
//! footer. If there were any footers, they would be treated the same as
//! headers, except that they would be consumed from the end and working towards
//! the beginning, as opposed to headers, which are consumed from the beginning
//! and working towards the end.
//!
//! Also note that, in order to satisfy Ethernet's minimum body size
//! requirement, padding is added after the IPv4 packet. The IPv4 packet and
//! padding together are considered the body of the Ethernet frame. If we were
//! to include the Ethernet FCS footer in this example, it would go after the
//! padding.
//!
//! ```text
//! |-------------------------------------|++++++++++++++++++++|-----| TCP segment
//! |-----------------|++++++++++++++++++++++++++++++++++++++++|-----| IPv4 packet
//! |++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++| Ethernet frame
//!
//! |-----------------|-------------------|--------------------|-----|
//! Ethernet header IPv4 header TCP segment Padding
//! ```
//!
//! At first, the buffer's body would be equal to the bytes of the Ethernet
//! frame (although depending on how the buffer was initialized, it might have
//! extra capacity in addition to the body):
//!
//! ```text
//! |-------------------------------------|++++++++++++++++++++|-----| TCP segment
//! |-----------------|++++++++++++++++++++++++++++++++++++++++|-----| IPv4 packet
//! |++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++| Ethernet frame
//!
//! |-----------------|-------------------|--------------------|-----|
//! Ethernet header IPv4 header TCP segment Padding
//!
//! |----------------------------------------------------------------|
//! Buffer Body
//! ```
//!
//! First, the Ethernet frame is parsed. This results in a hypothetical
//! `EthernetFrame` object (this library does not provide any concrete parsing
//! implementations) with references into the buffer, and updates the body of
//! the buffer to be equal to the body of the Ethernet frame:
//!
//! ```text
//! |-------------------------------------|++++++++++++++++++++|-----| TCP segment
//! |-----------------|++++++++++++++++++++++++++++++++++++++++|-----| IPv4 packet
//! |++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++| Ethernet frame
//!
//! |-----------------|----------------------------------------------|
//! Ethernet header Ethernet body
//! | |
//! +--------------------------+ |
//! | |
//! EthernetFrame { header, body }
//!
//! |-----------------|----------------------------------------------|
//! buffer prefix buffer body
//! ```
//!
//! The `EthernetFrame` object mutably borrows the buffer. So long as it exists,
//! the buffer cannot be used directly (although the `EthernetFrame` object may
//! be used to access or modify the contents of the buffer). In order to parse
//! the body of the Ethernet frame, we have to drop the `EthernetFrame` object
//! so that we can call methods on the buffer again. \[1\]
//!
//! After dropping the `EthernetFrame` object, the IPv4 packet is parsed. Recall
//! that the Ethernet body contains both the IPv4 packet and some padding. Since
//! IPv4 packets encode their own length, the IPv4 packet parser is able to
//! detect that some of the bytes it's operating on are padding bytes. It is the
//! parser's responsibility to consume and discard these bytes so that they are
//! not erroneously treated as part of the IPv4 packet's body in subsequent
//! parsings.
//!
//! This parsing results in a hypothetical `Ipv4Packet` object with references
//! into the buffer, and updates the body of the buffer to be equal to the body
//! of the IPv4 packet:
//!
//! ```text
//! |-------------------------------------|++++++++++++++++++++|-----| TCP segment
//! |-----------------|++++++++++++++++++++++++++++++++++++++++|-----| IPv4 packet
//! |++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++| Ethernet frame
//!
//! |-----------------|-------------------|--------------------|-----|
//! IPv4 header IPv4 body
//! | |
//! +-----------+ |
//! | |
//! Ipv4Packet { header, body }
//!
//! |-------------------------------------|--------------------|-----|
//! buffer prefix buffer body buffer suffix
//! ```
//!
//! We can continue this process as long as we like, repeatedly parsing
//! subsequent packet bodies until there are no more packets to parse.
//!
//! \[1\] It is also possible to treat the `EthernetFrame`'s `body` field as a
//! buffer and parse from it directly. However, this has the disadvantage that
//! if parsing is spread across multiple functions, the functions which parse
//! the inner packets only see part of the buffer, and so if they wish to later
//! re-use the buffer for serializing new packets (see the "Serialization"
//! section of this documentation), they are limited to doing so in a smaller
//! buffer, making it more likely that a new buffer will need to be allocated.
//!
//! ## Serialization
//!
//! In this section, we will illustrate serialization using the same packet
//! structure that was used to illustrate parsing - a TCP segment in an IPv4
//! packet in an Ethernet frame.
//!
//! Serialization comprises two tasks:
//! - First, given a buffer with sufficient capacity, and part of the packet
//! already serialized, serialize the next layer of the packet. For example,
//! given a buffer with a TCP segment already serialized in it, serialize the
//! IPv4 header, resulting in an IPv4 packet containing a TCP segment.
//! - Second, given a description of a nested sequence of packets, figure out
//! the constraints that a buffer must satisfy in order to be able to fit the
//! entire sequence, and allocate a buffer which satisfies those constraints.
//! This buffer is then used to serialize one layer at a time, as described in
//! the previous bullet.
//!
//! ### Serializing into a buffer
//!
//! The [`PacketBuilder`] trait is implemented by types which are capable of
//! serializing a new layer of a packet into an existing buffer. For example, we
//! might define an `Ipv4PacketBuilder` type, which describes the source IP
//! address, destination IP address, and any other metadata required to generate
//! the header of an IPv4 packet. Importantly, a `PacketBuilder` does *not*
//! define any encapsulated packets. In order to construct a TCP segment in an
//! IPv4 packet, we would need a separate `TcpSegmentBuilder` to describe the
//! TCP segment.
//!
//! A `PacketBuilder` exposes the number of bytes it requires for headers,
//! footers, and minimum and maximum body lengths via the `constraints` method.
//! It serializes via the `serialize` method.
//!
//! In order to serialize a `PacketBuilder`, a [`SerializeTarget`] must first be
//! constructed. A `SerializeTarget` is a view into a buffer used for
//! serialization, and it is initialized with the proper number of bytes for the
//! header, footer, and body. The number of bytes required for these is
//! discovered through calls to the `PacketBuilder`'s `constraints` method.
//!
//! The `PacketBuilder`'s `serialize` method serializes the headers and footers
//! of the packet into the buffer. It expects that the `SerializeTarget` is
//! initialized with a body equal to the body which will be encapsulated. For
//! example, imagine that we are trying to serialize a TCP segment in an IPv4
//! packet in an Ethernet frame, and that, so far, we have only serialized the
//! TCP segment:
//!
//! ```text
//! |-------------------------------------|++++++++++++++++++++|-----| TCP segment
//! |-----------------|++++++++++++++++++++++++++++++++++++++++|-----| IPv4 packet
//! |++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++| Ethernet frame
//!
//! |-------------------------------------|--------------------|-----|
//! TCP segment
//!
//! |-------------------------------------|--------------------|-----|
//! buffer prefix buffer body buffer suffix
//! ```
//!
//! Note that the buffer's body is currently equal to the TCP segment, and the
//! contents of the body are already initialized to the segment's contents.
//!
//! Given an `Ipv4PacketBuilder`, we call the appropriate methods to discover
//! that it requires 20 bytes for its header. Thus, we modify the buffer by
//! extending the body by 20 bytes, and constructing a `SerializeTarget` whose
//! header references the newly-added 20 bytes, and whose body references the
//! old contents of the body, corresponding to the TCP segment.
//!
//! ```text
//! |-------------------------------------|++++++++++++++++++++|-----| TCP segment
//! |-----------------|++++++++++++++++++++++++++++++++++++++++|-----| IPv4 packet
//! |++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++| Ethernet frame
//!
//! |-----------------|-------------------|--------------------|-----|
//! IPv4 header IPv4 body
//! | |
//! +-----------+ |
//! | |
//! SerializeTarget { header, body }
//!
//! |-----------------|----------------------------------------|-----|
//! buffer prefix buffer body buffer suffix
//! ```
//!
//! We then pass the `SerializeTarget` to a call to the `Ipv4PacketBuilder`'s
//! `serialize` method, and it serializes the IPv4 header in the space provided.
//! When the call to `serialize` returns, the `SerializeTarget` and
//! `Ipv4PacketBuilder` have been discarded, and the buffer's body is now equal
//! to the bytes of the IPv4 packet.
//!
//! ```text
//! |-------------------------------------|++++++++++++++++++++|-----| TCP segment
//! |-----------------|++++++++++++++++++++++++++++++++++++++++|-----| IPv4 packet
//! |++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++| Ethernet frame
//!
//! |-----------------|----------------------------------------|-----|
//! IPv4 packet
//!
//! |-----------------|----------------------------------------|-----|
//! buffer prefix buffer body buffer suffix
//! ```
//!
//! Now, we are ready to repeat the same process with the Ethernet layer of the
//! packet.
//!
//! ### Constructing a buffer for serialization
//!
//! Now that we know how, given a buffer with a subset of a packet serialized
//! into it, we can serialize the next layer of the packet, we need to figure
//! out how to construct such a buffer in the first place.
//!
//! The primary challenge here is that we need to be able to commit to what
//! we're going to serialize before we actually serialize it. For example,
//! consider sending a TCP segment to the network. From the perspective of the
//! TCP module of our code, we don't know how large the buffer needs to be
//! because don't know what packet layers our TCP segment will be encapsulated
//! inside of. If the IP layer decides to route our segment over an Ethernet
//! link, then we'll need to have a buffer large enough for a TCP segment in an
//! IPv4 packet in an Ethernet segment. If, on the other hand, the IP layer
//! decides to route our segment through a GRE tunnel, then we'll need to have a
//! buffer large enough for a TCP segment in an IPv4 packet in a GRE packet in
//! an IP packet in an Ethernet segment.
//!
//! We accomplish this commit-before-serializing via the [`Serializer`] trait. A
//! `Serializer` describes a packet which can be serialized in the future, but
//! which has not yet been serialized. Unlike a `PacketBuilder`, a `Serializer`
//! describes all layers of a packet up to a certain point. For example, a
//! `Serializer` might describe a TCP segment, or it might describe a TCP
//! segment in an IP packet, or it might describe a TCP segment in an IP packet
//! in an Ethernet frame, etc.
//!
//! #### Constructing a `Serializer`
//!
//! `Serializer`s are recursive - a `Serializer` combined with a `PacketBuilder`
//! yields a new `Serializer` which describes encapsulating the original
//! `Serializer` in a new packet layer. For example, a `Serializer` describing a
//! TCP segment combined with an `Ipv4PacketBuilder` yields a `Serializer` which
//! describes a TCP segment in an IPv4 packet. Concretely, given a `Serializer`,
//! `s`, and a `PacketBuilder`, `b`, a new `Serializer` can be constructed by
//! calling `s.encapsulate(b)`. The [`Serializer::encapsulate`] method consumes
//! both the `Serializer` and the `PacketBuilder` by value, and returns a new
//! `Serializer`.
//!
//! Note that, while `Serializer`s are passed around by value, they are only as
//! large in memory as the `PacketBuilder`s they're constructed from, and those
//! should, in most cases, be quite small. If size is a concern, the
//! `PacketBuilder` trait can be implemented for a reference type (e.g.,
//! `&Ipv4PacketBuilder`), and references passed around instead of values.
//!
//! #### Constructing a buffer from a `Serializer`
//!
//! If `Serializer`s are constructed by starting at the innermost packet layer
//! and working outwards, adding packet layers, then in order to turn a
//! `Serializer` into a buffer, they are consumed by starting at the outermost
//! packet layer and working inwards.
//!
//! In order to construct a buffer, the [`Serializer::serialize`] method is
//! provided. It takes a [`NestedPacketBuilder`], which describes one or more
//! encapsulating packet layers. For example, when serializing a TCP segment in
//! an IP packet in an Ethernet frame, the `serialize` call on the IP packet
//! `Serializer` would be given a `NestedPacketBuilder` describing the Ethernet
//! frame. This call would then compute a new `NestedPacketBuilder` describing
//! the combined IP packet and Ethernet frame, and would pass this to a call to
//! `serialize` on the TCP segment `Serializer`.
//!
//! When the innermost call to `serialize` is reached, it is that call's
//! responsibility to produce a buffer which satisfies the constraints passed to
//! it, and to initialize that buffer's body with the contents of its packet.
//! For example, the TCP segment `Serializer` from the preceding example would
//! need to produce a buffer with 38 bytes of prefix for the IP and Ethernet
//! headers, and whose body was initialized to the bytes of the TCP segment.
//!
//! We can now see how `Serializer`s and `PacketBuilder`s compose - the buffer
//! returned from a call to `serialize` satisfies the requirements of the
//! `PacketBuilder::serialize` method - its body is initialized to the packet to
//! be encapsulated, and enough prefix and suffix space exist to serialize this
//! layer's header and footer. For example, the call to `Serializer::serialize`
//! on the TCP segment serializer would return a buffer with 38 bytes of prefix
//! and a body initialized to the bytes of the TCP segment. The call to
//! `Serializer::serialize` on the IP packet would then pass this buffer to a
//! call to `PacketBuilder::serialize` on its `Ipv4PacketBuilder`, resulting in
//! a buffer with 18 bytes of prefix and a body initialized to the bytes of the
//! entire IP packet. This buffer would then be suitable to return from the call
//! to `Serializer::serialize`, allowing the Ethernet layer to continue
//! operating on the buffer, and so on.
//!
//! Note in particular that, throughout this entire process of constructing
//! `Serializer`s and `PacketBuilder`s and then consuming them, a buffer is only
//! allocated once, and each byte of the packet is only serialized once. No
//! temporary buffers or copying between buffers are required.
//!
//! #### Reusing buffers
//!
//! Another important property of the `Serializer` trait is that it can be
//! implemented by buffers. Since buffers contain prefixes, bodies, and
//! suffixes, and since the `Serializer::serialize` method consumes the
//! `Serializer` by value and returns a buffer by value, a buffer is itself a
//! valid `Serializer`. When `serialize` is called, so long as it already
//! satisfies the constraints requested, it can simply return itself by value.
//! If the constraints are not satisfied, it may need to produce a different
//! buffer through some user-defined mechanism (see the [`BufferProvider`] trait
//! for details).
//!
//! This allows existing buffers to be reused in many cases. For example,
//! consider receiving a packet in a buffer, and then responding to that packet
//! with a new packet. The buffer that the original packet was stored in can be
//! used to serialize the new packet, avoiding any unnecessary allocation.
/// Emits method impls for [`FragmentedBuffer`] which assume that the type is
/// a contiguous buffer which implements [`AsRef`].
macro_rules! fragmented_buffer_method_impls {
() => {
fn len(&self) -> usize {
self.as_ref().len()
}
fn with_bytes<R, F>(&self, f: F) -> R
where
F: for<'macro_a, 'macro_b> FnOnce(FragmentedBytes<'macro_a, 'macro_b>) -> R,
{
let mut bs = [AsRef::<[u8]>::as_ref(self)];
f(FragmentedBytes::new(&mut bs))
}
fn to_flattened_vec(&self) -> Vec<u8> {
self.as_ref().to_vec()
}
};
}
/// Emits method impls for [`FragmentedBufferMut`] which assume that the type is
/// a contiguous buffer which implements [`AsMut`].
macro_rules! fragmented_buffer_mut_method_impls {
() => {
fn with_bytes_mut<R, F>(&mut self, f: F) -> R
where
F: for<'macro_a, 'macro_b> FnOnce(FragmentedBytesMut<'macro_a, 'macro_b>) -> R,
{
let mut bs = [AsMut::<[u8]>::as_mut(self)];
f(FragmentedBytesMut::new(&mut bs))
}
fn zero_range<R>(&mut self, range: R)
where
R: RangeBounds<usize>,
{
let len = FragmentedBuffer::len(self);
let range = crate::canonicalize_range(len, &range);
crate::zero(&mut self.as_mut()[range.start..range.end]);
}
fn copy_within<R: RangeBounds<usize>>(&mut self, src: R, dest: usize) {
self.as_mut().copy_within(src, dest);
}
};
}
mod fragmented;
pub mod records;
pub mod serialize;
mod util;
pub use crate::fragmented::*;
pub use crate::serialize::*;
pub use crate::util::*;
use std::cmp;
use std::convert::Infallible as Never;
use std::mem;
use std::ops::{Bound, Range, RangeBounds};
use zerocopy::{AsBytes, ByteSlice, ByteSliceMut, FromBytes, NoCell, Ref, Unaligned};
/// A buffer that may be fragmented in multiple parts which are discontiguous in
/// memory.
pub trait FragmentedBuffer {
/// Gets the total length, in bytes, of this `FragmentedBuffer`.
fn len(&self) -> usize;
/// Returns `true` if this `FragmentedBuffer` is empty.
fn is_empty(&self) -> bool {
self.len() == 0
}
/// Invokes a callback on a view into this buffer's contents as
/// [`FragmentedBytes`].
fn with_bytes<R, F>(&self, f: F) -> R
where
F: for<'a, 'b> FnOnce(FragmentedBytes<'a, 'b>) -> R;
/// Returns a flattened version of this buffer, copying its contents into a
/// [`Vec`].
fn to_flattened_vec(&self) -> Vec<u8> {
self.with_bytes(|b| b.to_flattened_vec())
}
}
/// A [`FragmentedBuffer`] with mutable access to its contents.
pub trait FragmentedBufferMut: FragmentedBuffer {
/// Invokes a callback on a mutable view into this buffer's contents as
/// [`FragmentedBytesMut`].
fn with_bytes_mut<R, F>(&mut self, f: F) -> R
where
F: for<'a, 'b> FnOnce(FragmentedBytesMut<'a, 'b>) -> R;
/// Sets all bytes in `range` to zero.
///
/// # Panics
///
/// Panics if the provided `range` is not within the bounds of this
/// `FragmentedBufferMut`, or if the range is nonsensical (the end precedes
/// the start).
fn zero_range<R>(&mut self, range: R)
where
R: RangeBounds<usize>,
{
let len = self.len();
let range = canonicalize_range(len, &range);
self.with_bytes_mut(|mut b| {
zero_iter(b.iter_mut().skip(range.start).take(range.end - range.start))
})
}
/// Copies elements from one part of the `FragmentedBufferMut` to another
/// part of itself.
///
/// `src` is the range within `self` to copy from. `dst` is the starting
/// index of the range within `self` to copy to, which will have the same
/// length as `src`. The two ranges may overlap. The ends of the two ranges
/// must be less than or equal to `self.len()`.
///
/// # Panics
///
/// Panics if either the source or destination range is out of bounds, or if
/// `src` is nonsensical (its end precedes its start).
fn copy_within<R: RangeBounds<usize>>(&mut self, src: R, dst: usize) {
self.with_bytes_mut(|mut b| b.copy_within(src, dst));
}
/// Copies all the bytes from another `FragmentedBuffer` `other` into
/// `self`.
///
/// # Panics
///
/// Panics if `self.len() != other.len()`.
fn copy_from<B: FragmentedBuffer>(&mut self, other: &B) {
self.with_bytes_mut(|dst| {
other.with_bytes(|src| {
let dst = dst.try_into_contiguous();
let src = src.try_into_contiguous();
match (dst, src) {
(Ok(dst), Ok(src)) => {
dst.copy_from_slice(src);
}
(Ok(dst), Err(src)) => {
src.copy_into_slice(dst);
}
(Err(mut dst), Ok(src)) => {
dst.copy_from_slice(src);
}
(Err(mut dst), Err(src)) => {
dst.copy_from(&src);
}
}
});
});
}
}
/// A buffer that is contiguous in memory.
///
/// If the implementing type is a buffer which exposes a prefix and a suffix,
/// the [`AsRef`] implementation provides access only to the body. If [`AsMut`]
/// is also implemented, it must provide access to the same bytes as [`AsRef`].
pub trait ContiguousBuffer: FragmentedBuffer + AsRef<[u8]> {}
/// A mutable buffer that is contiguous in memory.
///
/// If the implementing type is a buffer which exposes a prefix and a suffix,
/// the [`AsMut`] implementation provides access only to the body.
///
/// `ContiguousBufferMut` is shorthand for `ContiguousBuffer +
/// FragmentedBufferMut + AsMut<[u8]>`.
pub trait ContiguousBufferMut: ContiguousBuffer + FragmentedBufferMut + AsMut<[u8]> {}
impl<B: ContiguousBuffer + FragmentedBufferMut + AsMut<[u8]>> ContiguousBufferMut for B {}
/// A buffer that can reduce its size.
///
/// A `ShrinkBuffer` is a buffer that can be reduced in size without the
/// guarantee that the prefix or suffix will be retained. This is typically
/// sufficient for parsing, but not for serialization.
///
/// # Notable implementations
///
/// `ShrinkBuffer` is implemented for byte slices - `&[u8]` and `&mut [u8]`.
/// These types do not implement [`GrowBuffer`]; once bytes are consumed from
/// their bodies, those bytes are discarded and cannot be recovered.
pub trait ShrinkBuffer: FragmentedBuffer {
/// Shrinks the front of the body towards the end of the buffer.
///
/// `shrink_front` consumes the `n` left-most bytes of the body, and adds
/// them to the prefix.
///
/// # Panics
///
/// Panics if `n` is larger than the body.
fn shrink_front(&mut self, n: usize);
/// Shrinks the buffer to be no larger than `len` bytes, consuming from the
/// front.
///
/// `shrink_front_to` consumes as many of the left-most bytes of the body as
/// necessary to ensure that the buffer is no longer than `len` bytes. It
/// adds any bytes consumed to the prefix. If the body is already not longer
/// than `len` bytes, `shrink_front_to` does nothing.
fn shrink_front_to(&mut self, len: usize) {
let old_len = self.len();
let new_len = cmp::min(old_len, len);
self.shrink_front(old_len - new_len);
}
/// Shrinks the back of the body towards the beginning of the buffer.
///
/// `shrink_back` consumes the `n` right-most bytes of the body, and adds
/// them to the suffix.
///
/// # Panics
///
/// Panics if `n` is larger than the body.
fn shrink_back(&mut self, n: usize);
/// Shrinks the buffer to be no larger than `len` bytes, consuming from the
/// back.
///
/// `shrink_back_to` consumes as many of the right-most bytes of the body as
/// necessary to ensure that the buffer is no longer than `len` bytes.
/// It adds any bytes consumed to the suffix. If the body is already no
/// longer than `len` bytes, `shrink_back_to` does nothing.
fn shrink_back_to(&mut self, len: usize) {
let old_len = self.len();
let new_len = cmp::min(old_len, len);
self.shrink_back(old_len - new_len);
}
/// Shrinks the body.
///
/// `shrink` shrinks the body to be equal to `range` of the previous body.
/// Any bytes preceding the range are added to the prefix, and any bytes
/// following the range are added to the suffix.
///
/// # Panics
///
/// Panics if `range` is out of bounds of the body, or if the range
/// is nonsensical (the end precedes the start).
fn shrink<R: RangeBounds<usize>>(&mut self, range: R) {
let len = self.len();
let range = canonicalize_range(len, &range);
self.shrink_front(range.start);
self.shrink_back(len - range.end);
}
}
/// A byte buffer used for parsing.
///
/// A `ParseBuffer` is a [`ContiguousBuffer`] that can shrink in size.
///
/// While a `ParseBuffer` allows the ranges covered by its prefix, body, and
/// suffix to be modified, it only provides immutable access to their contents.
/// For mutable access, see [`ParseBufferMut`].
///
/// # Notable implementations
///
/// `ParseBuffer` is implemented for byte slices - `&[u8]` and `&mut [u8]`.
/// These types do not implement [`GrowBuffer`]; once bytes are consumed from
/// their bodies, those bytes are discarded and cannot be recovered.
pub trait ParseBuffer: ShrinkBuffer + ContiguousBuffer {
/// Parses a packet from the body.
///
/// `parse` parses a packet from the body by invoking [`P::parse`] on a
/// [`BufferView`] into this buffer. Any bytes consumed from the
/// `BufferView` are also consumed from the body, and added to the prefix or
/// suffix. After `parse` has returned, the buffer's body will contain only
/// those bytes which were not consumed by the call to `P::parse`.
///
/// See the [`BufferView`] and [`ParsablePacket`] documentation for more
/// details.
///
/// [`P::parse`]: ParsablePacket::parse
fn parse<'a, P: ParsablePacket<&'a [u8], ()>>(&'a mut self) -> Result<P, P::Error> {
self.parse_with(())
}
/// Parses a packet with arguments.
///
/// `parse_with` is like [`parse`], but it accepts arguments to pass to
/// [`P::parse`].
///
/// [`parse`]: ParseBuffer::parse
/// [`P::parse`]: ParsablePacket::parse
fn parse_with<'a, ParseArgs, P: ParsablePacket<&'a [u8], ParseArgs>>(
&'a mut self,
args: ParseArgs,
) -> Result<P, P::Error>;
}
/// A [`ParseBuffer`] which provides mutable access to its contents.
///
/// While a [`ParseBuffer`] allows the ranges covered by its prefix, body, and
/// suffix to be modified, it only provides immutable access to their contents.
/// A `ParseBufferMut`, on the other hand, provides mutable access to the
/// contents of its prefix, body, and suffix.
///
/// # Notable implementations
///
/// `ParseBufferMut` is implemented for mutable byte slices - `&mut [u8]`.
/// Mutable byte slices do not implement [`GrowBuffer`] or [`GrowBufferMut`];
/// once bytes are consumed from their bodies, those bytes are discarded and
/// cannot be recovered.
pub trait ParseBufferMut: ParseBuffer + ContiguousBufferMut {
/// Parses a mutable packet from the body.
///
/// `parse_mut` is like [`ParseBuffer::parse`], but instead of calling
/// [`P::parse`] on a [`BufferView`], it calls [`P::parse_mut`] on a
/// [`BufferViewMut`]. The effect is that the parsed packet can contain
/// mutable references to the buffer. This can be useful if you want to
/// modify parsed packets in-place.
///
/// Depending on the implementation of [`P::parse_mut`], the contents
/// of the buffer may be modified during parsing.
///
/// See the [`BufferViewMut`] and [`ParsablePacket`] documentation for more
/// details.
///
/// [`P::parse`]: ParsablePacket::parse
/// [`P::parse_mut`]: ParsablePacket::parse_mut
fn parse_mut<'a, P: ParsablePacket<&'a mut [u8], ()>>(&'a mut self) -> Result<P, P::Error> {
self.parse_with_mut(())
}
/// Parses a mutable packet with arguments.
///
/// `parse_with_mut` is like [`parse_mut`], but it accepts arguments to pass
/// to [`P::parse_mut`].
///
/// [`parse_mut`]: ParseBufferMut::parse_mut
/// [`P::parse_mut`]: ParsablePacket::parse_mut
fn parse_with_mut<'a, ParseArgs, P: ParsablePacket<&'a mut [u8], ParseArgs>>(
&'a mut self,
args: ParseArgs,
) -> Result<P, P::Error>;
}
/// A buffer that can grow its body by taking space from its prefix and suffix.
///
/// A `GrowBuffer` is a byte buffer with a prefix, a body, and a suffix. The
/// size of the buffer is referred to as its "capacity", and the size of the
/// body is referred to as its "length". The body of the buffer can shrink or
/// grow as allowed by the capacity as packets are parsed or serialized.
///
/// A `GrowBuffer` guarantees never to discard bytes from the prefix or suffix,
/// which is an important requirement for serialization. \[1\] For parsing, this
/// guarantee is not needed. The subset of methods which do not require this
/// guarantee are defined in the [`ShrinkBuffer`] trait, which does not have
/// this requirement.
///
/// While a `GrowBuffer` allows the ranges covered by its prefix, body, and
/// suffix to be modified, it only provides immutable access to their contents.
/// For mutable access, see [`GrowBufferMut`].
///
/// If a type implements `GrowBuffer`, then its implementations of the methods
/// on [`FragmentedBuffer`] provide access only to the buffer's body. In
/// particular, [`len`] returns the body's length, [`with_bytes`] provides
/// access to the body, and [`to_flattened_vec`] returns a copy of the body.
///
/// \[1\] If `GrowBuffer`s could shrink their prefix or suffix, then it would
/// not be possible to guarantee that a call to [`undo_parse`] wouldn't panic.
/// `undo_parse` is used when retaining previously-parsed packets for
/// serialization, which is useful in scenarios such as packet forwarding.
///
/// [`len`]: FragmentedBuffer::len
/// [`with_bytes`]: FragmentedBuffer::with_bytes
/// [`to_flattened_vec`]: FragmentedBuffer::to_flattened_vec
/// [`undo_parse`]: GrowBuffer::undo_parse
pub trait GrowBuffer: FragmentedBuffer {
/// Gets a view into the parts of this `GrowBuffer`.
///
/// Calls `f`, passing the prefix, body, and suffix as arguments (in that
/// order).
fn with_parts<O, F>(&self, f: F) -> O
where
F: for<'a, 'b> FnOnce(&'a [u8], FragmentedBytes<'a, 'b>, &'a [u8]) -> O;
/// The capacity of the buffer.
///
/// `b.capacity()` is equivalent to `b.prefix_len() + b.len() +
/// b.suffix_len()`.
fn capacity(&self) -> usize {
self.with_parts(|prefix, body, suffix| prefix.len() + body.len() + suffix.len())
}
/// The length of the prefix.
fn prefix_len(&self) -> usize {
self.with_parts(|prefix, _body, _suffix| prefix.len())
}
/// The length of the suffix.
fn suffix_len(&self) -> usize {
self.with_parts(|_prefix, _body, suffix| suffix.len())
}
/// Grows the front of the body towards Growf the buffer.
///
/// `grow_front` consumes the right-most `n` bytes of the prefix, and adds
/// them to the body.
///
/// # Panics
///
/// Panics if `n` is larger than the prefix.
fn grow_front(&mut self, n: usize);
/// Grows the back of the body towards the end of the buffer.
///
/// `grow_back` consumes the left-most `n` bytes of the suffix, and adds
/// them to the body.
///
/// # Panics
///
/// Panics if `n` is larger than the suffix.
fn grow_back(&mut self, n: usize);
/// Resets the body to be equal to the entire buffer.
///
/// `reset` consumes the entire prefix and suffix, adding them to the body.
fn reset(&mut self) {
self.grow_front(self.prefix_len());
self.grow_back(self.suffix_len());
}
/// Undoes the effects of a previous parse in preparation for serialization.
///
/// `undo_parse` undoes the effects of having previously parsed a packet by
/// consuming the appropriate number of bytes from the prefix and suffix.
/// After a call to `undo_parse`, the buffer's body will contain the bytes
/// of the previously-parsed packet, including any headers or footers. This
/// allows a previously-parsed packet to be used in serialization.
///
/// `undo_parse` takes a [`ParseMetadata`], which can be obtained from
/// [`ParsablePacket::parse_metadata`].
///
/// `undo_parse` must always be called starting with the most recently
/// parsed packet, followed by the second most recently parsed packet, and
/// so on. Otherwise, it may panic, and in any case, almost certainly won't
/// produce the desired buffer contents.
///
/// # Padding
///
/// If, during parsing, a packet encountered post-packet padding that was
/// discarded (see the documentation on [`ParsablePacket::parse`]), calling
/// `undo_parse` on the `ParseMetadata` from that packet will not undo the
/// effects of consuming and discarding that padding. The reason for this is
/// that the padding is not considered part of the packet itself (the body
/// it was parsed from can be thought of comprising the packet and
/// post-packet padding back-to-back).
///
/// Calling `undo_parse` on the next encapsulating packet (the one whose
/// body contained the padding) will undo those effects.
///
/// # Panics
///
/// `undo_parse` may panic if called in the wrong order. See the first
/// section of this documentation for details.
fn undo_parse(&mut self, meta: ParseMetadata) {
if self.len() < meta.body_len {
// There were padding bytes which were stripped when parsing the
// encapsulated packet. We need to add them back in order to restore
// the original packet.
let len = self.len();
self.grow_back(meta.body_len - len);
}
self.grow_front(meta.header_len);
self.grow_back(meta.footer_len);
}
}
/// A [`GrowBuffer`] which provides mutable access to its contents.
///
/// While a [`GrowBuffer`] allows the ranges covered by its prefix, body, and
/// suffix to be modified, it only provides immutable access to their contents.
/// A `GrowBufferMut`, on the other hand, provides mutable access to the
/// contents of its prefix, body, and suffix.
pub trait GrowBufferMut: GrowBuffer + FragmentedBufferMut {
/// Gets a mutable view into the parts of this `GrowBufferMut`.
///
/// Calls `f`, passing the prefix, body, and suffix as arguments (in that
/// order).
fn with_parts_mut<O, F>(&mut self, f: F) -> O
where
F: for<'a, 'b> FnOnce(&'a mut [u8], FragmentedBytesMut<'a, 'b>, &'a mut [u8]) -> O;
/// Gets a mutable view into the header of the previously parsed packet.
///
/// Calls `f`, passing the subset of the prefix that forms the header of the
/// previously parsed packet, as specified by `meta`.
///
/// # Panics
///
/// Panics if `meta.header_len` is greater than the size of `self`'s prefix.
fn with_header_mut_with_meta<O, F>(&mut self, meta: ParseMetadata, f: F) -> O
where
F: for<'a, 'b> FnOnce(&'a mut [u8]) -> O,
{
self.with_parts_mut(|prefix, _body, _suffix| {
assert!(
prefix.len() >= meta.header_len,
"prefix ({} bytes) too small to contain header ({} bytes)",
prefix.len(),
meta.header_len
);
let offset = prefix.len() - meta.header_len;
let header = &mut prefix[offset..];
f(header)
})
}
/// Extends the front of the body towards the beginning of the buffer,
/// zeroing the new bytes.
///
/// `grow_front_zero` calls [`GrowBuffer::grow_front`] and sets the
/// newly-added bytes to 0. This can be useful when serializing to ensure
/// that the contents of packets previously stored in the buffer are not
/// leaked.
fn grow_front_zero(&mut self, n: usize) {
self.grow_front(n);
self.zero_range(..n);
}
/// Extends the back of the body towards the end of the buffer, zeroing the
/// new bytes.
///
/// `grow_back_zero` calls [`GrowBuffer::grow_back`] and sets the
/// newly-added bytes to 0. This can be useful when serializing to ensure
/// that the contents of packets previously stored in the buffer are not
/// leaked.
fn grow_back_zero(&mut self, n: usize) {
let old_len = self.len();
self.grow_back(n);
self.zero_range(old_len..);
}
/// Resets the body to be equal to the entire buffer, zeroing the new bytes.
///
/// Like [`GrowBuffer::reset`], `reset_zero` consumes the entire prefix and
/// suffix, adding them to the body. It sets these bytes to 0. This can be
/// useful when serializing to ensure that the contents of packets
/// previously stored in the buffer are not leaked.
fn reset_zero(&mut self) {
self.grow_front_zero(self.prefix_len());
self.grow_back_zero(self.suffix_len());
}
/// Serializes a packet in the buffer.
///
/// *This method is usually called by this crate during the serialization of
/// a [`Serializer`], not directly by the user.*
///
/// `serialize` serializes the packet described by `builder` into the
/// buffer. The body of the buffer is used as the body of the packet, and
/// the prefix and suffix of the buffer are used to serialize the packet's
/// header and footer.
///
/// If `builder` has a minimum body size which is larger than the current
/// body, then `serialize` first grows the body to the right (towards the
/// end of the buffer) with padding bytes in order to meet the minimum body
/// size. This is transparent to the `builder` - it always just sees a body
/// which meets the minimum body size requirement.
///
/// The added padding is zeroed in order to avoid leaking the contents of
/// packets previously stored in the buffer.
///
/// # Panics
///
/// `serialize` panics if there are not enough prefix or suffix bytes to
/// serialize the packet. In particular, `b.serialize(builder)` with `c =
/// builder.constraints()` panics if either of the following hold:
/// - `b.prefix_len() < c.header_len()`
/// - `b.len() + b.suffix_len() < c.min_body_bytes() + c.footer_len()`
#[doc(hidden)]
fn serialize<B: PacketBuilder>(&mut self, builder: B) {
let c = builder.constraints();
if self.len() < c.min_body_len() {
// The body isn't large enough to satisfy the minimum body length
// requirement, so we add padding.
// SECURITY: Use _zero to ensure we zero padding bytes to prevent
// leaking information from packets previously stored in this
// buffer.
let len = self.len();
self.grow_back_zero(c.min_body_len() - len);
}
// These aren't necessary for correctness (grow_xxx_zero will panic
// under the same conditions that these assertions will fail), but they
// provide nicer error messages for debugging.
debug_assert!(
self.prefix_len() >= c.header_len(),
"prefix ({} bytes) too small to serialize header ({} bytes)",
self.prefix_len(),
c.header_len()
);
debug_assert!(
self.suffix_len() >= c.footer_len(),
"suffix ({} bytes) too small to serialize footer ({} bytes)",
self.suffix_len(),
c.footer_len()
);
self.with_parts_mut(|prefix, body, suffix| {
let header = prefix.len() - c.header_len();
let header = &mut prefix[header..];
let footer = &mut suffix[..c.footer_len()];
// SECURITY: zero here is technically unnecessary since it's
// PacketBuilder::serialize's responsibility to zero/initialize the
// header and footer, but we do it anyway to hedge against
// non-compliant PacketBuilder::serialize implementations. If this
// becomes a performance issue, we can revisit it, but the optimizer
// will probably take care of it for us.
zero(header);
zero(footer);
builder.serialize(&mut SerializeTarget { header, footer }, body);
});
self.grow_front(c.header_len());
self.grow_back(c.footer_len());
}
}
/// A byte buffer that can be serialized into multiple times.
///
/// `ReusableBuffer` is a shorthand for `GrowBufferMut + ShrinkBuffer`. A
/// `ReusableBuffer` can be serialized into multiple times - the
/// [`ShrinkBuffer`] implementation allows the buffer's capacity to be reclaimed
/// for a new serialization pass.
pub trait ReusableBuffer: GrowBufferMut + ShrinkBuffer {}
impl<B> ReusableBuffer for B where B: GrowBufferMut + ShrinkBuffer {}
/// A byte buffer used for parsing that can grow back to its original size.
///
/// `Buffer` owns its backing memory and so implies `GrowBuffer + ParseBuffer`.
/// A `Buffer` can be used for parsing (via [`ParseBuffer`]) and then grow back
/// to its original size (via [`GrowBuffer`]). Since it owns the backing memory,
/// it also provides the ability to provide both a parsed and un-parsed view
/// into a packet via [`Buffer::parse_with_view`].
pub trait Buffer: GrowBuffer + ParseBuffer {
/// Like [`ParseBuffer::parse_with`] but additionally provides an
/// un-structured view into the parsed data on successful parsing.
fn parse_with_view<'a, ParseArgs, P: ParsablePacket<&'a [u8], ParseArgs>>(
&'a mut self,
args: ParseArgs,
) -> Result<(P, &'a [u8]), P::Error>;
}
/// A byte buffer used for parsing and serialization.
///
/// `BufferMut` is a shorthand for `GrowBufferMut + ParseBufferMut`. A
/// `BufferMut` can be used for parsing (via [`ParseBufferMut`]) and
/// serialization (via [`GrowBufferMut`]).
pub trait BufferMut: GrowBufferMut + ParseBufferMut + Buffer {}
impl<B> BufferMut for B where B: GrowBufferMut + ParseBufferMut + Buffer {}
/// An empty buffer.
///
/// An `EmptyBuf` is a buffer with 0 bytes of length or capacity. It implements
/// all of the buffer traits (`XxxBuffer` and `XxxBufferMut`) and both buffer
/// view traits ([`BufferView`] and [`BufferViewMut`]).
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct EmptyBuf;
impl AsRef<[u8]> for EmptyBuf {
#[inline]
fn as_ref(&self) -> &[u8] {
&[]
}
}
impl AsMut<[u8]> for EmptyBuf {
#[inline]
fn as_mut(&mut self) -> &mut [u8] {
&mut []
}
}
impl FragmentedBuffer for EmptyBuf {
fragmented_buffer_method_impls!();
}
impl FragmentedBufferMut for EmptyBuf {
fragmented_buffer_mut_method_impls!();
}
impl ContiguousBuffer for EmptyBuf {}
impl ShrinkBuffer for EmptyBuf {
#[inline]
fn shrink_front(&mut self, n: usize) {
assert_eq!(n, 0);
}
#[inline]
fn shrink_back(&mut self, n: usize) {
assert_eq!(n, 0);
}
}
impl ParseBuffer for EmptyBuf {
#[inline]
fn parse_with<'a, ParseArgs, P: ParsablePacket<&'a [u8], ParseArgs>>(
&'a mut self,
args: ParseArgs,
) -> Result<P, P::Error> {
P::parse(EmptyBuf, args)
}
}
impl ParseBufferMut for EmptyBuf {
#[inline]
fn parse_with_mut<'a, ParseArgs, P: ParsablePacket<&'a mut [u8], ParseArgs>>(
&'a mut self,
args: ParseArgs,
) -> Result<P, P::Error> {
P::parse_mut(EmptyBuf, args)
}
}
impl GrowBuffer for EmptyBuf {
#[inline]
fn with_parts<O, F>(&self, f: F) -> O
where
F: for<'a, 'b> FnOnce(&'a [u8], FragmentedBytes<'a, 'b>, &'a [u8]) -> O,
{
f(&[], FragmentedBytes::new_empty(), &[])
}
#[inline]
fn grow_front(&mut self, n: usize) {
assert_eq!(n, 0);
}
#[inline]
fn grow_back(&mut self, n: usize) {
assert_eq!(n, 0);
}
}
impl GrowBufferMut for EmptyBuf {
fn with_parts_mut<O, F>(&mut self, f: F) -> O
where
F: for<'a, 'b> FnOnce(&'a mut [u8], FragmentedBytesMut<'a, 'b>, &'a mut [u8]) -> O,
{
f(&mut [], FragmentedBytesMut::new_empty(), &mut [])
}
}
impl<'a> BufferView<&'a [u8]> for EmptyBuf {
#[inline]
fn len(&self) -> usize {
0
}
#[inline]
fn take_front(&mut self, n: usize) -> Option<&'a [u8]> {
if n > 0 {
return None;
}
Some(&[])
}
#[inline]
fn take_back(&mut self, n: usize) -> Option<&'a [u8]> {
if n > 0 {
return None;
}
Some(&[])
}
#[inline]
fn into_rest(self) -> &'a [u8] {
&[]
}
}
impl<'a> BufferView<&'a mut [u8]> for EmptyBuf {
#[inline]
fn len(&self) -> usize {
0
}
#[inline]
fn take_front(&mut self, n: usize) -> Option<&'a mut [u8]> {
if n > 0 {
return None;
}
Some(&mut [])
}
#[inline]
fn take_back(&mut self, n: usize) -> Option<&'a mut [u8]> {
if n > 0 {
return None;
}
Some(&mut [])
}
#[inline]
fn into_rest(self) -> &'a mut [u8] {
&mut []
}
}
impl<'a> BufferViewMut<&'a mut [u8]> for EmptyBuf {}
impl Buffer for EmptyBuf {
fn parse_with_view<'a, ParseArgs, P: ParsablePacket<&'a [u8], ParseArgs>>(
&'a mut self,
args: ParseArgs,
) -> Result<(P, &'a [u8]), P::Error> {
self.parse_with(args).map(|r| (r, [].as_slice()))
}
}
impl FragmentedBuffer for Never {
fn len(&self) -> usize {
match *self {}
}
fn with_bytes<R, F>(&self, _f: F) -> R
where
F: for<'a, 'b> FnOnce(FragmentedBytes<'a, 'b>) -> R,
{
match *self {}
}
}
impl FragmentedBufferMut for Never {
fn with_bytes_mut<R, F>(&mut self, _f: F) -> R
where
F: for<'a, 'b> FnOnce(FragmentedBytesMut<'a, 'b>) -> R,
{
match *self {}
}
}
impl ShrinkBuffer for Never {
fn shrink_front(&mut self, _n: usize) {}
fn shrink_back(&mut self, _n: usize) {}
}
impl GrowBuffer for Never {
fn with_parts<O, F>(&self, _f: F) -> O
where
F: for<'a, 'b> FnOnce(&'a [u8], FragmentedBytes<'a, 'b>, &'a [u8]) -> O,
{
match *self {}
}
fn grow_front(&mut self, _n: usize) {}
fn grow_back(&mut self, _n: usize) {}
}
impl GrowBufferMut for Never {
fn with_parts_mut<O, F>(&mut self, _f: F) -> O
where
F: for<'a, 'b> FnOnce(&'a mut [u8], FragmentedBytesMut<'a, 'b>, &'a mut [u8]) -> O,
{
match *self {}
}
}
/// A view into a [`ShrinkBuffer`].
///
/// A `BufferView` borrows a `ShrinkBuffer`, and provides methods to consume
/// bytes from the buffer's body. It is primarily intended to be used for
/// parsing, although it provides methods which are useful for serialization as
/// well.
///
/// A `BufferView` only provides immutable access to the contents of the buffer.
/// For mutable access, see [`BufferViewMut`].
///
/// # Notable implementations
///
/// `BufferView` is implemented for mutable references to byte slices (`&mut
/// &[u8]` and `&mut &mut [u8]`).
pub trait BufferView<B: ByteSlice>: Sized + AsRef<[u8]> {
/// The length of the buffer's body.
fn len(&self) -> usize {
self.as_ref().len()
}
/// Is the buffer's body empty?
fn is_empty(&self) -> bool {
self.len() == 0
}
/// Takes `n` bytes from the front of the buffer's body.
///
/// `take_front` consumes `n` bytes from the front of the buffer's body.
/// After a successful call to `take_front(n)`, the body is `n` bytes
/// shorter and, if `Self: GrowBuffer`, the prefix is `n` bytes longer. If
/// the body is not at least `n` bytes in length, `take_front` returns
/// `None`.
fn take_front(&mut self, n: usize) -> Option<B>;
/// Takes `n` bytes from the back of the buffer's body.
///
/// `take_back` consumes `n` bytes from the back of the buffer's body. After
/// a successful call to `take_back(n)`, the body is `n` bytes shorter and,
/// if `Self: GrowBuffer`, the suffix is `n` bytes longer. If the body is
/// not at least `n` bytes in length, `take_back` returns `None`.
fn take_back(&mut self, n: usize) -> Option<B>;
/// Takes the rest of the buffer's body from the front.
///
/// `take_rest_front` consumes the rest of the bytes from the buffer's body.
/// After a call to `take_rest_front`, the body is empty and, if `Self:
/// GrowBuffer`, the bytes which were previously in the body are now in the
/// prefix.
fn take_rest_front(&mut self) -> B {
let len = self.len();
self.take_front(len).unwrap()
}
/// Takes the rest of the buffer's body from the back.
///
/// `take_rest_back` consumes the rest of the bytes from the buffer's body.
/// After a call to `take_rest_back`, the body is empty and, if `Self:
/// GrowBuffer`, the bytes which were previously in the body are now in the
/// suffix.
fn take_rest_back(&mut self) -> B {
let len = self.len();
self.take_back(len).unwrap()
}
/// Takes a single byte of the buffer's body from the front.
///
/// `take_byte_front` consumes a single byte from the from of the buffer's
/// body. It's equivalent to calling `take_front(1)` and copying out the
/// single byte on successful return.
fn take_byte_front(&mut self) -> Option<u8> {
self.take_front(1).map(|x| x[0])
}
/// Takes a single byte of the buffer's body from the back.
///
/// `take_byte_back` consumes a single byte from the fron of the buffer's
/// body. It's equivalent to calling `take_back(1)` and copying out the
/// single byte on successful return.
fn take_byte_back(&mut self) -> Option<u8> {
self.take_back(1).map(|x| x[0])
}
/// Converts this view into a reference to the buffer's body.
///
/// `into_rest` consumes this `BufferView` by value, and returns a reference
/// to the buffer's body. Unlike `take_rest`, the body is not consumed - it
/// is left unchanged.
fn into_rest(self) -> B;
/// Peeks at an object at the front of the buffer's body.
///
/// `peek_obj_front` peeks at `size_of::<T>()` bytes at the front of the
/// buffer's body, and interprets them as a `T`. Unlike `take_obj_front`,
/// `peek_obj_front` does not modify the body. If the body is not at least
/// `size_of::<T>()` bytes in length, `peek_obj_front` returns `None`.
fn peek_obj_front<T>(&mut self) -> Option<&T>
where
T: FromBytes + NoCell + Unaligned,
{
Some(Ref::<_, T>::new_unaligned_from_prefix((&*self).as_ref())?.0.into_ref())
}
/// Takes an object from the front of the buffer's body.
///
/// `take_obj_front` consumes `size_of::<T>()` bytes from the front of the
/// buffer's body, and interprets them as a `T`. After a successful call to
/// `take_obj_front::<T>()`, the body is `size_of::<T>()` bytes shorter and,
/// if `Self: GrowBuffer`, the prefix is `size_of::<T>()` bytes longer. If
/// the body is not at least `size_of::<T>()` bytes in length,
/// `take_obj_front` returns `None`.
fn take_obj_front<T>(&mut self) -> Option<Ref<B, T>>
where
T: Unaligned,
{
let bytes = self.take_front(mem::size_of::<T>())?;
// new_unaligned only returns None if there aren't enough bytes
Some(Ref::new_unaligned(bytes).unwrap())
}
/// Takes a slice of objects from the front of the buffer's body.
///
/// `take_slice_front` consumes `n * size_of::<T>()` bytes from the front of
/// the buffer's body, and interprets them as a `[T]` with `n` elements.
/// After a successful call to `take_slice_front::<T>()`, the body is `n *
/// size_of::<T>()` bytes shorter and, if `Self: GrowBuffer`, the prefix is
/// `n * size_of::<T>()` bytes longer. If the body is not at least `n *
/// size_of::<T>()` bytes in length, `take_slice_front` returns `None`.
///
/// # Panics
///
/// Panics if `T` is a zero-sized type.
fn take_slice_front<T>(&mut self, n: usize) -> Option<Ref<B, [T]>>
where
T: Unaligned,
{
let bytes = self.take_front(n * mem::size_of::<T>())?;
// `new_slice_unaligned` will return `None` only if `bytes.len()` is
// not a multiple of `mem::size_of::<T>()`.
Some(Ref::new_slice_unaligned(bytes).unwrap())
}
/// Peeks at an object at the back of the buffer's body.
///
/// `peek_obj_back` peeks at `size_of::<T>()` bytes at the back of the
/// buffer's body, and interprets them as a `T`. Unlike `take_obj_back`,
/// `peek_obj_back` does not modify the body. If the body is not at least
/// `size_of::<T>()` bytes in length, `peek_obj_back` returns `None`.
fn peek_obj_back<T>(&mut self) -> Option<&T>
where
T: FromBytes + NoCell + Unaligned,
{
Some(Ref::<_, T>::new_unaligned_from_suffix((&*self).as_ref())?.1.into_ref())
}
/// Takes an object from the back of the buffer's body.
///
/// `take_obj_back` consumes `size_of::<T>()` bytes from the back of the
/// buffer's body, and interprets them as a `T`. After a successful call to
/// `take_obj_back::<T>()`, the body is `size_of::<T>()` bytes shorter and,
/// if `Self: GrowBuffer`, the suffix is `size_of::<T>()` bytes longer. If
/// the body is not at least `size_of::<T>()` bytes in length,
/// `take_obj_back` returns `None`.
fn take_obj_back<T>(&mut self) -> Option<Ref<B, T>>
where
T: Unaligned,
{
let bytes = self.take_back(mem::size_of::<T>())?;
// new_unaligned only returns None if there aren't enough bytes
Some(Ref::new_unaligned(bytes).unwrap())
}
/// Takes a slice of objects from the back of the buffer's body.
///
/// `take_slice_back` consumes `n * size_of::<T>()` bytes from the back of
/// the buffer's body, and interprets them as a `[T]` with `n` elements.
/// After a successful call to `take_slice_back::<T>()`, the body is `n *
/// size_of::<T>()` bytes shorter and, if `Self: GrowBuffer`, the suffix is
/// `n * size_of::<T>()` bytes longer. If the body is not at least `n *
/// size_of::<T>()` bytes in length, `take_slice_back` returns `None`.
///
/// # Panics
///
/// Panics if `T` is a zero-sized type.
fn take_slice_back<T>(&mut self, n: usize) -> Option<Ref<B, [T]>>
where
T: Unaligned,
{
let bytes = self.take_back(n * mem::size_of::<T>())?;
// `new_slice_unaligned` will return `None` only if `bytes.len()` is
// not a multiple of `mem::size_of::<T>()`.
Some(Ref::new_slice_unaligned(bytes).unwrap())
}
}
/// A mutable view into a `Buffer`.
///
/// A `BufferViewMut` is a [`BufferView`] which provides mutable access to the
/// contents of the buffer.
///
/// # Notable implementations
///
/// `BufferViewMut` is implemented for `&mut &mut [u8]`.
pub trait BufferViewMut<B: ByteSliceMut>: BufferView<B> + AsMut<[u8]> {
/// Takes `n` bytes from the front of the buffer's body and zeroes them.
///
/// `take_front_zero` is like [`BufferView::take_front`], except that it
/// zeroes the bytes before returning them. This can be useful when
/// serializing to ensure that the contents of packets previously stored in
/// the buffer are not leaked.
fn take_front_zero(&mut self, n: usize) -> Option<B> {
self.take_front(n).map(|mut buf| {
zero(buf.deref_mut());
buf
})
}
/// Takes `n` bytes from the back of the buffer's body and zeroes them.
///
/// `take_back_zero` is like [`BufferView::take_back`], except that it
/// zeroes the bytes before returning them. This can be useful when
/// serializing to ensure that the contents of packets previously stored in
/// the buffer are not leaked.
fn take_back_zero(&mut self, n: usize) -> Option<B> {
self.take_back(n).map(|mut buf| {
zero(buf.deref_mut());
buf
})
}
/// Takes the rest of the buffer's body from the front and zeroes it.
///
/// `take_rest_front_zero` is like [`BufferView::take_rest_front`], except
/// that it zeroes the bytes before returning them. This can be useful when
/// serializing to ensure that the contents of packets previously stored in
/// the buffer are not leaked.
fn take_rest_front_zero(mut self) -> B {
let len = self.len();
self.take_front_zero(len).unwrap()
}
/// Takes the rest of the buffer's body from the back and zeroes it.
///
/// `take_rest_back_zero` is like [`BufferView::take_rest_back`], except
/// that it zeroes the bytes before returning them. This can be useful when
/// serializing to ensure that the contents of packets previously stored in
/// the buffer are not leaked.
fn take_rest_back_zero(mut self) -> B {
let len = self.len();
self.take_front_zero(len).unwrap()
}
/// Converts this view into a reference to the buffer's body, and zeroes it.
///
/// `into_rest_zero` is like [`BufferView::into_rest`], except that it
/// zeroes the bytes before returning them. This can be useful when
/// serializing to ensure that the contents of packets previously stored in
/// the buffer are not leaked.
fn into_rest_zero(self) -> B {
let mut bytes = self.into_rest();
zero(&mut bytes);
bytes
}
/// Takes an object from the front of the buffer's body and zeroes it.
///
/// `take_obj_front_zero` is like [`BufferView::take_obj_front`], except
/// that it zeroes the bytes before converting them to a `T`. This can be
/// useful when serializing to ensure that the contents of packets
/// previously stored in the buffer are not leaked.
fn take_obj_front_zero<T>(&mut self) -> Option<Ref<B, T>>
where
T: Unaligned,
{
let bytes = self.take_front(mem::size_of::<T>())?;
// new_unaligned_zeroed only returns None if there aren't enough bytes
Some(Ref::new_unaligned_zeroed(bytes).unwrap())
}
/// Takes an object from the back of the buffer's body and zeroes it.
///
/// `take_obj_back_zero` is like [`BufferView::take_obj_back`], except that
/// it zeroes the bytes before converting them to a `T`. This can be useful
/// when serializing to ensure that the contents of packets previously
/// stored in the buffer are not leaked.
fn take_obj_back_zero<T>(&mut self) -> Option<Ref<B, T>>
where
T: Unaligned,
{
let bytes = self.take_back(mem::size_of::<T>())?;
// new_unaligned_zeroed only returns None if there aren't enough bytes
Some(Ref::new_unaligned_zeroed(bytes).unwrap())
}
/// Writes an object to the front of the buffer's body, consuming the bytes.
///
/// `write_obj_front` consumes `size_of_val(obj)` bytes from the front of
/// the buffer's body, and overwrites them with `obj`. After a successful
/// call to `write_obj_front(obj)`, the body is `size_of_val(obj)` bytes
/// shorter and, if `Self: GrowBuffer`, the prefix is `size_of_val(obj)`
/// bytes longer. If the body is not at least `size_of_val(obj)` bytes in
/// length, `write_obj_front` returns `None`.
fn write_obj_front<T>(&mut self, obj: &T) -> Option<()>
where
T: ?Sized + AsBytes + NoCell,
{
let mut bytes = self.take_front(mem::size_of_val(obj))?;
bytes.copy_from_slice(obj.as_bytes());
Some(())
}
/// Writes an object to the back of the buffer's body, consuming the bytes.
///
/// `write_obj_back` consumes `size_of_val(obj)` bytes from the back of the
/// buffer's body, and overwrites them with `obj`. After a successful call
/// to `write_obj_back(obj)`, the body is `size_of_val(obj)` bytes shorter
/// and, if `Self: GrowBuffer`, the suffix is `size_of_val(obj)` bytes
/// longer. If the body is not at least `size_of_val(obj)` bytes in length,
/// `write_obj_back` returns `None`.
fn write_obj_back<T>(&mut self, obj: &T) -> Option<()>
where
T: ?Sized + AsBytes + NoCell,
{
let mut bytes = self.take_back(mem::size_of_val(obj))?;
bytes.copy_from_slice(obj.as_bytes());
Some(())
}
}
// NOTE on undo_parse algorithm: It's important that ParseMetadata only describe
// the packet itself, and not any padding. This is because the user might call
// undo_parse on a packet only once, and then serialize that packet inside of
// another packet with a lower minimum body length requirement than the one it
// was encapsulated in during parsing. In this case, if we were to include
// padding, we would spuriously serialize an unnecessarily large body. Omitting
// the padding is required for this reason. It is acceptable because, using the
// body_len field of the encapsulating packet's ParseMetadata, it is possible
// for undo_parse to reconstruct how many padding bytes there were if it needs
// to.
//
// undo_parse also needs to differentiate between bytes which were consumed from
// the beginning and end of the buffer. For normal packets this is easy -
// headers are consumed from the beginning, and footers from the end. For inner
// packets, which do not have a header/footer distinction (at least from the
// perspective of this crate), we arbitrarily decide that all bytes are consumed
// from the beginning. So long as ParsablePacket implementations obey this
// requirement, undo_parse will work properly. In order to support this,
// ParseMetadata::from_inner_packet constructs a ParseMetadata in which the only
// non-zero field is header_len.
/// Metadata about a previously-parsed packet used to undo its parsing.
///
/// See [`GrowBuffer::undo_parse`] for more details.
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct ParseMetadata {
header_len: usize,
body_len: usize,
footer_len: usize,
}
impl ParseMetadata {
/// Constructs a new `ParseMetadata` from information about a packet.
pub fn from_packet(header_len: usize, body_len: usize, footer_len: usize) -> ParseMetadata {
ParseMetadata { header_len, body_len, footer_len }
}
/// Constructs a new `ParseMetadata` from information about an inner packet.
///
/// Since inner packets do not have a header/body/footer distinction (at
/// least from the perspective of the utilities in this crate), we
/// arbitrarily produce a `ParseMetadata` with a header length and no body
/// or footer lengths. Thus, `from_inner_packet(len)` is equivalent to
/// `from_packet(len, 0, 0)`.
pub fn from_inner_packet(len: usize) -> ParseMetadata {
ParseMetadata { header_len: len, body_len: 0, footer_len: 0 }
}
/// Gets the header length.
///
/// `header_len` returns the length of the header of the packet described by
/// this `ParseMetadata`.
pub fn header_len(&self) -> usize {
self.header_len
}
/// Gets the body length.
///
/// `body_len` returns the length of the body of the packet described by
/// this `ParseMetadata`.
pub fn body_len(&self) -> usize {
self.body_len
}
/// Gets the footer length.
///
/// `footer_len` returns the length of the footer of the packet described by
/// this `ParseMetadata`.
pub fn footer_len(&self) -> usize {
self.footer_len
}
}
/// A packet which can be parsed from a buffer.
///
/// A `ParsablePacket` is a packet which can be parsed from the body of a
/// buffer. For performance reasons, it is recommended that as much of the
/// packet object as possible be stored as references into the body in order to
/// avoid copying.
pub trait ParsablePacket<B: ByteSlice, ParseArgs>: Sized {
/// The type of errors returned from [`parse`] and [`parse_mut`].
///
/// [`parse`]: ParsablePacket::parse
/// [`parse_mut`]: ParsablePacket::parse_mut
type Error;
/// Parses a packet from a buffer.
///
/// Given a view into a buffer, `parse` parses a packet by consuming bytes
/// from the buffer's body. This works slightly differently for normal
/// packets and inner packets (those which do not contain other packets).
///
/// ## Packets
///
/// When parsing a packet which contains another packet, the outer packet's
/// header and footer should be consumed from the beginning and end of the
/// buffer's body respectively. The packet's body should be constructed from
/// a reference to the buffer's body (i.e., [`BufferView::into_rest`]), but
/// the buffer's body should not be consumed. This allows the next
/// encapsulated packet to be parsed from the remaining buffer body. See the
/// crate documentation for more details.
///
/// ## Inner Packets
///
/// When parsing packets which do not contain other packets, the entire
/// packet's contents should be consumed from the beginning of the buffer's
/// body. The buffer's body should be empty after `parse` has returned.
///
/// # Padding
///
/// There may be post-packet padding (coming after the entire packet,
/// including any footer) which was added in order to satisfy the minimum
/// body length requirement of an encapsulating packet. If the packet
/// currently being parsed describes its own length (and thus, it's possible
/// to determine whether there's any padding), `parse` is required to
/// consume any post-packet padding from the buffer's suffix. If this
/// invariant is not upheld, future calls to [`ParseBuffer::parse`] or
/// [`GrowBuffer::undo_parse`] may behave incorrectly.
///
/// Pre-packet padding is not supported; if a protocol supports such
/// padding, it must be handled in a way that is transparent to this API. In
/// particular, that means that the [`parse_metadata`] method must treat that
/// padding as part of the packet.
///
/// [`parse_metadata`]: ParsablePacket::parse_metadata
fn parse<BV: BufferView<B>>(buffer: BV, args: ParseArgs) -> Result<Self, Self::Error>;
/// Parses a packet from a mutable buffer.
///
/// `parse_mut` is like [`parse`], except that it operates on a mutable
/// buffer view.
///
/// [`parse`]: ParsablePacket::parse
fn parse_mut<BV: BufferViewMut<B>>(buffer: BV, args: ParseArgs) -> Result<Self, Self::Error>
where
B: ByteSliceMut,
{
Self::parse(buffer, args)
}
/// Gets metadata about this packet required by [`GrowBuffer::undo_parse`].
///
/// The returned [`ParseMetadata`] records the number of header and footer
/// bytes consumed by this packet during parsing, and the number of bytes
/// left in the body (not consumed from the buffer). For packets which
/// encapsulate other packets, the header length must be equal to the number
/// of bytes consumed from the prefix, and the footer length must be equal
/// to the number of bytes consumed from the suffix. For inner packets, use
/// [`ParseMetadata::from_inner_packet`].
///
/// There is one exception: if any post-packet padding was consumed from the
/// suffix, this should not be included, as it is not considered part of the
/// packet. For example, consider a packet with 8 bytes of footer followed
/// by 8 bytes of post-packet padding. Parsing this packet would consume 16
/// bytes from the suffix, but calling `parse_metadata` on the resulting
/// object would return a `ParseMetadata` with only 8 bytes of footer.
fn parse_metadata(&self) -> ParseMetadata;
}
fn zero_iter<'a, I: Iterator<Item = &'a mut u8>>(bytes: I) {
for byte in bytes {
*byte = 0;
}
}
fn zero(bytes: &mut [u8]) {
for byte in bytes.iter_mut() {
*byte = 0;
}
}
impl<'a> FragmentedBuffer for &'a [u8] {
fragmented_buffer_method_impls!();
}
impl<'a> ContiguousBuffer for &'a [u8] {}
impl<'a> ShrinkBuffer for &'a [u8] {
fn shrink_front(&mut self, n: usize) {
let _: &[u8] = take_front(self, n);
}
fn shrink_back(&mut self, n: usize) {
let _: &[u8] = take_back(self, n);
}
}
impl<'a> ParseBuffer for &'a [u8] {
fn parse_with<'b, ParseArgs, P: ParsablePacket<&'b [u8], ParseArgs>>(
&'b mut self,
args: ParseArgs,
) -> Result<P, P::Error> {
// A `&'b mut &'a [u8]` wrapper which implements `BufferView<&'b [u8]>`
// instead of `BufferView<&'a [u8]>`. This is needed thanks to fact that
// `P: ParsablePacket` has the lifetime `'b`, not `'a`.
struct ByteSlice<'a, 'b>(&'b mut &'a [u8]);
impl<'a, 'b> AsRef<[u8]> for ByteSlice<'a, 'b> {
fn as_ref(&self) -> &[u8] {
&self.0
}
}
impl<'b, 'a: 'b> BufferView<&'b [u8]> for ByteSlice<'a, 'b> {
fn len(&self) -> usize {
<[u8]>::len(self.0)
}
fn take_front(&mut self, n: usize) -> Option<&'b [u8]> {
if self.0.len() < n {
return None;
}
Some(take_front(self.0, n))
}
fn take_back(&mut self, n: usize) -> Option<&'b [u8]> {
if self.0.len() < n {
return None;
}
Some(take_back(self.0, n))
}
fn into_rest(self) -> &'b [u8] {
self.0
}
}
P::parse(ByteSlice(self), args)
}
}
impl<'a> FragmentedBuffer for &'a mut [u8] {
fragmented_buffer_method_impls!();
}
impl<'a> FragmentedBufferMut for &'a mut [u8] {
fragmented_buffer_mut_method_impls!();
}
impl<'a> ContiguousBuffer for &'a mut [u8] {}
impl<'a> ShrinkBuffer for &'a mut [u8] {
fn shrink_front(&mut self, n: usize) {
let _: &[u8] = take_front_mut(self, n);
}
fn shrink_back(&mut self, n: usize) {
let _: &[u8] = take_back_mut(self, n);
}
}
impl<'a> ParseBuffer for &'a mut [u8] {
fn parse_with<'b, ParseArgs, P: ParsablePacket<&'b [u8], ParseArgs>>(
&'b mut self,
args: ParseArgs,
) -> Result<P, P::Error> {
P::parse(self, args)
}
}
impl<'a> ParseBufferMut for &'a mut [u8] {
fn parse_with_mut<'b, ParseArgs, P: ParsablePacket<&'b mut [u8], ParseArgs>>(
&'b mut self,
args: ParseArgs,
) -> Result<P, P::Error> {
P::parse_mut(self, args)
}
}
impl<'b, 'a: 'b> BufferView<&'a [u8]> for &'b mut &'a [u8] {
fn len(&self) -> usize {
<[u8]>::len(self)
}
fn take_front(&mut self, n: usize) -> Option<&'a [u8]> {
if self.len() < n {
return None;
}
Some(take_front(self, n))
}
fn take_back(&mut self, n: usize) -> Option<&'a [u8]> {
if self.len() < n {
return None;
}
Some(take_back(self, n))
}
fn into_rest(self) -> &'a [u8] {
self
}
}
impl<'b, 'a: 'b> BufferView<&'b [u8]> for &'b mut &'a mut [u8] {
fn len(&self) -> usize {
<[u8]>::len(self)
}
fn take_front(&mut self, n: usize) -> Option<&'b [u8]> {
if <[u8]>::len(self) < n {
return None;
}
Some(take_front_mut(self, n))
}
fn take_back(&mut self, n: usize) -> Option<&'b [u8]> {
if <[u8]>::len(self) < n {
return None;
}
Some(take_back_mut(self, n))
}
fn into_rest(self) -> &'b [u8] {
self
}
}
impl<'b, 'a: 'b> BufferView<&'b mut [u8]> for &'b mut &'a mut [u8] {
fn len(&self) -> usize {
<[u8]>::len(self)
}
fn take_front(&mut self, n: usize) -> Option<&'b mut [u8]> {
if <[u8]>::len(self) < n {
return None;
}
Some(take_front_mut(self, n))
}
fn take_back(&mut self, n: usize) -> Option<&'b mut [u8]> {
if <[u8]>::len(self) < n {
return None;
}
Some(take_back_mut(self, n))
}
fn into_rest(self) -> &'b mut [u8] {
self
}
}
impl<'b, 'a: 'b> BufferViewMut<&'b mut [u8]> for &'b mut &'a mut [u8] {}
/// A [`BufferViewMut`] into a `&mut [u8]`.
///
/// This type is useful for instantiating a mutable view into a slice that can
/// be used for parsing, where any parsing that is done only affects this view
/// and therefore need not be "undone" later.
///
/// Note that `BufferViewMut<&mut [u8]>` is also implemented for &mut &mut [u8]
/// (a mutable reference to a mutable byte slice), but this can be problematic
/// if you need to materialize an *owned* type that implements `BufferViewMut`,
/// in order to pass it to a function, for example, so that it does not hold a
/// reference to a temporary value.
pub struct SliceBufViewMut<'a>(&'a mut [u8]);
impl<'a> SliceBufViewMut<'a> {
pub fn new(buf: &'a mut [u8]) -> Self {
Self(buf)
}
}
impl<'a> BufferView<&'a mut [u8]> for SliceBufViewMut<'a> {
fn take_front(&mut self, n: usize) -> Option<&'a mut [u8]> {
let Self(buf) = self;
if <[u8]>::len(buf) < n {
return None;
}
Some(take_front_mut(buf, n))
}
fn take_back(&mut self, n: usize) -> Option<&'a mut [u8]> {
let Self(buf) = self;
if <[u8]>::len(buf) < n {
return None;
}
Some(take_back_mut(buf, n))
}
fn into_rest(self) -> &'a mut [u8] {
self.0
}
}
impl<'a> BufferViewMut<&'a mut [u8]> for SliceBufViewMut<'a> {}
impl<'a> AsRef<[u8]> for SliceBufViewMut<'a> {
fn as_ref(&self) -> &[u8] {
self.0
}
}
impl<'a> AsMut<[u8]> for SliceBufViewMut<'a> {
fn as_mut(&mut self) -> &mut [u8] {
self.0
}
}
fn take_front<'a>(bytes: &mut &'a [u8], n: usize) -> &'a [u8] {
let (prefix, rest) = mem::replace(bytes, &[]).split_at(n);
*bytes = rest;
prefix
}
fn take_back<'a>(bytes: &mut &'a [u8], n: usize) -> &'a [u8] {
let split = bytes.len() - n;
let (rest, suffix) = mem::replace(bytes, &[]).split_at(split);
*bytes = rest;
suffix
}
fn take_front_mut<'a>(bytes: &mut &'a mut [u8], n: usize) -> &'a mut [u8] {
let (prefix, rest) = mem::replace(bytes, &mut []).split_at_mut(n);
*bytes = rest;
prefix
}
fn take_back_mut<'a>(bytes: &mut &'a mut [u8], n: usize) -> &'a mut [u8] {
let split = <[u8]>::len(bytes) - n;
let (rest, suffix) = mem::replace(bytes, &mut []).split_at_mut(split);
*bytes = rest;
suffix
}
// Returns the inclusive-exclusive equivalent of the bound, verifying that it is
// in range of `len`, and panicking if it is not or if the range is nonsensical.
fn canonicalize_range<R: RangeBounds<usize>>(len: usize, range: &R) -> Range<usize> {
let lower = canonicalize_lower_bound(range.start_bound());
let upper = canonicalize_upper_bound(len, range.end_bound()).expect("range out of bounds");
assert!(lower <= upper, "invalid range: upper bound precedes lower bound");
lower..upper
}
// Returns the inclusive equivalent of the bound.
fn canonicalize_lower_bound(bound: Bound<&usize>) -> usize {
match bound {
Bound::Included(x) => *x,
Bound::Excluded(x) => *x + 1,
Bound::Unbounded => 0,
}
}
// Returns the exclusive equivalent of the bound, verifying that it is in range
// of `len`.
fn canonicalize_upper_bound(len: usize, bound: Bound<&usize>) -> Option<usize> {
let bound = match bound {
Bound::Included(x) => *x + 1,
Bound::Excluded(x) => *x,
Bound::Unbounded => len,
};
if bound > len {
return None;
}
Some(bound)
}
mod sealed {
pub trait Sealed {}
}
#[cfg(test)]
mod tests {
use super::*;
// Call test_buffer, test_buffer_view, and test_buffer_view_post for each of
// the Buffer types. Call test_parse_buffer and test_buffer_view for each of
// the ParseBuffer types.
#[test]
fn test_byte_slice_impl_buffer() {
let mut avoid_leaks = Vec::new();
test_parse_buffer::<&[u8], _>(|len| {
let v = ascending(len);
// Requires that |avoid_leaks| outlives this reference. In this case, we know
// |test_parse_buffer| does not retain the reference beyond its run.
let s = unsafe { std::slice::from_raw_parts(v.as_ptr(), v.len()) };
let () = avoid_leaks.push(v);
s
});
let buf = ascending(10);
let mut buf: &[u8] = buf.as_ref();
test_buffer_view::<&[u8], _>(&mut buf);
}
#[test]
fn test_byte_slice_mut_impl_buffer() {
let mut avoid_leaks = Vec::new();
test_parse_buffer::<&mut [u8], _>(|len| {
let mut v = ascending(len);
// Requires that |avoid_leaks| outlives this reference. In this case, we know
// |test_parse_buffer| does not retain the reference beyond its run.
let s = unsafe { std::slice::from_raw_parts_mut(v.as_mut_ptr(), v.len()) };
let () = avoid_leaks.push(v);
s
});
let mut buf = ascending(10);
let mut buf: &mut [u8] = buf.as_mut();
test_buffer_view::<&mut [u8], _>(&mut buf);
}
#[test]
fn test_either_impl_buffer() {
macro_rules! test_either {
($variant:ident) => {
test_buffer::<Either<Buf<Vec<u8>>, Buf<Vec<u8>>>, _>(|len| {
Either::$variant(Buf::new(ascending(len), ..))
});
// Test call to `Buf::buffer_view` which returns a
// `BufferView`.
let mut buf: Either<Buf<Vec<u8>>, Buf<Vec<u8>>> =
Either::$variant(Buf::new(ascending(10), ..));
test_buffer_view(match &mut buf {
Either::$variant(buf) => buf.buffer_view(),
_ => unreachable!(),
});
test_buffer_view_post(&buf, true);
// Test call to `Buf::buffer_view_mut` which returns a
// `BufferViewMut`.
let mut buf: Either<Buf<Vec<u8>>, Buf<Vec<u8>>> =
Either::$variant(Buf::new(ascending(10), ..));
test_buffer_view_mut(match &mut buf {
Either::$variant(buf) => buf.buffer_view_mut(),
_ => unreachable!(),
});
test_buffer_view_mut_post(&buf, true);
};
}
test_either!(A);
test_either!(B);
}
#[test]
fn test_slice_buf_view_mut() {
let mut buf = ascending(10);
test_buffer_view(SliceBufViewMut::new(&mut buf));
test_buffer_view_mut(SliceBufViewMut::new(&mut buf));
}
#[test]
fn test_buf_impl_buffer() {
test_buffer(|len| Buf::new(ascending(len), ..));
let mut buf = Buf::new(ascending(10), ..);
test_buffer_view(buf.buffer_view());
test_buffer_view_post(&buf, true);
}
fn ascending(n: u8) -> Vec<u8> {
(0..n).collect::<Vec<u8>>()
}
// This test performs a number of shrinking operations (for ParseBuffer
// implementations) followed by their equivalent growing operations (for
// Buffer implementations only), and at each step, verifies various
// properties of the buffer. The shrinking part of the test is in
// test_parse_buffer_inner, while test_buffer calls test_parse_buffer_inner
// and then performs the growing part of the test.
// When shrinking, we keep two buffers - 'at_once' and 'separately', and for
// each test case, we do the following:
// - shrink the 'at_once' buffer with the 'shrink' field
// - shrink_front the 'separately' buffer with the 'front' field
// - shrink_back the 'separately' buffer with the 'back' field
//
// When growing, we only keep one buffer from the shrinking phase, and for
// each test case, we do the following:
// - grow_front the buffer with the 'front' field
// - grow_back the buffer with the 'back' field
//
// After each action, we verify that the len and contents are as expected.
// For Buffers, we also verify the cap, prefix, and suffix.
struct TestCase {
shrink: Range<usize>,
front: usize, // shrink or grow the front of the body
back: usize, // shrink or grow the back of the body
cap: usize,
len: usize,
pfx: usize,
sfx: usize,
contents: &'static [u8],
}
#[rustfmt::skip]
const TEST_CASES: &[TestCase] = &[
TestCase { shrink: 0..10, front: 0, back: 0, cap: 10, len: 10, pfx: 0, sfx: 0, contents: &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], },
TestCase { shrink: 2..10, front: 2, back: 0, cap: 10, len: 8, pfx: 2, sfx: 0, contents: &[2, 3, 4, 5, 6, 7, 8, 9], },
TestCase { shrink: 0..8, front: 0, back: 0, cap: 10, len: 8, pfx: 2, sfx: 0, contents: &[2, 3, 4, 5, 6, 7, 8, 9], },
TestCase { shrink: 0..6, front: 0, back: 2, cap: 10, len: 6, pfx: 2, sfx: 2, contents: &[2, 3, 4, 5, 6, 7], },
TestCase { shrink: 2..4, front: 2, back: 2, cap: 10, len: 2, pfx: 4, sfx: 4, contents: &[4, 5], },
];
// Test a ParseBuffer implementation. 'new_buf' is a function which
// constructs a buffer of length n, and initializes its contents to [0, 1,
// 2, ..., n -1].
fn test_parse_buffer<B: ParseBuffer, N: FnMut(u8) -> B>(new_buf: N) {
let _: B = test_parse_buffer_inner(new_buf, |buf, _, len, _, _, contents| {
assert_eq!(buf.len(), len);
assert_eq!(buf.as_ref(), contents);
});
}
// Code common to test_parse_buffer and test_buffer. 'assert' is a function
// which takes a buffer, and verifies that its capacity, length, prefix,
// suffix, and contents are equal to the arguments (in that order). For
// ParseBuffers, the capacity, prefix, and suffix arguments are irrelevant,
// and ignored.
//
// When the test is done, test_parse_buffer_inner returns one of the buffers
// it used for testing so that test_buffer can do further testing on it. Its
// prefix, body, and suffix will be [0, 1, 2, 3], [4, 5], and [6, 7, 8, 9]
// respectively.
fn test_parse_buffer_inner<
B: ParseBuffer,
N: FnMut(u8) -> B,
A: Fn(&B, usize, usize, usize, usize, &[u8]),
>(
mut new_buf: N,
assert: A,
) -> B {
let mut at_once = new_buf(10);
let mut separately = new_buf(10);
for tc in TEST_CASES {
at_once.shrink(tc.shrink.clone());
separately.shrink_front(tc.front);
separately.shrink_back(tc.back);
assert(&at_once, tc.cap, tc.len, tc.pfx, tc.sfx, tc.contents);
assert(&separately, tc.cap, tc.len, tc.pfx, tc.sfx, tc.contents);
}
at_once
}
// Test a Buffer implementation. 'new_buf' is a function which constructs a
// buffer of length and capacity n, and initializes its contents to [0, 1,
// 2, ..., n - 1].
fn test_buffer<B: Buffer, F: Fn(u8) -> B>(new_buf: F) {
fn assert<B: Buffer>(
buf: &B,
cap: usize,
len: usize,
pfx: usize,
sfx: usize,
contents: &[u8],
) {
assert_eq!(buf.len(), len);
assert_eq!(buf.capacity(), cap);
assert_eq!(buf.prefix_len(), pfx);
assert_eq!(buf.suffix_len(), sfx);
assert_eq!(buf.as_ref(), contents);
}
let mut buf = test_parse_buffer_inner(new_buf, assert);
buf.reset();
assert(&buf, 10, 10, 0, 0, &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9][..]);
buf.shrink_front(4);
buf.shrink_back(4);
assert(&buf, 10, 2, 4, 4, &[4, 5][..]);
for tc in TEST_CASES.iter().rev() {
assert(&buf, tc.cap, tc.len, tc.pfx, tc.sfx, tc.contents);
buf.grow_front(tc.front);
buf.grow_back(tc.back);
}
}
// Test a BufferView implementation. Call with a view into a buffer with no
// extra capacity whose body contains [0, 1, ..., 9]. After the call
// returns, call test_buffer_view_post on the buffer.
fn test_buffer_view<B: ByteSlice, BV: BufferView<B>>(mut view: BV) {
assert_eq!(view.len(), 10);
assert_eq!(view.take_front(1).unwrap().as_ref(), &[0][..]);
assert_eq!(view.len(), 9);
assert_eq!(view.take_back(1).unwrap().as_ref(), &[9][..]);
assert_eq!(view.len(), 8);
assert_eq!(view.peek_obj_front::<[u8; 2]>().unwrap(), &[1, 2]);
assert_eq!(view.take_obj_front::<[u8; 2]>().unwrap().as_ref(), [1, 2]);
assert_eq!(view.len(), 6);
assert_eq!(view.peek_obj_back::<[u8; 2]>().unwrap(), &[7, 8]);
assert_eq!(view.take_obj_back::<[u8; 2]>().unwrap().as_ref(), [7, 8]);
assert_eq!(view.len(), 4);
assert!(view.take_front(5).is_none());
assert_eq!(view.len(), 4);
assert!(view.take_back(5).is_none());
assert_eq!(view.len(), 4);
assert_eq!(view.into_rest().as_ref(), &[3, 4, 5, 6][..]);
}
// Test a BufferViewMut implementation. Call with a mutable view into a buffer
// with no extra capacity whose body contains [0, 1, ..., 9]. After the call
// returns, call test_buffer_view_post on the buffer.
fn test_buffer_view_mut<B: ByteSliceMut, BV: BufferViewMut<B>>(mut view: BV) {
assert_eq!(view.len(), 10);
assert_eq!(view.as_mut()[0], 0);
assert_eq!(view.take_front_zero(1).unwrap().as_ref(), &[0][..]);
assert_eq!(view.len(), 9);
assert_eq!(view.as_mut()[0], 1);
assert_eq!(view.take_front_zero(1).unwrap().as_ref(), &[0][..]);
assert_eq!(view.len(), 8);
assert_eq!(view.as_mut()[7], 9);
assert_eq!(view.take_back_zero(1).unwrap().as_ref(), &[0][..]);
assert_eq!(view.len(), 7);
assert_eq!(&view.as_mut()[0..2], &[2, 3][..]);
assert_eq!(view.peek_obj_front::<[u8; 2]>().unwrap(), &[2, 3]);
assert_eq!(view.take_obj_front_zero::<[u8; 2]>().unwrap().as_ref(), &[0, 0][..]);
assert_eq!(view.len(), 5);
assert_eq!(&view.as_mut()[3..5], &[7, 8][..]);
assert_eq!(view.peek_obj_back::<[u8; 2]>().unwrap(), &[7, 8]);
assert_eq!(view.take_obj_back_zero::<[u8; 2]>().unwrap().as_ref(), &[0, 0][..]);
assert_eq!(view.write_obj_front(&[0u8]), Some(()));
assert_eq!(view.as_mut(), &[5, 6][..]);
assert_eq!(view.write_obj_back(&[0u8]), Some(()));
assert_eq!(view.as_mut(), &[5][..]);
assert!(view.take_front_zero(2).is_none());
assert_eq!(view.len(), 1);
assert!(view.take_back_zero(2).is_none());
assert_eq!(view.len(), 1);
assert_eq!(view.as_mut(), &[5][..]);
assert_eq!(view.into_rest_zero().as_ref(), &[0][..]);
}
// Post-verification to test a BufferView implementation. Call after
// test_buffer_view.
fn test_buffer_view_post<B: Buffer>(buffer: &B, preserves_cap: bool) {
assert_eq!(buffer.as_ref(), &[3, 4, 5, 6][..]);
if preserves_cap {
assert_eq!(buffer.prefix_len(), 3);
assert_eq!(buffer.suffix_len(), 3);
}
}
// Post-verification to test a BufferViewMut implementation. Call after
// test_buffer_view_mut.
fn test_buffer_view_mut_post<B: Buffer>(buffer: &B, preserves_cap: bool) {
assert_eq!(buffer.as_ref(), &[0][..]);
if preserves_cap {
assert_eq!(buffer.prefix_len(), 5);
assert_eq!(buffer.suffix_len(), 4);
}
}
#[test]
fn test_buffer_view_from_buffer() {
// This test is specifically designed to verify that implementations of
// ParseBuffer::parse properly construct a BufferView, and that that
// BufferView properly updates the underlying buffer. It was inspired by
// the bug with Change-Id Ifeab21fba0f7ba94d1a12756d4e83782002e4e1e.
// This ParsablePacket implementation takes the contents it expects as a
// parse argument and validates the BufferView[Mut] against it. It consumes
// one byte from the front and one byte from the back to ensure that that
// functionality works as well. For a mutable buffer, the implementation also
// modifies the bytes that were consumed so tests can make sure that the
// `parse_mut` function was actually called and that the bytes are mutable.
struct TestParsablePacket {}
impl<B: ByteSlice> ParsablePacket<B, &[u8]> for TestParsablePacket {
type Error = ();
fn parse<BV: BufferView<B>>(
mut buffer: BV,
args: &[u8],
) -> Result<TestParsablePacket, ()> {
assert_eq!(buffer.as_ref(), args);
let _: B = buffer.take_front(1).unwrap();
let _: B = buffer.take_back(1).unwrap();
Ok(TestParsablePacket {})
}
fn parse_mut<BV: BufferViewMut<B>>(
mut buffer: BV,
args: &[u8],
) -> Result<TestParsablePacket, ()>
where
B: ByteSliceMut,
{
assert_eq!(buffer.as_ref(), args);
buffer.take_front(1).unwrap().as_mut()[0] += 1;
buffer.take_back(1).unwrap().as_mut()[0] += 2;
Ok(TestParsablePacket {})
}
fn parse_metadata(&self) -> ParseMetadata {
unimplemented!()
}
}
// immutable byte slices
let mut buf = &[0, 1, 2, 3, 4, 5, 6, 7][..];
let TestParsablePacket {} =
buf.parse_with::<_, TestParsablePacket>(&[0, 1, 2, 3, 4, 5, 6, 7]).unwrap();
// test that, after parsing, the bytes consumed are consumed permanently
let TestParsablePacket {} =
buf.parse_with::<_, TestParsablePacket>(&[1, 2, 3, 4, 5, 6]).unwrap();
// test that different temporary values do not affect one another and
// also that slicing works properly (in that the elements outside of the
// slice are not exposed in the BufferView[Mut]; this is fairly obvious
// for slices, but less obvious for Buf, which we test below)
let buf = &[0, 1, 2, 3, 4, 5, 6, 7][..];
let TestParsablePacket {} =
(&buf[1..7]).parse_with::<_, TestParsablePacket>(&[1, 2, 3, 4, 5, 6]).unwrap();
let TestParsablePacket {} =
(&buf[1..7]).parse_with::<_, TestParsablePacket>(&[1, 2, 3, 4, 5, 6]).unwrap();
// mutable byte slices
let mut bytes = [0, 1, 2, 3, 4, 5, 6, 7];
let mut buf = &mut bytes[..];
let TestParsablePacket {} =
buf.parse_with::<_, TestParsablePacket>(&[0, 1, 2, 3, 4, 5, 6, 7]).unwrap();
// test that, after parsing, the bytes consumed are consumed permanently
let TestParsablePacket {} =
buf.parse_with::<_, TestParsablePacket>(&[1, 2, 3, 4, 5, 6]).unwrap();
// test that this also works with parse_with_mut
let TestParsablePacket {} =
buf.parse_with_mut::<_, TestParsablePacket>(&[2, 3, 4, 5]).unwrap();
let TestParsablePacket {} = buf.parse_with_mut::<_, TestParsablePacket>(&[3, 4]).unwrap();
assert_eq!(bytes, [0, 1, 3, 4, 6, 7, 6, 7]);
// test that different temporary values do not affect one another and
// also that slicing works properly (in that the elements outside of the
// slice are not exposed in the BufferView[Mut]; this is fairly obvious
// for slices, but less obvious for Buf, which we test below)
let buf = &mut [0, 1, 2, 3, 4, 5, 6, 7][..];
let TestParsablePacket {} =
(&buf[1..7]).parse_with::<_, TestParsablePacket>(&[1, 2, 3, 4, 5, 6]).unwrap();
let TestParsablePacket {} =
(&buf[1..7]).parse_with::<_, TestParsablePacket>(&[1, 2, 3, 4, 5, 6]).unwrap();
let TestParsablePacket {} =
(&mut buf[1..7]).parse_with_mut::<_, TestParsablePacket>(&[1, 2, 3, 4, 5, 6]).unwrap();
let TestParsablePacket {} =
(&mut buf[1..7]).parse_with_mut::<_, TestParsablePacket>(&[2, 2, 3, 4, 5, 8]).unwrap();
assert_eq!(buf, &[0, 3, 2, 3, 4, 5, 10, 7][..]);
// Buf with immutable byte slice
let mut buf = Buf::new(&[0, 1, 2, 3, 4, 5, 6, 7][..], ..);
let TestParsablePacket {} =
buf.parse_with::<_, TestParsablePacket>(&[0, 1, 2, 3, 4, 5, 6, 7]).unwrap();
// test that, after parsing, the bytes consumed are consumed permanently
let TestParsablePacket {} =
buf.parse_with::<_, TestParsablePacket>(&[1, 2, 3, 4, 5, 6]).unwrap();
// the same test again, but this time with Buf's range set
let mut buf = Buf::new(&[0, 1, 2, 3, 4, 5, 6, 7][..], 1..7);
let TestParsablePacket {} =
buf.parse_with::<_, TestParsablePacket>(&[1, 2, 3, 4, 5, 6]).unwrap();
// test that, after parsing, the bytes consumed are consumed permanently
let TestParsablePacket {} = buf.parse_with::<_, TestParsablePacket>(&[2, 3, 4, 5]).unwrap();
// Buf with mutable byte slice
let mut bytes = [0, 1, 2, 3, 4, 5, 6, 7];
let buf = &mut bytes[..];
let mut buf = Buf::new(&mut buf[..], ..);
let TestParsablePacket {} =
buf.parse_with::<_, TestParsablePacket>(&[0, 1, 2, 3, 4, 5, 6, 7]).unwrap();
// test that, after parsing, the bytes consumed are consumed permanently
let TestParsablePacket {} =
buf.parse_with::<_, TestParsablePacket>(&[1, 2, 3, 4, 5, 6]).unwrap();
// test that this also works with parse_with_mut
let TestParsablePacket {} =
buf.parse_with_mut::<_, TestParsablePacket>(&[2, 3, 4, 5]).unwrap();
let TestParsablePacket {} = buf.parse_with_mut::<_, TestParsablePacket>(&[3, 4]).unwrap();
assert_eq!(bytes, [0, 1, 3, 4, 6, 7, 6, 7]);
// the same test again, but this time with Buf's range set
let mut bytes = [0, 1, 2, 3, 4, 5, 6, 7];
let buf = &mut bytes[..];
let mut buf = Buf::new(&mut buf[..], 1..7);
let TestParsablePacket {} =
buf.parse_with::<_, TestParsablePacket>(&[1, 2, 3, 4, 5, 6]).unwrap();
// test that, after parsing, the bytes consumed are consumed permanently
let TestParsablePacket {} = buf.parse_with::<_, TestParsablePacket>(&[2, 3, 4, 5]).unwrap();
assert_eq!(bytes, [0, 1, 2, 3, 4, 5, 6, 7]);
// test that this also works with parse_with_mut
let mut bytes = [0, 1, 2, 3, 4, 5, 6, 7];
let buf = &mut bytes[..];
let mut buf = Buf::new(&mut buf[..], 1..7);
let TestParsablePacket {} =
buf.parse_with_mut::<_, TestParsablePacket>(&[1, 2, 3, 4, 5, 6]).unwrap();
let TestParsablePacket {} =
buf.parse_with_mut::<_, TestParsablePacket>(&[2, 3, 4, 5]).unwrap();
assert_eq!(bytes, [0, 2, 3, 3, 4, 7, 8, 7]);
}
#[test]
fn test_buf_shrink_to() {
// Tests the shrink_front_to and shrink_back_to methods.
fn test(buf: &[u8], shrink_to: usize, size_after: usize) {
let mut buf0 = &buf[..];
buf0.shrink_front_to(shrink_to);
assert_eq!(buf0.len(), size_after);
let mut buf1 = &buf[..];
buf1.shrink_back_to(shrink_to);
assert_eq!(buf0.len(), size_after);
}
test(&[0, 1, 2, 3], 2, 2);
test(&[0, 1, 2, 3], 4, 4);
test(&[0, 1, 2, 3], 8, 4);
}
#[test]
fn test_empty_buf() {
// Test ParseBuffer impl
assert_eq!(EmptyBuf.as_ref(), []);
assert_eq!(EmptyBuf.as_mut(), []);
EmptyBuf.shrink_front(0);
EmptyBuf.shrink_back(0);
struct DummyParsablePacket;
impl<B: ByteSlice> ParsablePacket<B, ()> for DummyParsablePacket {
type Error = Never;
fn parse<BV: BufferView<B>>(buffer: BV, _args: ()) -> Result<Self, Self::Error> {
assert_eq!(buffer.as_ref(), []);
Ok(DummyParsablePacket)
}
fn parse_mut<BV: BufferViewMut<B>>(
mut buffer: BV,
_args: (),
) -> Result<Self, Self::Error>
where
B: ByteSliceMut,
{
assert_eq!(buffer.as_mut(), []);
Ok(DummyParsablePacket)
}
fn parse_metadata(&self) -> ParseMetadata {
unimplemented!()
}
}
// Test Buffer impl
assert_eq!(EmptyBuf.prefix_len(), 0);
assert_eq!(EmptyBuf.suffix_len(), 0);
EmptyBuf.grow_front(0);
EmptyBuf.grow_back(0);
// Test BufferView impl
assert_eq!(BufferView::<&[u8]>::take_front(&mut EmptyBuf, 0), Some(&[][..]));
assert_eq!(BufferView::<&[u8]>::take_front(&mut EmptyBuf, 1), None);
assert_eq!(BufferView::<&[u8]>::take_back(&mut EmptyBuf, 0), Some(&[][..]));
assert_eq!(BufferView::<&[u8]>::take_back(&mut EmptyBuf, 1), None);
assert_eq!(BufferView::<&[u8]>::into_rest(EmptyBuf), &[][..]);
}
// Each panic test case needs to be in its own function, which results in an
// explosion of test functions. These macros generates the appropriate
// function definitions automatically for a given type, reducing the amount
// of code by a factor of ~4.
macro_rules! make_parse_buffer_panic_tests {
(
$new_empty_buffer:expr,
$shrink_panics:ident,
$nonsense_shrink_panics:ident,
) => {
#[test]
#[should_panic]
fn $shrink_panics() {
($new_empty_buffer).shrink(..1);
}
#[test]
#[should_panic]
fn $nonsense_shrink_panics() {
#[allow(clippy::reversed_empty_ranges)] // Intentionally testing with invalid range
($new_empty_buffer).shrink(1..0);
}
};
}
macro_rules! make_panic_tests {
(
$new_empty_buffer:expr,
$shrink_panics:ident,
$nonsense_shrink_panics:ident,
$grow_front_panics:ident,
$grow_back_panics:ident,
) => {
make_parse_buffer_panic_tests!(
$new_empty_buffer,
$shrink_panics,
$nonsense_shrink_panics,
);
#[test]
#[should_panic]
fn $grow_front_panics() {
($new_empty_buffer).grow_front(1);
}
#[test]
#[should_panic]
fn $grow_back_panics() {
($new_empty_buffer).grow_back(1);
}
};
}
make_parse_buffer_panic_tests!(
&[][..],
test_byte_slice_shrink_panics,
test_byte_slice_nonsense_shrink_panics,
);
make_parse_buffer_panic_tests!(
&mut [][..],
test_byte_slice_mut_shrink_panics,
test_byte_slice_mut_nonsense_shrink_panics,
);
make_panic_tests!(
Either::A::<Buf<&[u8]>, Buf<&[u8]>>(Buf::new(&[][..], ..)),
test_either_slice_panics,
test_either_nonsense_slice_panics,
test_either_grow_front_panics,
test_either_grow_back_panics,
);
make_panic_tests!(
Buf::new(&[][..], ..),
test_buf_shrink_panics,
test_buf_nonsense_shrink_panics,
test_buf_grow_front_panics,
test_buf_grow_back_panics,
);
make_panic_tests!(
EmptyBuf,
test_empty_buf_shrink_panics,
test_empty_buf_nonsense_shrink_panics,
test_empty_buf_grow_front_panics,
test_empty_buf_grow_back_panics,
);
#[test]
fn take_rest_front_back() {
let buf = [1_u8, 2, 3];
let mut b = &mut &buf[..];
assert_eq!(b.take_rest_front(), &buf[..]);
assert_eq!(b.len(), 0);
let mut b = &mut &buf[..];
assert_eq!(b.take_rest_back(), &buf[..]);
assert_eq!(b.len(), 0);
}
#[test]
fn take_byte_front_back() {
let buf = [1_u8, 2, 3, 4];
let mut b = &mut &buf[..];
assert_eq!(b.take_byte_front().unwrap(), 1);
assert_eq!(b.take_byte_front().unwrap(), 2);
assert_eq!(b.take_byte_back().unwrap(), 4);
assert_eq!(b.take_byte_back().unwrap(), 3);
assert!(b.take_byte_front().is_none());
assert!(b.take_byte_back().is_none());
}
#[test]
fn with_header_mut_with_meta() {
#[derive(zerocopy::FromZeros, FromBytes, AsBytes, NoCell, Unaligned)]
#[repr(C)]
struct Header {
two_bytes: [u8; 2],
}
struct TestParsablePacket<B> {
header: Ref<B, Header>,
}
#[derive(Debug)]
struct ParseError;
impl<B: ByteSlice> ParsablePacket<B, ()> for TestParsablePacket<B> {
type Error = ParseError;
fn parse<BV: BufferView<B>>(
mut buffer: BV,
_args: (),
) -> Result<TestParsablePacket<B>, ParseError> {
let header = buffer.take_obj_front::<Header>().ok_or(ParseError)?;
Ok(TestParsablePacket { header })
}
fn parse_mut<BV: BufferViewMut<B>>(
mut buffer: BV,
_args: (),
) -> Result<TestParsablePacket<B>, ParseError>
where
B: ByteSliceMut,
{
let header = buffer.take_obj_front::<Header>().ok_or(ParseError)?;
Ok(TestParsablePacket { header })
}
fn parse_metadata(&self) -> ParseMetadata {
let header_len = self.header.bytes().len();
ParseMetadata::from_packet(header_len, 0, 0)
}
}
// Parse the packet.
let mut buf = Buf::new(vec![0, 1, 2, 3], ..);
let outer = buf.parse::<TestParsablePacket<_>>().unwrap();
assert_eq!(outer.header.two_bytes, [0, 1]);
// We should be able to access the header we just parsed using its
// ParseMetadata.
let meta = outer.parse_metadata();
buf.with_header_mut_with_meta(meta, |mut header| {
let TestParsablePacket { mut header } =
header.parse_mut::<TestParsablePacket<_>>().unwrap();
assert_eq!(header.two_bytes, [0, 1]);
header.two_bytes = [2, 3];
});
// If we undo the parse and extract the inner buffer, we should be able
// to see that the header of the outer packet was modified.
buf.undo_parse(meta);
assert_eq!(buf.into_inner(), vec![2, 3, 2, 3]);
}
}