// 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.

//! Serialization.

use std::cmp;
use std::convert::Infallible as Never;
use std::fmt::{self, Debug, Formatter};
use std::ops::{Range, RangeBounds};

use arrayvec::ArrayVec;
use zerocopy::ByteSlice;

use crate::{
    canonicalize_range, take_back, take_back_mut, take_front, take_front_mut,
    AsFragmentedByteSlice, BufferMut, BufferView, BufferViewMut, ContiguousBuffer,
    ContiguousBufferImpl, ContiguousBufferMut, ContiguousBufferMutImpl, EmptyBuf, FragmentedBuffer,
    FragmentedBufferMut, FragmentedBytes, FragmentedBytesMut, GrowBuffer, GrowBufferMut,
    ParsablePacket, ParseBuffer, ParseBufferMut, ReusableBuffer, SerializeBuffer, ShrinkBuffer,
    TargetBuffer,
};

const MAX_USIZE: usize = core::usize::MAX;

/// Either of two buffers.
///
/// An `Either` wraps one of two different buffer types. It implements all of
/// the relevant traits by calling the corresponding methods on the wrapped
/// buffer.
#[derive(Copy, Clone, Debug)]
pub enum Either<A, B> {
    A(A),
    B(B),
}

impl<A, B> Either<A, B> {
    /// Maps the `A` variant of an `Either`.
    ///
    /// Given an `Either<A, B>` and a function from `A` to `AA`, `map_a`
    /// produces an `Either<AA, B>` by applying the function to the `A` variant
    /// or passing on the `B` variant unmodified.
    pub fn map_a<AA, F: FnOnce(A) -> AA>(self, f: F) -> Either<AA, B> {
        match self {
            Either::A(a) => Either::A(f(a)),
            Either::B(b) => Either::B(b),
        }
    }

    /// Maps the `B` variant of an `Either`.
    ///
    /// Given an `Either<A, B>` and a function from `B` to `BB`, `map_b`
    /// produces an `Either<A, BB>` by applying the function to the `B` variant
    /// or passing on the `A` variant unmodified.
    pub fn map_b<BB, F: FnOnce(B) -> BB>(self, f: F) -> Either<A, BB> {
        match self {
            Either::A(a) => Either::A(a),
            Either::B(b) => Either::B(f(b)),
        }
    }

    /// Returns the `A` variant in an `Either<A, B>`.
    ///
    /// # Panics
    ///
    /// Panics if this `Either<A, B>` does not hold the `A` variant.
    pub fn unwrap_a(self) -> A {
        match self {
            Either::A(x) => x,
            Either::B(_) => panic!("This `Either<A, B>` does not hold the `A` variant"),
        }
    }

    /// Returns the `B` variant in an `Either<A, B>`.
    ///
    /// # Panics
    ///
    /// Panics if this `Either<A, B>` does not hold the `B` variant.
    pub fn unwrap_b(self) -> B {
        match self {
            Either::A(_) => panic!("This `Either<A, B>` does not hold the `B` variant"),
            Either::B(x) => x,
        }
    }
}

impl<A> Either<A, A> {
    /// Returns the inner value held by this `Either` when both possible values
    /// `Either::A` and `Either::B` contain the same inner types.
    pub fn into_inner(self) -> A {
        match self {
            Either::A(x) => x,
            Either::B(x) => x,
        }
    }
}

impl<A> Either<A, Never> {
    /// Returns the `A` value in an `Either<A, Never>`.
    #[inline]
    pub fn into_a(self) -> A {
        match self {
            Either::A(a) => a,
            Either::B(never) => match never {},
        }
    }
}

impl<B> Either<Never, B> {
    /// Returns the `B` value in an `Either<Never, B>`.
    #[inline]
    pub fn into_b(self) -> B {
        match self {
            Either::A(never) => match never {},
            Either::B(b) => b,
        }
    }
}

macro_rules! call_method_on_either {
    ($val:expr, $method:ident, $($args:expr),*) => {
        match $val {
            Either::A(a) => a.$method($($args),*),
            Either::B(b) => b.$method($($args),*),
        }
    };
    ($val:expr, $method:ident) => {
        call_method_on_either!($val, $method,)
    };
}

// NOTE(joshlf): We override the default implementations of all methods for
// Either. Many of the default implementations make multiple calls to other
// Buffer methods, each of which performs a match statement to figure out which
// Either variant is present. We assume that doing this match once is more
// performant than doing it multiple times.

impl<A, B> FragmentedBuffer for Either<A, B>
where
    A: FragmentedBuffer,
    B: FragmentedBuffer,
{
    fn len(&self) -> usize {
        call_method_on_either!(self, len)
    }

    fn with_bytes<R, F>(&self, f: F) -> R
    where
        F: for<'a, 'b> FnOnce(FragmentedBytes<'a, 'b>) -> R,
    {
        call_method_on_either!(self, with_bytes, f)
    }
}

impl<A, B> ContiguousBuffer for Either<A, B>
where
    A: ContiguousBuffer,
    B: ContiguousBuffer,
{
}

impl<A, B> ContiguousBufferMut for Either<A, B>
where
    A: ContiguousBufferMut,
    B: ContiguousBufferMut,
{
}

impl<A, B> ShrinkBuffer for Either<A, B>
where
    A: ShrinkBuffer,
    B: ShrinkBuffer,
{
    fn shrink<R: RangeBounds<usize>>(&mut self, range: R) {
        call_method_on_either!(self, shrink, range)
    }
    fn shrink_front(&mut self, n: usize) {
        call_method_on_either!(self, shrink_front, n)
    }
    fn shrink_back(&mut self, n: usize) {
        call_method_on_either!(self, shrink_back, n)
    }
}

impl<A, B> ParseBuffer for Either<A, B>
where
    A: ParseBuffer,
    B: ParseBuffer,
{
    fn parse<'a, P: ParsablePacket<&'a [u8], ()>>(&'a mut self) -> Result<P, P::Error> {
        call_method_on_either!(self, parse)
    }
    fn parse_with<'a, ParseArgs, P: ParsablePacket<&'a [u8], ParseArgs>>(
        &'a mut self,
        args: ParseArgs,
    ) -> Result<P, P::Error> {
        call_method_on_either!(self, parse_with, args)
    }
}

impl<A, B> FragmentedBufferMut for Either<A, B>
where
    A: FragmentedBufferMut,
    B: FragmentedBufferMut,
{
    fn with_bytes_mut<R, F>(&mut self, f: F) -> R
    where
        F: for<'a, 'b> FnOnce(FragmentedBytesMut<'a, 'b>) -> R,
    {
        call_method_on_either!(self, with_bytes_mut, f)
    }
}

impl<A, B> ParseBufferMut for Either<A, B>
where
    A: ParseBufferMut,
    B: ParseBufferMut,
{
    fn parse_mut<'a, P: ParsablePacket<&'a mut [u8], ()>>(&'a mut self) -> Result<P, P::Error> {
        call_method_on_either!(self, parse_mut)
    }
    fn parse_with_mut<'a, ParseArgs, P: ParsablePacket<&'a mut [u8], ParseArgs>>(
        &'a mut self,
        args: ParseArgs,
    ) -> Result<P, P::Error> {
        call_method_on_either!(self, parse_with_mut, args)
    }
}

impl<A, B> GrowBuffer for Either<A, B>
where
    A: GrowBuffer,
    B: GrowBuffer,
{
    fn capacity(&self) -> usize {
        call_method_on_either!(self, capacity)
    }
    fn prefix_len(&self) -> usize {
        call_method_on_either!(self, prefix_len)
    }
    fn suffix_len(&self) -> usize {
        call_method_on_either!(self, suffix_len)
    }
    fn grow_front(&mut self, n: usize) {
        call_method_on_either!(self, grow_front, n)
    }
    fn grow_back(&mut self, n: usize) {
        call_method_on_either!(self, grow_back, n)
    }
    fn reset(&mut self) {
        call_method_on_either!(self, reset)
    }
}

impl<A, B> TargetBuffer for Either<A, B>
where
    A: TargetBuffer,
    B: TargetBuffer,
{
    fn with_parts<O, F>(&mut self, f: F) -> O
    where
        F: for<'a, 'b> FnOnce(&'a mut [u8], FragmentedBytesMut<'a, 'b>, &'a mut [u8]) -> O,
    {
        call_method_on_either!(self, with_parts, f)
    }

    fn serialize<BB: PacketBuilder>(&mut self, c: PacketConstraints, builder: BB) {
        call_method_on_either!(self, serialize, c, builder)
    }
}

impl<A: AsRef<[u8]>, B: AsRef<[u8]>> AsRef<[u8]> for Either<A, B> {
    fn as_ref(&self) -> &[u8] {
        call_method_on_either!(self, as_ref)
    }
}

impl<A: AsMut<[u8]>, B: AsMut<[u8]>> AsMut<[u8]> for Either<A, B> {
    fn as_mut(&mut self) -> &mut [u8] {
        call_method_on_either!(self, as_mut)
    }
}

/// A byte slice wrapper providing buffer functionality.
///
/// A `Buf` wraps a byte slice (a type which implements `AsRef<[u8]>` or
/// `AsMut<[u8]>`) and implements various buffer traits by keeping track of
/// prefix, body, and suffix offsets within the byte slice.
#[derive(Clone, Debug)]
#[cfg_attr(test, derive(Eq, PartialEq))]
pub struct Buf<B> {
    buf: B,
    range: Range<usize>,
}

impl<B: AsRef<[u8]>> Buf<B> {
    /// Constructs a new `Buf`.
    ///
    /// `new` constructs a new `Buf` from a buffer and a range. The bytes within
    /// the range will be the body, the bytes before the range will be the
    /// prefix, and the bytes after the range will be the suffix.
    ///
    /// # Panics
    ///
    /// `new` panics if `range` is out of bounds of `buf`, or if it is
    /// nonsensical (the end precedes the start).
    pub fn new<R: RangeBounds<usize>>(buf: B, range: R) -> Buf<B> {
        let len = buf.as_ref().len();
        Buf { buf, range: canonicalize_range(len, &range) }
    }

    /// Constructs a [`BufView`] which will be a [`BufferView`] into this `Buf`.
    pub fn buffer_view(&mut self) -> BufView<'_> {
        BufView { buf: &self.buf.as_ref()[self.range.clone()], range: &mut self.range }
    }
}

impl<B: AsRef<[u8]> + AsMut<[u8]>> Buf<B> {
    /// Constructs a [`BufViewMut`] which will be a [`BufferViewMut`] into this `Buf`.
    pub fn buffer_view_mut(&mut self) -> BufViewMut<'_> {
        BufViewMut { buf: &mut self.buf.as_mut()[self.range.clone()], range: &mut self.range }
    }
}

impl<B: AsRef<[u8]>> ContiguousBufferImpl for Buf<B> {}
impl<B: AsRef<[u8]>> ShrinkBuffer for Buf<B> {
    fn shrink<R: RangeBounds<usize>>(&mut self, range: R) {
        let len = self.len();
        let mut range = canonicalize_range(len, &range);
        range.start += self.range.start;
        range.end += self.range.start;
        self.range = range;
    }

    fn shrink_front(&mut self, n: usize) {
        assert!(n <= self.len());
        self.range.start += n;
    }
    fn shrink_back(&mut self, n: usize) {
        assert!(n <= self.len());
        self.range.end -= n;
    }
}
impl<B: AsRef<[u8]>> ParseBuffer for Buf<B> {
    fn parse_with<'a, ParseArgs, P: ParsablePacket<&'a [u8], ParseArgs>>(
        &'a mut self,
        args: ParseArgs,
    ) -> Result<P, P::Error> {
        P::parse(self.buffer_view(), args)
    }
}

impl<B: AsRef<[u8]> + AsMut<[u8]>> ParseBufferMut for Buf<B> {
    fn parse_with_mut<'a, ParseArgs, P: ParsablePacket<&'a mut [u8], ParseArgs>>(
        &'a mut self,
        args: ParseArgs,
    ) -> Result<P, P::Error> {
        P::parse_mut(self.buffer_view_mut(), args)
    }
}

impl<B: AsRef<[u8]>> GrowBuffer for Buf<B> {
    fn capacity(&self) -> usize {
        self.buf.as_ref().len()
    }
    fn prefix_len(&self) -> usize {
        self.range.start
    }
    fn suffix_len(&self) -> usize {
        self.buf.as_ref().len() - self.range.end
    }
    fn grow_front(&mut self, n: usize) {
        assert!(n <= self.range.start);
        self.range.start -= n;
    }
    fn grow_back(&mut self, n: usize) {
        assert!(n <= self.buf.as_ref().len() - self.range.end);
        self.range.end += n;
    }
}
impl<B: AsRef<[u8]> + AsMut<[u8]>> ContiguousBufferMutImpl for Buf<B> {}
impl<B: AsRef<[u8]> + AsMut<[u8]>> TargetBuffer for Buf<B> {
    fn with_parts<O, F>(&mut self, f: F) -> O
    where
        F: for<'a, 'b> FnOnce(&'a mut [u8], FragmentedBytesMut<'a, 'b>, &'a mut [u8]) -> O,
    {
        let (prefix, buf) = self.buf.as_mut().split_at_mut(self.range.start);
        let (body, suffix) = buf.split_at_mut(self.range.end - self.range.start);
        let mut body = [&mut body[..]];
        f(prefix, body.as_fragmented_byte_slice(), suffix)
    }
}

impl<B: AsRef<[u8]>> AsRef<[u8]> for Buf<B> {
    fn as_ref(&self) -> &[u8] {
        &self.buf.as_ref()[self.range.clone()]
    }
}

impl<B: AsMut<[u8]>> AsMut<[u8]> for Buf<B> {
    fn as_mut(&mut self) -> &mut [u8] {
        &mut self.buf.as_mut()[self.range.clone()]
    }
}

/// A [`BufferView`] into a [`Buf`].
///
/// A `BufView` is constructed by [`Buf::buffer_view`], and implements
/// `BufferView`, providing a view into the `Buf` from which it was constructed.
pub struct BufView<'a> {
    buf: &'a [u8],
    range: &'a mut Range<usize>,
}

impl<'a> BufferView<&'a [u8]> for BufView<'a> {
    fn take_front(&mut self, n: usize) -> Option<&'a [u8]> {
        if self.len() < n {
            return None;
        }
        self.range.start += n;
        Some(take_front(&mut self.buf, n))
    }

    fn take_back(&mut self, n: usize) -> Option<&'a [u8]> {
        if self.len() < n {
            return None;
        }
        self.range.end -= n;
        Some(take_back(&mut self.buf, n))
    }

    fn into_rest(self) -> &'a [u8] {
        self.buf
    }
}

impl<'a> AsRef<[u8]> for BufView<'a> {
    fn as_ref(&self) -> &[u8] {
        self.buf
    }
}

/// A [`BufferViewMut`] into a [`Buf`].
///
/// A `BufViewMut` is constructed by [`Buf::buffer_view_mut`], and implements
/// `BufferViewMut`, providing a mutable view into the `Buf` from which it was
/// constructed.
pub struct BufViewMut<'a> {
    buf: &'a mut [u8],
    range: &'a mut Range<usize>,
}

impl<'a> BufferView<&'a mut [u8]> for BufViewMut<'a> {
    fn take_front(&mut self, n: usize) -> Option<&'a mut [u8]> {
        if self.len() < n {
            return None;
        }
        self.range.start += n;
        Some(take_front_mut(&mut self.buf, n))
    }

    fn take_back(&mut self, n: usize) -> Option<&'a mut [u8]> {
        if self.len() < n {
            return None;
        }
        self.range.end -= n;
        Some(take_back_mut(&mut self.buf, n))
    }

    fn into_rest(self) -> &'a mut [u8] {
        self.buf
    }
}

impl<'a> BufferViewMut<&'a mut [u8]> for BufViewMut<'a> {}

impl<'a> AsRef<[u8]> for BufViewMut<'a> {
    fn as_ref(&self) -> &[u8] {
        self.buf
    }
}

impl<'a> AsMut<[u8]> for BufViewMut<'a> {
    fn as_mut(&mut self) -> &mut [u8] {
        self.buf
    }
}

/// The constraints required by a [`PacketBuilder`].
///
/// `PacketConstraints` represents the constraints that must be satisfied in
/// order to serialize a `PacketBuilder`.
///
/// A `PacketConstraints`, `c`, guarantees two properties:
/// - `c.max_body_len() >= c.min_body_len()`
/// - `c.header_len() + c.min_body_len() + c.footer_len()` does not overflow
///   `usize`
///
/// It is not possible (using safe code) to obtain a `PacketConstraints` which
/// violates these properties, so code may rely for its correctness on the
/// assumption that these properties hold.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct PacketConstraints {
    header_len: usize,
    footer_len: usize,
    min_body_len: usize,
    max_body_len: usize,
}

impl PacketConstraints {
    /// Constructs a new `PacketConstraints`.
    ///
    /// # Panics
    ///
    /// `new` panics if the arguments violate the validity properties of
    /// `PacketConstraints` - if `max_body_len < min_body_len`, or if
    /// `header_len + min_body_len + footer_len` overflows `usize`.
    #[inline]
    pub fn new(
        header_len: usize,
        footer_len: usize,
        min_body_len: usize,
        max_body_len: usize,
    ) -> PacketConstraints {
        PacketConstraints::try_new(header_len, footer_len, min_body_len, max_body_len).expect(
            "max_body_len < min_body_len or header_len + min_body_len + footer_len overflows usize",
        )
    }

    /// Tries to construct a new `PacketConstraints`.
    ///
    /// `new` returns `None` if the provided values violate the validity
    /// properties of `PacketConstraints` - if `max_body_len < min_body_len`, or
    /// if `header_len + min_body_len + footer_len` overflows `usize`.
    #[inline]
    pub fn try_new(
        header_len: usize,
        footer_len: usize,
        min_body_len: usize,
        max_body_len: usize,
    ) -> Option<PacketConstraints> {
        // Test case 3 in test_nested_packet_builder
        let header_min_body_footer_overflows = header_len
            .checked_add(min_body_len)
            .and_then(|sum| sum.checked_add(footer_len))
            .is_none();
        // Test case 5 in test_nested_packet_builder
        let max_less_than_min = max_body_len < min_body_len;
        if max_less_than_min || header_min_body_footer_overflows {
            return None;
        }
        Some(PacketConstraints { header_len, footer_len, min_body_len, max_body_len })
    }

    /// The number of bytes in this packet's header.
    #[inline]
    pub fn header_len(&self) -> usize {
        self.header_len
    }

    /// The number of bytes in this packet's footer.
    #[inline]
    pub fn footer_len(&self) -> usize {
        self.footer_len
    }

    /// The minimum body length (in bytes) required by this packet in order to
    /// avoid adding padding.
    ///
    /// `min_body_len` returns the minimum number of body bytes required in
    /// order to avoid adding padding. Note that, if padding bytes are required,
    /// they may not necessarily belong immediately following the body,
    /// depending on which packet layer imposes the minimum. In particular, in a
    /// nested packet, padding goes after the body of the layer which imposes
    /// the minimum. This means that, if the layer that imposes the minimum is
    /// not the innermost one, then padding must be added not after the
    /// innermost body, but instead in between footers.
    /// [`NestedPacketBuilder::serialize_into`] is responsible for inserting
    /// padding when serializing nested packets.
    ///
    /// If there is no minimum body length, this returns 0.
    #[inline]
    pub fn min_body_len(&self) -> usize {
        self.min_body_len
    }

    /// The maximum length (in bytes) of a body allowed by this packet.
    ///
    /// If there is no maximum body length, this returns `core::usize::MAX`.
    #[inline]
    pub fn max_body_len(&self) -> usize {
        self.max_body_len
    }
}

/// A builder capable of serializing a packet's headers and footers.
///
/// A `PacketBuilder` describes a packet's headers and footers, and is capable
/// of serializing that packet into an existing buffer via the `serialize`
/// method. A `PacketBuilder` never describes a body - one must always be
/// provided in order to call `serialize`.
///
/// Thanks to a blanket implementation, every `PacketBuilder` is also a
/// [`NestedPacketBuilder`]. While a `PacketBuilder` represents exactly one
/// "layer" of a packet - a pair of a header and a footer - a
/// `NestedPacketBuilder` can represent multiple nested layers of a packet, and
/// can be composed from other `NestedPacketBuilder`s. See the trait
/// documentation for more details.
///
/// `()` may be used as an "empty" `PacketBuilder` with no header, footer,
/// minimum body length requirement, or maximum body length requirement.
pub trait PacketBuilder {
    /// Gets the constraints for this `PacketBuilder`.
    fn constraints(&self) -> PacketConstraints;

    /// Serializes this packet into an existing buffer.
    ///
    /// `serialize` is called with a [`SerializeBuffer`] which provides access
    /// to the parts of a buffer corresponding to the header, body, and footer
    /// of this packet. The buffer's body is initialized with the body to be
    /// encapsulated, and `serialize` is responsible for serializing the header
    /// and footer into the appropriate sections of the buffer. The caller is
    /// responsible for ensuring that the body satisfies both the minimum and
    /// maximum body length requirements, possibly by adding padding or
    /// truncating the body.
    ///
    /// This method is usually called from
    /// [`NestedPacketBuilder::serialize_into`], not directly by the user.
    ///
    /// # Security
    ///
    /// `serialize` must initialize of the bytes of the header and footer, even
    /// if only to zero, in order to avoid leaking the contents of packets
    /// previously stored in the same buffer.
    ///
    /// # Panics
    ///
    /// `serialize` may panic if the `SerializeBuffer`'s header or footer are
    /// not large enough to fit the packet's header and footer, or if the body
    /// does not satisfy the minimum or maximum body length requirements.
    fn serialize(&self, buffer: &mut SerializeBuffer<'_, '_>);
}

/// One or more nested [`PacketBuilder`]s.
///
/// A `NestedPacketBuilder` represents one or more `PacketBuilder`s nested
/// inside of each other. Two `NestedPacketBuilder`s, `a` and `b`, can be
/// composed by calling `a.encapsulate(b)`. The resulting `NestedPacketBuilder`
/// has a header comprising `b`'s header followed by `a`'s header, and has a
/// footer comprising `a`'s footer followed by `b`'s footer. It also has minimum
/// and maximum body length requirements which are the composition of those of
/// `a` and `b`. See [`encapsulate`] for more details.
///
/// [`encapsulate`]: crate::serialize::NestedPacketBuilder::encapsulate
pub trait NestedPacketBuilder {
    /// Gets the constraints for this `NestedPacketBuilder`.
    ///
    /// If `constraints` returns `None`, it means that a valid
    /// [`PacketConstraints`] cannot be constructed. Since
    /// `NestedPacketBuilder`s can be nested, multiple valid
    /// `NestedPacketBuilder`s can nest to create an invalid
    /// `NestedPacketBuilder`. This can happen if an inner
    /// `NestedPacketBuilder`'s headers and footers take up more space than an
    /// outer `NestedPacketBuilder`'s maximum body length, so the maximum body
    /// length of this `NestedPacketBuilder` is technically negative. It can
    /// also happen if the header and footer lengths, when summed, overflow
    /// `usize`. In either case, the `PacketConstraints` type cannot represent
    /// the constraints, and no body exists which would satisfy those
    /// constraints (a satisfying body would need to have negative length).
    /// Thus, the correct behavior is to interpret a `None` value as implying
    /// that an MTU error should be reported.
    ///
    /// If `constraints` returns `None`, the caller must not call
    /// [`serialize_into`], or risk unspecified behavior (including possibly a
    /// panic).
    ///
    /// [`serialize_into`]: crate::serialize::NestedPacketBuilder::serialize_into
    fn try_constraints(&self) -> Option<PacketConstraints>;

    /// Serializes this `NestedPacketBuilder` into a buffer.
    ///
    /// `serialize_into` takes a buffer containing a body, and serializes this
    /// `NestedPacketBuilder`'s headers and footers before and after that body.
    /// When `serialize_into` returns, the buffer's body has been expanded to
    /// include the newly-serialized headers and footers.
    ///
    /// If the provided body is smaller than this `NestedPacketBuilder`'s
    /// minimum body length requirement, `serialize_into` will add padding after
    /// the body in order to meet that requriement. If this
    /// `NestedPacketBuilder` comprises multiple other `NestedPacketBuilder`s
    /// with their own minimum body length requirements, then internal padding
    /// may be added between footers in order to meet those requirements. In
    /// particular, padding is always added after the body of the packet with
    /// that requirement (as opposed to after the body of an encapsulated
    /// packet).
    ///
    /// Callers should *not* add their own post-body padding! The minimum body
    /// length requirement might come from a `NestedPacketBuilder` which is not
    /// the innermost one, in which case padding belongs after at least one of
    /// the footers, and adding padding directly after the body would be
    /// incorrect. As described in the previous paragraph, `serialize_into` will
    /// take care of putting padding in the right place.
    ///
    /// # Security
    ///
    /// Any added padding will be zeroed in order to ensure that the contents of
    /// another packet previously stored in the same buffer do not leak.
    ///
    /// # Panics
    ///
    /// `serialize_into` may panic if `buffer` doesn't have enough prefix and
    /// suffix space to hold the headers and footers. In particular, if this
    /// `NestedPacketBuilder` has [`PacketConstraints`] `c`, then `buffer` must
    /// satisfy the following requirements:
    /// - `buffer.prefix_len() >= c.header_len()`
    /// - `buffer.suffix_len() >= c.footer_len()`
    /// - `buffer.len() <= c.max_body_len()`
    /// - If `padding = c.min_body_len().saturating_sub(buffer.len())`, then
    ///   `buffer.suffix_len() >= padding + c.footer_len()`
    ///
    /// Note that the `PacketConstraints` type has certain invariants that make
    /// it easier for implementers to satisfy these preconditions.
    ///
    /// `serialize_into` may exhibit unspecified behavior (including possibly
    /// panicking) if `self.try_constraints()` returns `None`. In order to avoid
    /// a panic, the caller must call that method first, and only call
    /// `serialize_into` if it returns `Some`.
    fn serialize_into<B: TargetBuffer>(&self, buffer: &mut B);

    /// Encapsulates this `NestedPacketBuilder` inside of another one.
    ///
    /// If `a` and `b` are `NestedPacketBuilder`s with [`PacketConstraints`]
    /// `ac` and `bc`, then `a.encapsulate(b)` produces a `NestedPacketBuilder`
    /// with the following properties:
    /// - Its header is equivalent to `b`'s header followed by `a`'s header, and
    ///   has length `bc.header_len() + ac.header_len()`
    /// - Its footer is equivalent to `a`'s footer followed by `b`'s footer, and
    ///   has length `ac.footer_len() + bc.footer_len()`
    /// - Its minimum body length requirement is equal to
    ///   `core::cmp::max(ac.min_body_len(), bc.min_body_len() -
    ///   (ac.header_len() + ac.footer_len()))`
    /// - Its maximum body length requirement is
    ///   `core::cmp::min(ac.max_body_len(), bc.max_body_len() -
    ///   (ac.header_len() + ac.footer_len()))`
    ///
    /// Note that `a` and `b` having valid `PacketConstraints` does *not* imply
    /// that `a.encapsulate(b)` will as well. This could be for one of the
    /// following reasons:
    /// - `b` has a maximum body length requirement which is exceeded by `a`'s
    ///   headers and footers alone (without considering further space occupied
    ///   by a body)
    /// - `b` has a maximum body length requirement which is exceeded by the sum
    ///   of `a`'s header and footers and `a`'s minimum body length requirement
    /// - The `PacketConstraints` would have values that overflow `usize`, such
    ///   as `b`'s header length plus `a`'s header length
    ///
    /// [`serialize_into`]: crate::serialize::NestedPacketBuilder::serialize_into
    #[inline]
    fn encapsulate<O: NestedPacketBuilder>(self, outer: O) -> Nested<Self, O>
    where
        Self: Sized,
    {
        Nested { inner: self, outer }
    }

    // TODO(joshlf): Clarify that the MTU created by with_mtu apply outside of
    // the NestedPacketBuilder.

    /// Constructs a new `NestedPacketBuilder` with an additional MTU
    /// constraint.
    ///
    /// The returned `NestedPacketBuilder` will have a maximum body length
    /// constraint equal to the minimum of its original maximum body length
    /// constraint and `mtu`.
    #[inline]
    fn with_mtu(self, mtu: usize) -> MtuPacketBuilder<Self>
    where
        Self: Sized,
    {
        MtuPacketBuilder { mtu, inner: self }
    }
}

impl<PB: PacketBuilder> NestedPacketBuilder for PB {
    fn try_constraints(&self) -> Option<PacketConstraints> {
        Some(self.constraints())
    }

    fn serialize_into<B: TargetBuffer>(&self, buffer: &mut B) {
        buffer.serialize(self.constraints(), self);
    }
}

impl<'a, B: PacketBuilder> PacketBuilder for &'a B {
    #[inline]
    fn constraints(&self) -> PacketConstraints {
        B::constraints(self)
    }
    #[inline]
    fn serialize(&self, buffer: &mut SerializeBuffer<'_, '_>) {
        B::serialize(self, buffer)
    }
}

impl<'a, B: PacketBuilder> PacketBuilder for &'a mut B {
    #[inline]
    fn constraints(&self) -> PacketConstraints {
        B::constraints(self)
    }
    #[inline]
    fn serialize(&self, buffer: &mut SerializeBuffer<'_, '_>) {
        B::serialize(self, buffer)
    }
}

impl PacketBuilder for () {
    #[inline]
    fn constraints(&self) -> PacketConstraints {
        PacketConstraints { header_len: 0, footer_len: 0, min_body_len: 0, max_body_len: MAX_USIZE }
    }
    #[inline]
    fn serialize(&self, _buffer: &mut SerializeBuffer<'_, '_>) {}
}

impl PacketBuilder for Never {
    fn constraints(&self) -> PacketConstraints {
        match *self {}
    }
    fn serialize(&self, _buffer: &mut SerializeBuffer<'_, '_>) {}
}

/// One object encapsulated in another one.
///
/// `Nested`s are constructed using the [`NestedPacketBuilder::encapsulate`] and
/// [`Serializer::encapsulate`] methods.
///
/// When `I: NestedPacketBuilder` and `O: NestedPacketBuilder`, `Nested<I, O>`
/// implements [`NestedPacketBuilder`]. When `I: Serializer` and `O:
/// NestedPacketBuilder`, `Nested<I, O>` implements [`Serializer`].
#[derive(Copy, Clone, Debug)]
#[cfg_attr(test, derive(Eq, PartialEq))]
pub struct Nested<I, O> {
    inner: I,
    outer: O,
}

impl<I, O> Nested<I, O> {
    /// Consumes this `Nested` and return the inner object, discarding the outer
    /// one.
    #[inline]
    pub fn into_inner(self) -> I {
        self.inner
    }

    /// Consumes this `Nested` and return the outer object, discarding the inner
    /// one.
    #[inline]
    pub fn into_outer(self) -> O {
        self.outer
    }
}

impl<I: NestedPacketBuilder, O: NestedPacketBuilder> NestedPacketBuilder for Nested<I, O> {
    #[inline]
    fn try_constraints(&self) -> Option<PacketConstraints> {
        let inner = self.inner.try_constraints()?;
        let outer = self.outer.try_constraints()?;

        // Test case 1 in test_nested_packet_builder
        let header_len = inner.header_len.checked_add(outer.header_len)?;
        // Test case 2 in test_nested_packet_builder
        let footer_len = inner.footer_len.checked_add(outer.footer_len)?;
        // This is guaranteed not to overflow by the invariants on
        // PacketConstraint.
        let inner_header_footer_len = inner.header_len + inner.footer_len;
        // Note the saturating_sub here - it's OK if the inner PacketBuilder
        // more than satisfies the outer PacketBuilder's minimum body length
        // requirement.
        let min_body_len = cmp::max(
            outer.min_body_len.saturating_sub(inner_header_footer_len),
            inner.min_body_len,
        );
        // Note the checked_sub here - it's NOT OK if the inner PacketBuilder
        // exceeds the outer PacketBuilder's maximum body length requirement.
        //
        // Test case 4 in test_nested_packet_builder
        let max_body_len =
            cmp::min(outer.max_body_len.checked_sub(inner_header_footer_len)?, inner.max_body_len);
        // It's still possible that `min_body_len > max_body_len` or that
        // `header_len + min_body_len + footer_len` overflows `usize`; `try_new`
        // checks those constraints for us.
        PacketConstraints::try_new(header_len, footer_len, min_body_len, max_body_len)
    }

    #[inline]
    fn serialize_into<B: TargetBuffer>(&self, buffer: &mut B) {
        // `serialize_into` is required to serialize padding, and in particular,
        // to serialize it in the right place, immediately following the body of
        // the packet which imposes the minimum body length requirement. This
        // happens naturally as a consequence of the fact that the
        // implementation of `NestedPacketBuilder` for `PB: PacketBuilder` adds
        // its own padding. Inner `PacketBuilder`s which do not have a minimum
        // body length requirement will not add padding and, when the
        // `PacketBuilder` with the minimum body length requirement is reached,
        // padding will still be required (assuming the minimum isn't already
        // satisfied by the original body and headers/footers), and that
        // `PacketBuilder`'s `serialize_into` implementation will add the
        // padding at that point.
        self.inner.serialize_into(buffer);
        self.outer.serialize_into(buffer);
    }
}

// It would be great to just do `impl<'a, PB: NestedPacketBuilder>
// NestedPacketBuilder for &'a PB`, but it would conflict with the blanket impl
// for `PB: PacketBuilder`. This replaces that impl. Note that it's not a big
// deal that we don't have that impl because the one that really matters is
// `PacketBuilder for &PB` where `PB: PacketBuilder` because users of this crate
// only implement the `PacketBuilder` trait.
struct RefNestedPacketBuilder<'a, PB>(&'a PB);

impl<'a, PB: NestedPacketBuilder> NestedPacketBuilder for RefNestedPacketBuilder<'a, PB> {
    fn try_constraints(&self) -> Option<PacketConstraints> {
        self.0.try_constraints()
    }

    fn serialize_into<B: TargetBuffer>(&self, buffer: &mut B) {
        self.0.serialize_into(buffer)
    }
}

/// A `PacketBuilder` with a specific MTU constraint.
///
/// `MtuPacketBuilder`s are constructed using the
/// [`NestedPacketBuilder::with_mtu`] method.
#[derive(Copy, Clone, Debug)]
#[cfg_attr(test, derive(Eq, PartialEq))]
pub struct MtuPacketBuilder<B> {
    mtu: usize,
    inner: B,
}

impl<B> MtuPacketBuilder<B> {
    /// Consumes this `MtuPacketBuilder` and return the inner `PacketBuilder`.
    #[inline]
    pub fn into_inner(self) -> B {
        self.inner
    }
}

impl<PB: NestedPacketBuilder> NestedPacketBuilder for MtuPacketBuilder<PB> {
    #[inline]
    fn try_constraints(&self) -> Option<PacketConstraints> {
        let mut c = self.inner.try_constraints()?;
        // This is guaranteed not to overflow by the invariants on
        // PacketConstraint.
        let header_footer_len = c.header_len + c.footer_len;
        c.max_body_len = cmp::min(self.mtu.checked_sub(header_footer_len)?, c.max_body_len);
        Some(c)
    }

    #[inline]
    fn serialize_into<B: TargetBuffer>(&self, buffer: &mut B) {
        self.inner.serialize_into(buffer)
    }
}

/// A builder capable of serializing packets - which do not encapsulate other
/// packets - into an existing buffer.
///
/// An `InnerPacketBuilder` describes a packet, and is capable of serializing
/// that packet into an existing buffer via the `serialize` method. Unlike the
/// [`PacketBuilder`] trait, it describes a packet which does not encapsulate
/// other packets.
///
/// # Notable implementations
///
/// `InnerPacketBuilder` is implemented for `&[u8]`, `&mut [u8]`, and `Vec<u8>`
/// by treating the contents of the slice/`Vec` as the contents of the packet to
/// be serialized.
pub trait InnerPacketBuilder {
    /// The number of bytes consumed by this packet.
    fn bytes_len(&self) -> usize;

    /// Serializes this packet into an existing buffer.
    ///
    /// `serialize` is called with a buffer of length `self.bytes()`, and is
    /// responsible for serializing the packet into the buffer.
    ///
    /// # Security
    ///
    /// All of the bytes of the buffer should be initialized, even if only to
    /// zero, in order to avoid leaking the contents of packets previously
    /// stored in the same buffer.
    fn serialize(&self, buffer: &mut [u8]);

    /// Converts this `InnerPacketBuilder` into a [`Serializer`].
    ///
    /// `into_serializer` is like [`into_serializer_with`], except that no
    /// buffer is provided for reuse in serialization.
    ///
    /// [`into_serializer_with`]: crate::serialize::InnerPacketBuilder::into_serializer_with
    #[inline]
    fn into_serializer(self) -> InnerSerializer<Self, EmptyBuf>
    where
        Self: Sized,
    {
        self.into_serializer_with(EmptyBuf)
    }

    /// Converts this `InnerPacketBuilder` into a [`Serializer`] with a buffer
    /// that can be used for serialization.
    ///
    /// `into_serializer_with` consumes a buffer and converts this
    /// `InnerPacketBuilder` into a type which implements `Serialize` by
    /// treating it as the innermost body to be contained within any
    /// encapsulating `PacketBuilder`s. During serialization, the buffer will be
    /// provided to the [`BufferProvider`], allowing it to reuse the buffer for
    /// serialization and avoid allocating a new one if possible.
    ///
    /// The `buffer` will have its body shrunk to be zero bytes before the
    /// `InnerSerializer` is constructed.
    fn into_serializer_with<B: BufferMut>(self, mut buffer: B) -> InnerSerializer<Self, B>
    where
        Self: Sized,
    {
        buffer.shrink_back_to(0);
        InnerSerializer { inner: self, buffer }
    }
}

impl<'a, I: InnerPacketBuilder> InnerPacketBuilder for &'a I {
    #[inline]
    fn bytes_len(&self) -> usize {
        I::bytes_len(self)
    }
    #[inline]
    fn serialize(&self, buffer: &mut [u8]) {
        I::serialize(self, buffer)
    }
}
impl<'a, I: InnerPacketBuilder> InnerPacketBuilder for &'a mut I {
    #[inline]
    fn bytes_len(&self) -> usize {
        I::bytes_len(self)
    }
    #[inline]
    fn serialize(&self, buffer: &mut [u8]) {
        I::serialize(self, buffer)
    }
}
impl<'a> InnerPacketBuilder for &'a [u8] {
    #[inline]
    fn bytes_len(&self) -> usize {
        self.len()
    }
    #[inline]
    fn serialize(&self, buffer: &mut [u8]) {
        buffer.copy_from_slice(self);
    }
}
impl<'a> InnerPacketBuilder for &'a mut [u8] {
    #[inline]
    fn bytes_len(&self) -> usize {
        self.len()
    }
    #[inline]
    fn serialize(&self, buffer: &mut [u8]) {
        buffer.copy_from_slice(self);
    }
}
impl<'a> InnerPacketBuilder for Vec<u8> {
    #[inline]
    fn bytes_len(&self) -> usize {
        self.len()
    }
    #[inline]
    fn serialize(&self, buffer: &mut [u8]) {
        buffer.copy_from_slice(self.as_slice());
    }
}
impl<const N: usize> InnerPacketBuilder for ArrayVec<u8, N> {
    fn bytes_len(&self) -> usize {
        self.as_slice().bytes_len()
    }
    fn serialize(&self, buffer: &mut [u8]) {
        self.as_slice().serialize(buffer);
    }
}

/// An [`InnerPacketBuilder`] created from any `B: ByteSlice`.
///
/// `ByteSliceInnerPacketBuilder<B>` implements `InnerPacketBuilder` so long as
/// `B: ByteSlice`.
pub struct ByteSliceInnerPacketBuilder<B>(pub B);

impl<B: ByteSlice> InnerPacketBuilder for ByteSliceInnerPacketBuilder<B> {
    fn bytes_len(&self) -> usize {
        self.0.deref().bytes_len()
    }
    fn serialize(&self, buffer: &mut [u8]) {
        self.0.deref().serialize(buffer)
    }
}

impl<B: ByteSlice> Debug for ByteSliceInnerPacketBuilder<B> {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(f, "ByteSliceInnerPacketBuilder({:?})", self.0.as_ref())
    }
}

/// An error in serializing a packet.
///
/// `SerializeError` is the type of errors returned from methods on the
/// [`Serializer`] trait. The `Alloc` variant indicates that a new buffer could
/// not be allocated, while the `Mtu` variant indicates that an MTU constraint
/// was exceeded.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum SerializeError<A> {
    /// A new buffer could not be allocated.
    Alloc(A),
    /// An MTU constraint was exceeded.
    Mtu,
}

impl<A> SerializeError<A> {
    /// Is this `SerializeError::Alloc`?
    #[inline]
    pub fn is_alloc(&self) -> bool {
        match self {
            SerializeError::Alloc(_) => true,
            SerializeError::Mtu => false,
        }
    }

    /// Is this `SerializeError::Mtu`?
    #[inline]
    pub fn is_mtu(&self) -> bool {
        match self {
            SerializeError::Alloc(_) => false,
            SerializeError::Mtu => true,
        }
    }
}

impl<A> From<A> for SerializeError<A> {
    fn from(a: A) -> SerializeError<A> {
        SerializeError::Alloc(a)
    }
}

/// The error returned when a buffer is too short to hold a serialized packet,
/// and the [`BufferProvider`] is incapable of allocating a new one.
///
/// `BufferTooShortError` is returned by the [`Serializer`] methods
/// [`serialize_no_alloc`] and [`serialize_no_alloc_outer`].
///
/// [`serialize_no_alloc`]: crate::serialize::Serializer::serialize_no_alloc
/// [`serialize_no_alloc_outer`]: crate::serialize::Serializer::serialize_no_alloc_outer
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct BufferTooShortError;

/// An object capable of providing buffers which satisfy certain constraints.
///
/// A `BufferProvider<Input, Output>` is an object which is capable of consuming
/// a buffer of type `Input` and, either by reusing it or by allocating a new
/// one and copying the input buffer's body into it, producing a buffer of type
/// `Output` which meets certain prefix and suffix length constraints.
///
/// A `BufferProvider` must always be provided when serializing a
/// [`Serializer`].
///
/// Implementors may find the helper function [`try_reuse_buffer`] useful.
///
/// For clients who don't need the full expressive power of this trait, the
/// simpler [`BufferAlloc`] trait is provided. It only defines how to allocate
/// new buffers, and two blanket impls of `BufferProvider` are provided for all
/// `BufferAlloc` types.
pub trait BufferProvider<Input, Output> {
    /// The type of errors returned from [`reuse_or_realloc`].
    ///
    /// [`reuse_or_realloc`]: crate::serialize::BufferProvider::reuse_or_realloc
    type Error;

    /// Consumes an input buffer and attempts to produce an output buffer with
    /// the given constraints, either by reusing the input buffer or by
    /// allocating a new one and copying the body into it.
    ///
    /// `reuse_or_realloc` consumes a buffer by value, and produces a new buffer
    /// with the following invariants:
    /// - The output buffer must have at least `prefix` bytes of prefix
    /// - The output buffer must have at least `suffix` bytes of suffix
    /// - The output buffer must have the same body as the input buffer
    ///
    /// If these requirements cannot be met, then an error is returned along
    /// with the input buffer, which is unmodified.
    fn reuse_or_realloc(
        self,
        buffer: Input,
        prefix: usize,
        suffix: usize,
    ) -> Result<Output, (Self::Error, Input)>;
}

/// An object capable of allocating new buffers.
///
/// A `BufferAlloc<Output>` is an object which is capable of allocating new
/// buffers of type `Output`.
///
/// [Two blanket implementations] of [`BufferProvider`] are given for any type
/// which implements `BufferAlloc<O>`. One blanket implementation works for any
/// input buffer type, `I`, and produces buffers of type `Either<I, O>` as
/// output. One blanket implementation works only when the input and output
/// buffer types are the same, and produces buffers of that type. See the
/// documentation on those impls for more details.
///
/// The following implementations of `BufferAlloc` are provided:
/// - Any `FnOnce(usize) -> Result<O, E>` implements `BufferAlloc<O, Error = E>`
/// - `()` implements `BufferAlloc<Never, Error = ()>` (an allocator which
///   always fails)
/// - [`new_buf_vec`] implements `BufferAlloc<Buf<Vec<u8>>, Error = Never>` (an
///   allocator which infallibly heap-allocates `Vec`s)
///
/// [Two blanket implementations]: trait.BufferProvider.html#implementors
pub trait BufferAlloc<Output> {
    type Error;

    /// Attempts to allocate a new buffer of size `len`.
    fn alloc(self, len: usize) -> Result<Output, Self::Error>;
}

impl<O, E, F: FnOnce(usize) -> Result<O, E>> BufferAlloc<O> for F {
    type Error = E;

    #[inline]
    fn alloc(self, len: usize) -> Result<O, E> {
        self(len)
    }
}

impl BufferAlloc<Never> for () {
    type Error = ();

    #[inline]
    fn alloc(self, _len: usize) -> Result<Never, ()> {
        Err(())
    }
}

/// Allocates a new `Buf<Vec<u8>>`.
///
/// `new_buf_vec(len)` is shorthand for `Ok(Buf::new(vec![0; len], ..))`. It
/// implements [`BufferAlloc<Buf<Vec<u8>>, Error = Never>`], and, thanks to a
/// blanket impl, [`BufferProvider<I, Either<I, Buf<Vec<u8>>>, Error = Never>`]
/// for all `I: BufferMut`, and `BufferProvider<Buf<Vec<u8>>, Buf<Vec<u8>>,
/// Error = Never>`.
///
/// [`BufferAlloc<Buf<Vec<u8>>, Error = Never>`]: crate::serialize::BufferAlloc
/// [`BufferProvider<I, Either<I, Buf<Vec<u8>>>, Error = Never>`]: crate::serialize::BufferProvider
pub fn new_buf_vec(len: usize) -> Result<Buf<Vec<u8>>, Never> {
    Ok(Buf::new(vec![0; len], ..))
}

/// Attempts to reuse a buffer for the purposes of implementing
/// [`BufferProvider::reuse_or_realloc`].
///
/// `try_reuse_buffer` attempts to reuse an existing buffer to satisfy the given
/// prefix and suffix constraints. If it succeeds, it returns `Ok` containing a
/// buffer with the same body as the input, and with at least `prefix` prefix
/// bytes and at least `suffix` suffix bytes. Otherwise, it returns `Err`
/// containing the original, unmodified input buffer.
///
/// Concretely, `try_reuse_buffer` has the following behavior:
/// - If the prefix and suffix constraints are already met, it returns `Ok` with
///   the input unmodified
/// - If the prefix and suffix constraints are not yet met, then...
///   - If there is enough capacity to meet the constraints and the body is not
///     larger than `max_copy_bytes`, the body will be moved within the buffer
///     in order to meet the constraints, and it will be returned
///   - Otherwise, if there is not enough capacity or the body is larger than
///     `max_copy_bytes`, it returns `Err` with the input unmodified
///
/// `max_copy_bytes` is meant to be an estimate of how many bytes can be copied
/// before allocating a new buffer will be cheaper than copying.
#[inline]
pub fn try_reuse_buffer<B: GrowBufferMut + ShrinkBuffer>(
    mut buffer: B,
    prefix: usize,
    suffix: usize,
    max_copy_bytes: usize,
) -> Result<B, B> {
    let need_prefix = prefix;
    let need_suffix = suffix;
    let have_prefix = buffer.prefix_len();
    let have_body = buffer.len();
    let have_suffix = buffer.suffix_len();
    let need_capacity = need_prefix + have_body + need_suffix;

    if have_prefix >= need_prefix && have_suffix >= need_suffix {
        // We already satisfy the prefix and suffix requirements.
        Ok(buffer)
    } else if buffer.capacity() >= need_capacity && have_body <= max_copy_bytes {
        // The buffer is large enough, but the body is currently too far
        // forward or too far backwards to satisfy the prefix or suffix
        // requirements, so we need to move the body within the buffer.
        buffer.reset();

        // Copy the original body range to a point starting immediatley
        // after `prefix`. This satisfies the `prefix` constraint by
        // definition, and satisfies the `suffix` constraint since we know
        // that the total buffer capacity is sufficient to hold the total
        // length of the prefix, body, and suffix.
        buffer.copy_within(have_prefix..(have_prefix + have_body), need_prefix);
        buffer.shrink(need_prefix..(need_prefix + have_body));
        debug_assert_eq!(buffer.prefix_len(), need_prefix);
        debug_assert!(buffer.suffix_len() >= need_suffix);
        debug_assert_eq!(buffer.len(), have_body);
        Ok(buffer)
    } else {
        Err(buffer)
    }
}

/// All types which implement `BufferAlloc<O>` also implement `BufferProvider<I,
/// Either<I, O>>` for all `I` where `I` and `O` both implement [`BufferMut`].
///
/// Note that, if `I` and `O` are the same type, calling methods on `Either<I,
/// O>` will often be just as fast as calling methods on `I`/`O` itself since
/// Rust can optimize out branching on which enum variant is present. However,
/// in this case, an impl of `BufferProvider<I, I>` is also provided.
impl<I: ReusableBuffer, O: ReusableBuffer, A: BufferAlloc<O>> BufferProvider<I, Either<I, O>>
    for A
{
    type Error = A::Error;

    /// If `buffer` has enough capacity to store `need_prefix + need_suffix +
    /// buffer.len()` bytes, then reuse `buffer`. Otherwise, allocate a new
    /// buffer using `A`'s [`BufferAlloc`] implementation.
    ///
    /// If there is enough capacity, but the body is too far forwards or
    /// backwards in the buffer to satisfy the prefix and suffix constraints,
    /// the body will be moved within the buffer in order to satisfy the
    /// constraints. This operation is linear in the length of the body.
    #[inline]
    fn reuse_or_realloc(
        self,
        buffer: I,
        need_prefix: usize,
        need_suffix: usize,
    ) -> Result<Either<I, O>, (A::Error, I)> {
        // TODO(joshlf): Maybe it's worth coming up with a heuristic for when
        // moving the body is likely to be more expensive than allocating
        // (rather than just using `MAX_USIZE`)? This will be tough since we
        // don't know anything about the performance of `A::alloc`.
        match try_reuse_buffer(buffer, need_prefix, need_suffix, MAX_USIZE) {
            Ok(buffer) => Ok(Either::A(buffer)),
            Err(buffer) => {
                let have_body = buffer.len();
                let need_capacity = need_prefix + have_body + need_suffix;

                let mut buf = match BufferAlloc::alloc(self, need_capacity) {
                    Ok(buf) => buf,
                    Err(err) => return Err((err, buffer)),
                };
                buf.shrink(need_prefix..(need_prefix + have_body));

                buf.copy_from(&buffer);
                debug_assert_eq!(buf.prefix_len(), need_prefix);
                debug_assert!(buf.suffix_len() >= need_suffix);
                debug_assert_eq!(buf.len(), have_body);
                Ok(Either::B(buf))
            }
        }
    }
}

/// All types which implement `BufferAlloc<B>` also implement `BufferProvider<B,
/// B>` where `B` implements [`GrowBufferMut`] and [`ShrinkBuffer`].
impl<B: ReusableBuffer, A: BufferAlloc<B>> BufferProvider<B, B> for A {
    type Error = A::Error;

    /// If `buffer` has enough capacity to store `need_prefix + need_suffix +
    /// buffer.len()` bytes, then reuse `buffer`. Otherwise, allocate a new
    /// buffer using `A`'s [`BufferAlloc`] implementation.
    ///
    /// If there is enough capacity, but the body is too far forwards or
    /// backwards in the buffer to satisfy the prefix and suffix constraints,
    /// the body will be moved within the buffer in order to satisfy the
    /// constraints. This operation is linear in the length of the body.
    #[inline]
    fn reuse_or_realloc(self, buffer: B, prefix: usize, suffix: usize) -> Result<B, (A::Error, B)> {
        BufferProvider::<B, Either<B, B>>::reuse_or_realloc(self, buffer, prefix, suffix)
            .map(Either::into_inner)
    }
}

pub trait Serializer: Sized {
    /// The type of buffers returned from serialization methods on this trait.
    type Buffer;

    /// Serializes this `Serializer`, producing a buffer.
    ///
    /// `serialize` accepts a [`PacketBuilder`] and a [`BufferProvider`], and
    /// produces a buffer which contains the contents of this `Serializer`
    /// encapsulated in the header and footer described by the `PacketBuilder`.
    ///
    /// As `Serializer`s can be nested using the [`Nested`] type (constructed
    /// using the [`encapsulate`] method), the `serialize` method is recursive -
    /// calling it on a `Nested` will recurse into the inner `Serializer`, which
    /// might itself be a `Nested`, and so on. When the innermost `Serializer`
    /// is reached, the contained buffer is passed to the `provider`, allowing
    /// it to decide how to produce a buffer which is large enough to fit the
    /// entire packet - either by reusing the existing buffer, or by discarding
    /// it and allocating a new one.
    ///
    /// [`encapsulate`]: crate::serialize::Serializer::encapsulate
    fn serialize<B: TargetBuffer, PB: NestedPacketBuilder, P: BufferProvider<Self::Buffer, B>>(
        self,
        outer: PB,
        provider: P,
    ) -> Result<B, (SerializeError<P::Error>, Self)>;

    /// Serializes this `Serializer`, allocating a [`Buf<Vec<u8>>`] if the
    /// contained buffer isn't large enough.
    ///
    /// `serialize_vec` is like [`serialize`], except that, if the contained
    /// buffer isn't large enough to contain the packet, a new `Vec<u8>` is
    /// allocated and wrapped in a `Buf`. If the buffer is large enough, but the
    /// body is too far forwards or backwards to fit the encapsulating headers
    /// or footers, the body will be moved within the buffer (this is linear in
    /// the size of the body).
    ///
    /// `serialize_vec` is equivalent to calling `serialize` with
    /// [`new_buf_vec`] as the [`BufferProvider`].
    ///
    /// [`Buf<Vec<u8>>`]: crate::serialize::Buf
    /// [`serialize`]: crate::serialize::Serializer::serialize
    #[inline]
    #[allow(clippy::type_complexity)]
    fn serialize_vec<PB: NestedPacketBuilder>(
        self,
        outer: PB,
    ) -> Result<Either<Self::Buffer, Buf<Vec<u8>>>, (SerializeError<Never>, Self)>
    where
        Self::Buffer: ReusableBuffer,
    {
        self.serialize(outer, new_buf_vec)
    }

    /// Serializes this `Serializer`, failing if the existing buffer is not
    /// large enough.
    ///
    /// `serialize_no_alloc` is like [`serialize`], except that it will fail if
    /// the existing buffer isn't large enough. If the buffer is large enough,
    /// but the body is too far forwards or backwards to fit the encapsulating
    /// headers or footers, the body will be moved within the buffer (this is
    /// linear in the size of the body).
    ///
    /// `serialize_no_alloc` is equivalent to calling `serialize` with a
    /// `BufferProvider` which cannot allocate a new buffer (such as `()`).
    ///
    /// [`serialize`]: crate::serialize::Serializer::serialize
    #[inline]
    fn serialize_no_alloc<PB: NestedPacketBuilder>(
        self,
        outer: PB,
    ) -> Result<Self::Buffer, (SerializeError<BufferTooShortError>, Self)>
    where
        Self::Buffer: ReusableBuffer,
    {
        self.serialize(outer, ()).map(Either::into_a).map_err(|(err, slf)| {
            (
                match err {
                    SerializeError::Alloc(()) => BufferTooShortError.into(),
                    SerializeError::Mtu => SerializeError::Mtu,
                },
                slf,
            )
        })
    }

    /// Serializes this `Serializer` as the outermost packet.
    ///
    /// `serialize_outer` is like [`serialize`], except that it is called when
    /// this `Serializer` describes the outermost packet, not encapsulated in
    /// any other packets. It is equivalent to calling `serialize` with an empty
    /// [`PacketBuilder`] (such as `()`).
    ///
    /// [`serialize`]: crate::serialize::Serializer::serialize
    #[inline]
    fn serialize_outer<B: TargetBuffer, P: BufferProvider<Self::Buffer, B>>(
        self,
        provider: P,
    ) -> Result<B, (SerializeError<P::Error>, Self)> {
        self.serialize((), provider)
    }

    /// Serializes this `Serializer` as the outermost packet, allocating a
    /// [`Buf<Vec<u8>>`] if the contained buffer isn't large enough.
    ///
    /// `serialize_vec_outer` is like [`serialize_vec`], except that it is
    /// called when this `Serializer` describes the outermost packet, not
    /// encapsulated in any other packets. It is equivalent to calling
    /// `serialize_vec` with an empty [`PacketBuilder`] (such as `()`).
    ///
    /// [`Buf<Vec<u8>>`]: crate::serialize::Buf
    /// [`serialize_vec`]: crate::serialize::Serializer::serialize_vec
    #[inline]
    #[allow(clippy::type_complexity)]
    fn serialize_vec_outer(
        self,
    ) -> Result<Either<Self::Buffer, Buf<Vec<u8>>>, (SerializeError<Never>, Self)>
    where
        Self::Buffer: ReusableBuffer,
    {
        self.serialize_vec(())
    }

    /// Serializes this `Serializer` as the outermost packet, failing if the
    /// existing buffer is not large enough.
    ///
    /// `serialize_no_alloc_outer` is like [`serialize_no_alloc`], except that
    /// it is called when this `Serializer` describes the outermost packet, not
    /// encapsulated in any other packets. It is equivalent to calling
    /// `serialize_no_alloc` with an empty [`PacketBuilder`] (such as `()`).
    ///
    /// [`serialize_no_alloc`]: crate::serialize::Serializer::serialize_no_alloc
    #[inline]
    fn serialize_no_alloc_outer(
        self,
    ) -> Result<Self::Buffer, (SerializeError<BufferTooShortError>, Self)>
    where
        Self::Buffer: ReusableBuffer,
    {
        self.serialize_no_alloc(())
    }

    /// Encapsulates this `Serializer` in another packet, producing a new
    /// `Serializer`.
    ///
    /// `encapsulate` consumes this `Serializer` and a [`PacketBuilder`], and
    /// produces a new `Serializer` which describes encapsulating this one in
    /// the packet described by `outer`.
    #[inline]
    fn encapsulate<B: NestedPacketBuilder>(self, outer: B) -> Nested<Self, B> {
        Nested { inner: self, outer }
    }

    /// Create a new `Serializer` which will enforce a maximum transmission unit
    /// (MTU).
    ///
    /// `with_mtu` consumes this `Serializer` and an MTU, and produces a new
    /// `Serializer` which will enforce the given MTU on all serialization
    /// requests. Note that the given MTU will be enforced at this layer -
    /// serialization requests will be rejected if the body produced by the
    /// request at this layer would exceed the MTU. It has no effect on headers
    /// or footers added by encapsulating layers outside of this one.
    #[inline]
    fn with_mtu(self, mtu: usize) -> Nested<Self, MtuPacketBuilder<()>> {
        self.encapsulate(MtuPacketBuilder { mtu, inner: () })
    }
}

/// A [`Serializer`] constructed from an [`InnerPacketBuilder`].
///
/// An `InnerSerializer` wraps an `InnerPacketBuilder` and a buffer, and
/// implements the `Serializer` trait. When a serialization is requested, it
/// either reuses the stored buffer or allocates a new one large enough to hold
/// itself and all outer `PacketBuilder`s.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct InnerSerializer<I, B> {
    inner: I,
    // The buffer's length must be zero since we encapsulate the buffer in a
    // PacketBuilder. If the length were non-zero, that would have the effect of
    // retaining the contents of the buffer when serializing, and putting them
    // immediately after the bytes of `inner`.
    buffer: B,
}

impl<I: InnerPacketBuilder, B: GrowBuffer + ShrinkBuffer> Serializer for InnerSerializer<I, B> {
    type Buffer = B;

    #[inline]
    #[allow(clippy::type_complexity)]
    fn serialize<BB: TargetBuffer, PB: NestedPacketBuilder, P: BufferProvider<B, BB>>(
        self,
        outer: PB,
        provider: P,
    ) -> Result<BB, (SerializeError<P::Error>, InnerSerializer<I, B>)> {
        // A wrapper for InnerPacketBuilders which implements PacketBuilder by
        // treating the entire InnerPacketBuilder as the header of the
        // PacketBuilder. This allows us to compose our InnerPacketBuilder with
        // the outer PacketBuilders into a single, large PacketBuilder, and then
        // serialize it using self.buffer.
        struct InnerPacketBuilderWrapper<I>(I);

        impl<I: InnerPacketBuilder> PacketBuilder for InnerPacketBuilderWrapper<I> {
            fn constraints(&self) -> PacketConstraints {
                PacketConstraints::new(self.0.bytes_len(), 0, 0, MAX_USIZE)
            }

            fn serialize(&self, buffer: &mut SerializeBuffer<'_, '_>) {
                // Note that the body might be non-empty if an outer
                // PacketBuilder added a minimum body length constraint that
                // required padding.
                debug_assert_eq!(buffer.header().len(), self.0.bytes_len());
                debug_assert_eq!(buffer.footer().len(), 0);

                InnerPacketBuilder::serialize(&self.0, buffer.header());
            }
        }

        let pb = InnerPacketBuilderWrapper(self.inner);
        debug_assert_eq!(self.buffer.len(), 0);
        match self.buffer.encapsulate(&pb).serialize(outer, provider) {
            Ok(buf) => Ok(buf),
            Err((err, buffer)) => {
                let buffer = buffer.into_inner();
                Err((err, InnerSerializer { inner: pb.0, buffer }))
            }
        }
    }
}

impl<B: GrowBuffer + ShrinkBuffer> Serializer for B {
    type Buffer = B;

    #[inline]
    fn serialize<BB: TargetBuffer, PB: NestedPacketBuilder, P: BufferProvider<Self::Buffer, BB>>(
        self,
        outer: PB,
        provider: P,
    ) -> Result<BB, (SerializeError<P::Error>, Self)> {
        TruncatingSerializer::new(self, TruncateDirection::NoTruncating)
            .serialize(outer, provider)
            .map_err(|(err, ser)| (err, ser.buffer))
    }
}

/// The direction a buffer's body should be truncated from to force
/// it to fit within a MTU.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum TruncateDirection {
    /// If a buffer cannot fit within an MTU, discard bytes from the
    /// front of the body.
    DiscardFront,
    /// If a buffer cannot fit within an MTU, discard bytes from the
    /// end of the body.
    DiscardBack,
    /// Do not attempt to truncate a buffer to make it fit within an MTU.
    NoTruncating,
}

/// A [`Serializer`] that truncates its body if it would exceed an MTU
/// constraint.
///
/// `TruncatingSerializer` wraps a buffer, and implements `Serializer`. Unlike
/// the blanket impl of `Serializer` for `B: GrowBuffer + ShrinkBuffer`, if the
/// buffer's body exceeds the MTU constraint passed to `Serializer::serialize`,
/// the body is truncated to fit.
///
/// Note that this does not guarantee that MTU errors will not occur. The MTU
/// may be small enough that the encapsulating headers alone exceed the MTU.
/// There may also be a minimum body length constraint which is larger than the
/// MTU.
#[derive(Copy, Clone, Debug)]
#[cfg_attr(test, derive(Eq, PartialEq))]
pub struct TruncatingSerializer<B> {
    buffer: B,
    direction: TruncateDirection,
}

impl<B> TruncatingSerializer<B> {
    /// Constructs a new `TruncatingSerializer`.
    pub fn new(buffer: B, direction: TruncateDirection) -> TruncatingSerializer<B> {
        TruncatingSerializer { buffer, direction }
    }
}

impl<B: GrowBuffer + ShrinkBuffer> Serializer for TruncatingSerializer<B> {
    type Buffer = B;

    fn serialize<BB: TargetBuffer, PB: NestedPacketBuilder, P: BufferProvider<B, BB>>(
        mut self,
        outer: PB,
        provider: P,
    ) -> Result<BB, (SerializeError<P::Error>, Self)> {
        let c = match outer.try_constraints() {
            Some(c) => c,
            None => return Err((SerializeError::Mtu, self)),
        };
        let original_len = self.buffer.len();
        let excess_bytes =
            if original_len > c.max_body_len { Some(original_len - c.max_body_len) } else { None };
        if let Some(excess_bytes) = excess_bytes {
            match self.direction {
                TruncateDirection::DiscardFront => self.buffer.shrink_front(excess_bytes),
                TruncateDirection::DiscardBack => self.buffer.shrink_back(excess_bytes),
                TruncateDirection::NoTruncating => return Err((SerializeError::Mtu, self)),
            }
        }

        let padding = c.min_body_len().saturating_sub(self.buffer.len());

        // At this point, the body and padding MUST fit within the MTU. Note
        // that PacketConstraints guarantees that min_body_len <= max_body_len,
        // so the padding can't cause this assertion to fail.
        debug_assert!(self.buffer.len() + padding <= c.max_body_len());
        match provider.reuse_or_realloc(self.buffer, c.header_len(), padding + c.footer_len()) {
            Ok(mut buffer) => {
                outer.serialize_into(&mut buffer);
                Ok(buffer)
            }
            Err((err, mut buffer)) => {
                // Undo the effects of shrinking the buffer so that the buffer
                // we return is unmodified from its original (which is required
                // by the contract of this method).
                if let Some(excess_bytes) = excess_bytes {
                    match self.direction {
                        TruncateDirection::DiscardFront => buffer.grow_front(excess_bytes),
                        TruncateDirection::DiscardBack => buffer.grow_back(excess_bytes),
                        TruncateDirection::NoTruncating => unreachable!(),
                    }
                }

                Err((
                    SerializeError::Alloc(err),
                    TruncatingSerializer { buffer, direction: self.direction },
                ))
            }
        }
    }
}

impl<I: Serializer, O: NestedPacketBuilder> Serializer for Nested<I, O> {
    type Buffer = I::Buffer;

    #[inline]
    fn serialize<B: TargetBuffer, PB: NestedPacketBuilder, P: BufferProvider<I::Buffer, B>>(
        self,
        outer: PB,
        provider: P,
    ) -> Result<B, (SerializeError<P::Error>, Self)> {
        // We use `RefNestedPacketBuilder` here so that the call to `serialize`
        // doesn't consume `self.outer` by value. If it did, we'd have to way of
        // getting it back in the event of an error (when we need to reconstruct
        // `self` to return).
        match self.inner.serialize(
            NestedPacketBuilder::encapsulate(RefNestedPacketBuilder(&self.outer), outer),
            provider,
        ) {
            Ok(buf) => Ok(buf),
            Err((err, inner)) => Err((err, inner.encapsulate(self.outer))),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::Buffer;
    use std::fmt::Debug;

    // DummyPacketBuilder:
    // - Implements PacketBuilder with the stored constraints; it fills the
    //   header with 0xFF and the footer with 0xFE
    // - Implements InnerPacketBuilder by consuming a `header_len`-bytes body,
    //   and filling it with 0xFF
    #[derive(Copy, Clone, Debug, Eq, PartialEq)]
    struct DummyPacketBuilder {
        header_len: usize,
        footer_len: usize,
        min_body_len: usize,
        max_body_len: usize,
    }

    impl DummyPacketBuilder {
        fn new(
            header_len: usize,
            footer_len: usize,
            min_body_len: usize,
            max_body_len: usize,
        ) -> DummyPacketBuilder {
            DummyPacketBuilder { header_len, footer_len, min_body_len, max_body_len }
        }
    }

    fn fill(bytes: &mut [u8], byte: u8) {
        for b in bytes {
            *b = byte;
        }
    }

    impl PacketBuilder for DummyPacketBuilder {
        fn constraints(&self) -> PacketConstraints {
            PacketConstraints::new(
                self.header_len,
                self.footer_len,
                self.min_body_len,
                self.max_body_len,
            )
        }

        fn serialize(&self, buffer: &mut SerializeBuffer<'_, '_>) {
            // // `serialize` is allowed to panic if called on a `PacketBuilder`
            // // with invalid constraints.
            // assert!(self.try_constraints().is_some());
            assert_eq!(buffer.header().len(), self.header_len);
            assert_eq!(buffer.footer().len(), self.footer_len);
            assert!(buffer.body().len() >= self.min_body_len);
            assert!(buffer.body().len() <= self.max_body_len);
            fill(buffer.header(), 0xFF);
            fill(buffer.footer(), 0xFE);
        }
    }

    impl InnerPacketBuilder for DummyPacketBuilder {
        fn bytes_len(&self) -> usize {
            self.header_len
        }

        fn serialize(&self, buffer: &mut [u8]) {
            assert_eq!(buffer.len(), self.header_len);
            fill(buffer, 0xFF);
        }
    }

    impl SerializeError<Never> {
        fn into<E>(self) -> SerializeError<E> {
            match self {
                SerializeError::Alloc(never) => match never {},
                SerializeError::Mtu => SerializeError::Mtu,
            }
        }
    }

    // A Serializer that verifies certain invariants while operating. In
    // particular:
    // - If serialization fails, the original Serializer is returned unmodified.
    // - If `outer.try_constraints()` returns `None`, serialization fails.
    // - If the MTU is exceeded and truncation is disabled, serialization fails.
    // - If serialization succeeds, the body has the correct length, including
    //   taking into account `outer`'s minimum body length requirement
    #[derive(Copy, Clone, Debug, Eq, PartialEq)]
    struct VerifyingSerializer<S> {
        ser: S,
        // Is the inner Serializer a truncating (a TruncatingSerializer with
        // TruncateDirection::DiscardFront or DiscardBack)?
        truncating: bool,
    }

    impl<S: Serializer + Debug + Clone + Eq> Serializer for VerifyingSerializer<S>
    where
        S::Buffer: ReusableBuffer,
    {
        type Buffer = S::Buffer;

        fn serialize<
            B: TargetBuffer,
            PB: NestedPacketBuilder,
            P: BufferProvider<Self::Buffer, B>,
        >(
            self,
            outer: PB,
            provider: P,
        ) -> Result<B, (SerializeError<P::Error>, Self)> {
            let orig = self.ser.clone();

            // How long is the packet if we serialize it without the outer
            // PacketBuilder?
            let inner_len = match self.clone().ser.serialize_vec_outer() {
                Ok(buf) => buf.len(),
                Err((err, ser)) => {
                    // If serialization fails, the original Serializer should be
                    // unmodified.
                    assert_eq!(ser, orig);
                    return Err((err.into(), ser.into_verifying(self.truncating)));
                }
            };
            let outer_constraints = outer.try_constraints();
            let should_fail_mtu = outer_constraints
                .map(|c| c.max_body_len() < inner_len && !self.truncating)
                .unwrap_or(true);

            let res = self.ser.serialize(outer, provider);
            match res {
                Ok(buf) => {
                    let c = outer_constraints.unwrap();
                    // Since serialization has succeeded, we know that either
                    // inner_len <= c.max_body_len(), or that the body was
                    // truncated to fit.
                    let body_len =
                        cmp::min(cmp::max(inner_len, c.min_body_len()), c.max_body_len());
                    assert_eq!(buf.len(), c.header_len() + body_len + c.footer_len());
                    assert!(!should_fail_mtu);
                    Ok(buf)
                }
                Err((err, ser)) => {
                    // If we shouldn't fail as a result of an MTU error, we
                    // might still fail as a result of allocation.
                    assert!(should_fail_mtu || err.is_alloc());
                    // If serialization fails, the original Serializer should be
                    // unmodified.
                    assert_eq!(ser, orig);
                    Err((err, ser.into_verifying(self.truncating)))
                }
            }
        }
    }

    trait SerializerExt: Serializer {
        fn into_verifying(self, truncating: bool) -> VerifyingSerializer<Self>
        where
            Self::Buffer: ReusableBuffer,
        {
            VerifyingSerializer { ser: self, truncating }
        }

        fn encapsulate_verifying<B: PacketBuilder>(
            self,
            outer: B,
            truncating: bool,
        ) -> VerifyingSerializer<Nested<Self, B>>
        where
            Self::Buffer: ReusableBuffer,
        {
            self.encapsulate(outer).into_verifying(truncating)
        }

        fn with_mtu_verifying(
            self,
            mtu: usize,
            truncating: bool,
        ) -> VerifyingSerializer<Nested<Self, MtuPacketBuilder<()>>>
        where
            Self::Buffer: ReusableBuffer,
        {
            self.with_mtu(mtu).into_verifying(truncating)
        }
    }

    impl<S: Serializer> SerializerExt for S {}

    #[test]
    fn test_either_into_inner() {
        fn ret_either(a: u32, b: u32, c: bool) -> Either<u32, u32> {
            if c {
                Either::A(a)
            } else {
                Either::B(b)
            }
        }

        assert_eq!(ret_either(1, 2, true).into_inner(), 1);
        assert_eq!(ret_either(1, 2, false).into_inner(), 2);
    }

    #[test]
    fn test_either_unwrap_success() {
        assert_eq!(Either::<u16, u32>::A(5).unwrap_a(), 5);
        assert_eq!(Either::<u16, u32>::B(10).unwrap_b(), 10);
    }

    #[test]
    #[should_panic]
    fn test_either_unwrap_a_panic() {
        let _: u16 = Either::<u16, u32>::B(10).unwrap_a();
    }

    #[test]
    #[should_panic]
    fn test_either_unwrap_b_panic() {
        let _: u32 = Either::<u16, u32>::A(5).unwrap_b();
    }

    #[test]
    fn test_packet_constraints() {
        use PacketConstraints as PC;

        // Sanity check.
        assert!(PC::try_new(0, 0, 0, 0).is_some());
        // header_len + min_body_len + footer_len doesn't overflow usize
        assert!(PC::try_new(MAX_USIZE / 2, MAX_USIZE / 2, 0, 0).is_some());
        // header_len + min_body_len + footer_len overflows usize
        assert_eq!(PC::try_new(MAX_USIZE, 1, 0, 0), None);
        // min_body_len > max_body_len
        assert_eq!(PC::try_new(0, 0, 1, 0), None);
    }

    #[test]
    fn test_nested_packet_builder() {
        // DummyPacketBuilder itself doesn't have any interesting logic - it
        // just calls out to PacketConstraints::new. We've already tested that
        // method in test_packet_constraints. This test instead exercises the
        // logic in Nested to make sure that PacketBuilders compose correctly.
        //
        // Each failure test case corresponds to one check in either
        // Nested::constraints or PacketConstraints::new (which is called from
        // Nested::constraints). Each test case is labeled "Test case N", and a
        // corresponding comment in either of those two functions identifies
        // which line is being tested.

        use DummyPacketBuilder as DPB;
        use PacketConstraints as PC;

        // Sanity check.
        let pb = DPB::new(10, 10, 0, MAX_USIZE);
        assert_eq!(
            pb.encapsulate(pb).try_constraints().unwrap(),
            PC::new(20, 20, 0, MAX_USIZE - 20),
        );

        // The outer PacketBuilder's minimum body length requirement of 10 is
        // more than satisfied by the inner PacketBuilder's combined 20 bytes of
        // header and footer. The resulting PacketBuilder has its minimum body
        // length requirement saturated to 0.
        let inner = DPB::new(10, 10, 0, MAX_USIZE);
        let outer = DPB::new(0, 0, 10, MAX_USIZE);
        assert_eq!(
            inner.encapsulate(outer).try_constraints().unwrap(),
            PC::new(10, 10, 0, MAX_USIZE - 20),
        );

        // Test case 1
        //
        // The sum of the inner and outer header lengths overflows `usize`.
        let inner = DPB::new(MAX_USIZE, 0, 0, MAX_USIZE);
        let outer = DPB::new(1, 0, 0, MAX_USIZE);
        assert_eq!(inner.encapsulate(outer).try_constraints(), None);

        // Test case 2
        //
        // The sum of the inner and outer footer lengths overflows `usize`.
        let inner = DPB::new(0, MAX_USIZE, 0, MAX_USIZE);
        let outer = DPB::new(0, 1, 0, MAX_USIZE);
        assert_eq!(inner.encapsulate(outer).try_constraints(), None);

        // Test case 3
        //
        // The sum of the resulting header, footer, and minimum body lengths
        // overflows `usize`. We use MAX_USIZE / 5 + 1 as the constant so that
        // none of the intermediate additions overflow, so we make sure to test
        // that an overflow in the final addition will be caught.
        let one_fifth_max = (MAX_USIZE / 5) + 1;
        let inner = DPB::new(one_fifth_max, one_fifth_max, one_fifth_max, MAX_USIZE);
        let outer = DPB::new(one_fifth_max, one_fifth_max, 0, MAX_USIZE);
        assert_eq!(inner.encapsulate(outer).try_constraints(), None);

        // Test case 4
        //
        // The header and footer of the inner PacketBuilder exceed the maximum
        // body length requirement of the outer PacketBuilder.
        let inner = DPB::new(10, 10, 0, MAX_USIZE);
        let outer = DPB::new(0, 0, 0, 10);
        assert_eq!(inner.encapsulate(outer).try_constraints(), None);

        // Test case 5
        //
        // The resulting minimum body length (thanks to the inner
        // PacketBuilder's minimum body length) is larger than the resulting
        // maximum body length.
        let inner = DPB::new(0, 0, 10, MAX_USIZE);
        let outer = DPB::new(0, 0, 0, 5);
        assert_eq!(inner.encapsulate(outer).try_constraints(), None);
    }

    #[test]
    fn test_inner_serializer() {
        const INNER: &[u8] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

        fn concat<'a, I: IntoIterator<Item = &'a &'a [u8]>>(slices: I) -> Vec<u8> {
            let mut v = Vec::new();
            for slc in slices.into_iter() {
                v.extend_from_slice(slc);
            }
            v
        }

        // Sanity check.
        let buf = INNER.into_serializer().serialize_vec_outer().unwrap();
        assert_eq!(buf.as_ref(), INNER);

        // A larger minimum body length requirement will cause padding to be
        // added.
        let buf = INNER
            .into_serializer()
            .into_verifying(false)
            .serialize_vec(DummyPacketBuilder::new(0, 0, 20, MAX_USIZE))
            .unwrap();
        assert_eq!(buf.as_ref(), concat(&[INNER, vec![0; 10].as_ref()]).as_slice());

        // Headers and footers are added as appropriate (note that
        // DummyPacketBuilder fills its header with 0xFF and its footer with
        // 0xFE).
        let buf = INNER
            .into_serializer()
            .into_verifying(false)
            .serialize_vec(DummyPacketBuilder::new(10, 10, 0, MAX_USIZE))
            .unwrap();
        assert_eq!(
            buf.as_ref(),
            concat(&[vec![0xFF; 10].as_ref(), INNER, vec![0xFE; 10].as_ref()]).as_slice()
        );

        // An exceeded maximum body size is rejected.
        assert_eq!(
            INNER
                .into_serializer()
                .into_verifying(false)
                .serialize_vec(DummyPacketBuilder::new(0, 0, 0, 9))
                .unwrap_err()
                .0,
            SerializeError::Mtu
        );

        // `into_serializer_with` truncates the buffer's body to zero before
        // returning, so those body bytes are not included in the serialized
        // output.
        assert_eq!(
            INNER
                .into_serializer_with(Buf::new(vec![0xFF], ..))
                .into_verifying(false)
                .serialize_vec_outer()
                .unwrap()
                .as_ref(),
            INNER
        );
    }

    #[test]
    fn test_buffer_serializer_and_inner_serializer() {
        fn verify_buffer_serializer<B: BufferMut + Debug>(
            buffer: B,
            header_len: usize,
            footer_len: usize,
            min_body_len: usize,
        ) {
            let old_body = buffer.to_flattened_vec();

            let buffer = buffer
                .serialize_vec(DummyPacketBuilder::new(
                    header_len,
                    footer_len,
                    min_body_len,
                    MAX_USIZE,
                ))
                .unwrap();
            verify(buffer, &old_body, header_len, footer_len, min_body_len);
        }

        fn verify_inner_packet_builder_serializer(
            body: &[u8],
            header_len: usize,
            footer_len: usize,
            min_body_len: usize,
        ) {
            let buffer = body
                .into_serializer()
                .serialize_vec(DummyPacketBuilder::new(
                    header_len,
                    footer_len,
                    min_body_len,
                    MAX_USIZE,
                ))
                .unwrap();
            verify(buffer, body, header_len, footer_len, min_body_len);
        }

        fn verify<B: Buffer>(
            buffer: B,
            body: &[u8],
            header_len: usize,
            footer_len: usize,
            min_body_len: usize,
        ) {
            let flat = buffer.to_flattened_vec();
            let header_bytes = &flat[..header_len];
            let body_bytes = &flat[header_len..header_len + body.len()];
            let padding_len = min_body_len.saturating_sub(body.len());
            let padding_bytes =
                &flat[header_len + body.len()..header_len + body.len() + padding_len];
            let total_body_len = body.len() + padding_len;
            let footer_bytes = &flat[header_len + total_body_len..];
            assert_eq!(
                buffer.len() - total_body_len,
                header_len + footer_len,
                "buffer.len()({}) - total_body_len({}) != header_len({}) + footer_len({})",
                buffer.len(),
                header_len,
                footer_len,
                min_body_len,
            );

            // DummyPacketBuilder fills its header with 0xFF
            assert!(
                header_bytes.iter().all(|b| *b == 0xFF),
                "header_bytes {:?} are not filled with 0xFF's",
                header_bytes,
            );
            assert_eq!(body_bytes, body);
            // Padding bytes must be initialized to zero
            assert!(
                padding_bytes.iter().all(|b| *b == 0),
                "padding_bytes {:?} are not filled with 0s",
                padding_bytes,
            );
            // DummyPacketBuilder fills its footer with 0xFE
            assert!(
                footer_bytes.iter().all(|b| *b == 0xFE),
                "footer_bytes {:?} are not filled with 0xFE's",
                footer_bytes,
            );
        }

        // Test for every valid combination of buf_len, range_start, range_end,
        // prefix, suffix, and min_body within [0, 8).
        for buf_len in 0..8 {
            for range_start in 0..buf_len {
                for range_end in range_start..buf_len {
                    for prefix in 0..8 {
                        for suffix in 0..8 {
                            for min_body in 0..8 {
                                let mut vec = vec![0; buf_len];
                                // Initialize the vector with values 0, 1, 2,
                                // ... so that we can check to make sure that
                                // the range bytes have been properly copied if
                                // the buffer is reallocated.
                                #[allow(clippy::needless_range_loop)]
                                for i in 0..vec.len() {
                                    vec[i] = i as u8;
                                }
                                verify_buffer_serializer(
                                    Buf::new(vec.as_mut_slice(), range_start..range_end),
                                    prefix,
                                    suffix,
                                    min_body,
                                );
                                if range_start == 0 {
                                    // Unlike verify_buffer_serializer, this
                                    // test doesn't make use of the prefix or
                                    // suffix. In order to avoid running the
                                    // exact same test multiple times, we only
                                    // run this when `range_start == 0`, which
                                    // has the effect of reducing the number of
                                    // times that this test is run by roughly a
                                    // factor of 8.
                                    verify_inner_packet_builder_serializer(
                                        &vec.as_slice()[range_start..range_end],
                                        prefix,
                                        suffix,
                                        min_body,
                                    );
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    #[test]
    fn test_min_body_len() {
        // Test that padding is added after the body of the packet whose minimum
        // body length constraint requires it. A previous version of this code
        // had a bug where padding was always added after the innermost body.

        let body = &[1, 2];

        // 4 bytes of header and footer for a total of 6 bytes (including the
        // body).
        let inner = DummyPacketBuilder::new(2, 2, 0, MAX_USIZE);
        // Minimum body length of 8 will require 2 bytes of padding.
        let outer = DummyPacketBuilder::new(2, 2, 8, MAX_USIZE);
        let buf = body
            .into_serializer()
            .into_verifying(false)
            .encapsulate_verifying(inner, false)
            .encapsulate_verifying(outer, false)
            .serialize_vec_outer()
            .unwrap();
        assert_eq!(
            buf.as_ref(),
            &[
                0xFF, 0xFF, // Outer header
                0xFF, 0xFF, // Inner header
                1, 2, // Inner body
                0xFE, 0xFE, // Inner footer
                0, 0, // Padding to satisfy outer minimum body length requirement
                0xFE, 0xFE // Outer footer
            ]
        );
    }

    #[test]
    fn test_mtu() {
        // ser is a Serializer that will consume 1 byte of buffer space
        fn test<S: Serializer + Clone + Debug + Eq>(ser: S)
        where
            S::Buffer: ReusableBuffer,
        {
            // Each of these tests encapsulates ser in a DummyPacketBuilder
            // which consumes 1 byte for the header and one byte for the footer.
            // Thus, the inner serializer will consume 1 byte, while the
            // DummyPacketBuilder will consume 2 bytes, for a total of 3 bytes.

            let pb = DummyPacketBuilder::new(1, 1, 0, MAX_USIZE);

            // Test that an MTU of 3 is OK. Note that this is an important test
            // since it tests the case when the MTU is exactly sufficient. A
            // previous version of this code had a bug where a packet which fit
            // the MTU exactly would be rejected.
            assert!(ser
                .clone()
                .encapsulate_verifying(pb, false)
                .with_mtu_verifying(3, false)
                .serialize_vec_outer()
                .is_ok());
            // Test that a more-than-large-enough MTU of 4 is OK.
            assert!(ser
                .clone()
                .encapsulate_verifying(pb, false)
                .with_mtu_verifying(4, false)
                .serialize_vec_outer()
                .is_ok());
            // Test that the inner MTU of 1 only applies to the inner
            // serializer, and so is still OK even though the outer serializer
            // consumes 3 bytes total.
            assert!(ser
                .clone()
                .with_mtu_verifying(1, false)
                .encapsulate_verifying(pb, false)
                .with_mtu_verifying(3, false)
                .serialize_vec_outer()
                .is_ok());
            // Test that the inner MTU of 0 is exceeded by the inner
            // serializer's 1 byte length.
            assert!(ser
                .clone()
                .with_mtu_verifying(0, false)
                .encapsulate_verifying(pb, false)
                .serialize_vec_outer()
                .is_err());
            // Test that an MTU which would be exceeded by the encapsulating
            // layer is rejected by Nested's implementation. If this doesn't
            // work properly, then the MTU should underflow, resulting in a
            // panic (see the Nested implementation of Serialize).
            assert!(ser
                .clone()
                .encapsulate_verifying(pb, false)
                .with_mtu_verifying(1, false)
                .serialize_vec_outer()
                .is_err());
        }

        // We use this as an InnerPacketBuilder which consumes 1 byte of body.
        test(DummyPacketBuilder::new(1, 0, 0, MAX_USIZE).into_serializer().into_verifying(false));
        test(Buf::new(vec![0], ..).into_verifying(false));
    }

    #[test]
    fn test_truncating_serializer() {
        //
        // Test truncate front.
        //

        let body = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
        let ser =
            TruncatingSerializer::new(Buf::new(body.clone(), ..), TruncateDirection::DiscardFront)
                .into_verifying(true);
        let buf = ser.clone().with_mtu_verifying(4, true).serialize_vec_outer().unwrap();
        let buf: &[u8] = buf.as_ref();
        assert_eq!(buf, &[6, 7, 8, 9][..]);

        //
        // Test truncate back.
        //

        let ser =
            TruncatingSerializer::new(Buf::new(body.clone(), ..), TruncateDirection::DiscardBack)
                .into_verifying(true);
        let buf = ser.with_mtu_verifying(7, true).serialize_vec_outer().unwrap();
        let buf: &[u8] = buf.as_ref();
        assert_eq!(buf, &[0, 1, 2, 3, 4, 5, 6][..]);

        //
        // Test no truncating (default/original case).
        //

        let ser =
            TruncatingSerializer::new(Buf::new(body.clone(), ..), TruncateDirection::NoTruncating)
                .into_verifying(false);
        assert!(ser.clone().with_mtu_verifying(5, true).serialize_vec_outer().is_err());
        assert!(ser.with_mtu_verifying(5, true).serialize_vec_outer().is_err());

        //
        // Test that, when serialization fails, any truncation is undone.
        //

        // `ser` has a body of `[1, 2]` and no prefix or suffix
        fn test_serialization_failure<S: Serializer + Clone + Eq + Debug>(
            ser: S,
            err: SerializeError<BufferTooShortError>,
        ) where
            S::Buffer: ReusableBuffer + Debug,
        {
            // Serialize with a PacketBuilder with an MTU of 1 so that the body
            // (of length 2) is too large. If `ser` is configured not to
            // truncate, it should result in an MTU error. If it is configured
            // to truncate, the 2 + 2 = 4 combined bytes of header and footer
            // will cause allocating a new buffer to fail, and it should result
            // in an allocation failure. Even if the body was truncated, it
            // should be returned to its original un-truncated state before
            // being returned from `serialize`.
            let (e, new_ser) =
                ser.clone().serialize_no_alloc(DummyPacketBuilder::new(2, 2, 0, 1)).unwrap_err();
            assert_eq!(err, e);
            assert_eq!(new_ser, ser);
        }

        let body = Buf::new(vec![1, 2], ..);
        test_serialization_failure(
            TruncatingSerializer::new(body.clone(), TruncateDirection::DiscardFront)
                .into_verifying(true),
            SerializeError::Alloc(BufferTooShortError),
        );
        test_serialization_failure(
            TruncatingSerializer::new(body.clone(), TruncateDirection::DiscardFront)
                .into_verifying(true),
            SerializeError::Alloc(BufferTooShortError),
        );
        test_serialization_failure(
            TruncatingSerializer::new(body.clone(), TruncateDirection::NoTruncating)
                .into_verifying(false),
            SerializeError::Mtu,
        );
    }

    #[test]
    fn test_try_reuse_buffer() {
        fn test_expect_success(
            body_range: Range<usize>,
            prefix: usize,
            suffix: usize,
            max_copy_bytes: usize,
        ) {
            let mut bytes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
            let buffer = Buf::new(&mut bytes[..], body_range);
            let body = buffer.as_ref().to_vec();
            let buffer = try_reuse_buffer(buffer, prefix, suffix, max_copy_bytes).unwrap();
            assert_eq!(buffer.as_ref(), body.as_slice());
            assert!(buffer.prefix_len() >= prefix);
            assert!(buffer.suffix_len() >= suffix);
        }

        fn test_expect_failure(
            body_range: Range<usize>,
            prefix: usize,
            suffix: usize,
            max_copy_bytes: usize,
        ) {
            let mut bytes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
            let buffer = Buf::new(&mut bytes[..], body_range.clone());
            let mut bytes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
            let orig = Buf::new(&mut bytes[..], body_range.clone());
            let buffer = try_reuse_buffer(buffer, prefix, suffix, max_copy_bytes).unwrap_err();
            assert_eq!(buffer, orig);
        }

        // No prefix or suffix trivially succeeds.
        test_expect_success(0..10, 0, 0, 0);
        // If we have enough prefix/suffix, it succeeds.
        test_expect_success(1..9, 1, 1, 0);
        // If we don't have enough prefix/suffix, but we have enough capacity to
        // move the buffer within the body, it succeeds...
        test_expect_success(0..9, 1, 0, 9);
        test_expect_success(1..10, 0, 1, 9);
        // ...but if we don't provide a large enough max_copy_bytes, it will fail.
        test_expect_failure(0..9, 1, 0, 8);
        test_expect_failure(1..10, 0, 1, 8);
    }

    #[test]
    fn test_buffer_alloc_buffer_provider() {
        // Test that the blanket impl of `BufferProvider` for `A: BufferAlloc`
        // works as expected, returning Either::A when reusing is possible, and
        // returning Either::B when realloc'ing is needed.

        fn test_expect(body_range: Range<usize>, prefix: usize, suffix: usize, expect_a: bool) {
            let mut bytes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
            let buffer = Buf::new(&mut bytes[..], body_range);
            let body = buffer.as_ref().to_vec();
            let buffer =
                BufferProvider::reuse_or_realloc(new_buf_vec, buffer, prefix, suffix).unwrap();
            match &buffer {
                Either::A(_) if expect_a => {}
                Either::B(_) if !expect_a => {}
                Either::A(_) => panic!("expected Eitehr::B variant"),
                Either::B(_) => panic!("expected Eitehr::A variant"),
            }
            let bytes: &[u8] = buffer.as_ref();
            assert_eq!(bytes, body.as_slice());
            assert!(buffer.prefix_len() >= prefix);
            assert!(buffer.suffix_len() >= suffix);
        }

        // Expect that we'll be able to reuse the existing buffer.
        fn test_expect_reuse(body_range: Range<usize>, prefix: usize, suffix: usize) {
            test_expect(body_range, prefix, suffix, true);
        }

        // Expect that we'll need to allocate a new buffer.
        fn test_expect_realloc(body_range: Range<usize>, prefix: usize, suffix: usize) {
            test_expect(body_range, prefix, suffix, false);
        }

        // No prefix or suffix trivially succeeds.
        test_expect_reuse(0..10, 0, 0);
        // If we have enough prefix/suffix, it succeeds.
        test_expect_reuse(1..9, 1, 1);
        // If we don't have enough prefix/suffix, but we have enough capacity to
        // move the buffer within the body, it succeeds.
        test_expect_reuse(0..9, 1, 0);
        test_expect_reuse(1..10, 0, 1);
        // If we don't have enough capacity, it fails and must realloc.
        test_expect_realloc(0..9, 1, 1);
        test_expect_realloc(1..10, 1, 1);
    }

    /// Simple Vec-backed buffer to test fragmented buffers implementation.
    ///
    /// `ScatterGatherBuf` keeps:
    /// - an inner buffer `inner`, which is always part of its body.
    /// - extra backing memory in `data`.
    ///
    /// `data` has two "root" regions, marked by the midpoint `mid`. Everything
    /// left of `mid` is this buffer's prefix, and after `mid` is this buffer's
    /// suffix.
    ///
    /// The `range` field keeps the range in `data` that contains *filled*
    /// prefix and suffix information. `range.start` is always less than or
    /// equal to `mid` and `range.end` is always greater than or equal to `mid`,
    /// such that growing the front of the buffer means decrementing
    /// `range.start` and growing the back of the buffer means incrementing
    /// `range.end`.
    ///
    ///  At any time this buffer's parts are:
    /// - Free prefix data in range `0..range.start`.
    /// - Used prefix data (now part of body) in range `range.start..mid`.
    /// - Inner buffer body in `inner`.
    /// - Used suffix data (now part of body) in range `mid..range.end`.
    /// - Free suffix data in range `range.end..`
    struct ScatterGatherBuf<B> {
        data: Vec<u8>,
        mid: usize,
        range: Range<usize>,
        inner: B,
    }

    impl<B: BufferMut> FragmentedBuffer for ScatterGatherBuf<B> {
        fn len(&self) -> usize {
            self.inner.len() + (self.range.end - self.range.start)
        }

        fn with_bytes<R, F>(&self, f: F) -> R
        where
            F: for<'a, 'b> FnOnce(FragmentedBytes<'a, 'b>) -> R,
        {
            let (_, rest) = self.data.split_at(self.range.start);
            let (prefix_b, rest) = rest.split_at(self.mid - self.range.start);
            let (suffix_b, _) = rest.split_at(self.range.end - self.mid);
            let mut bytes = [prefix_b, self.inner.as_ref(), suffix_b];
            f(FragmentedBytes::new(&mut bytes[..]))
        }
    }

    impl<B: BufferMut> FragmentedBufferMut for ScatterGatherBuf<B> {
        fn with_bytes_mut<R, F>(&mut self, f: F) -> R
        where
            F: for<'a, 'b> FnOnce(FragmentedBytesMut<'a, 'b>) -> R,
        {
            let (_, rest) = self.data.split_at_mut(self.range.start);
            let (prefix_b, rest) = rest.split_at_mut(self.mid - self.range.start);
            let (suffix_b, _) = rest.split_at_mut(self.range.end - self.mid);
            let mut bytes = [prefix_b, self.inner.as_mut(), suffix_b];
            f(FragmentedBytesMut::new(&mut bytes[..]))
        }
    }

    impl<B: BufferMut> GrowBuffer for ScatterGatherBuf<B> {
        fn prefix_len(&self) -> usize {
            self.range.start
        }

        fn suffix_len(&self) -> usize {
            self.data.len() - self.range.end
        }

        fn grow_front(&mut self, n: usize) {
            self.range.start -= n;
        }

        fn grow_back(&mut self, n: usize) {
            self.range.end += n;
            assert!(self.range.end <= self.data.len());
        }
    }

    impl<B: BufferMut> TargetBuffer for ScatterGatherBuf<B> {
        fn with_parts<O, F>(&mut self, f: F) -> O
        where
            F: for<'a, 'b> FnOnce(&'a mut [u8], FragmentedBytesMut<'a, 'b>, &'a mut [u8]) -> O,
        {
            let (prefix, rest) = self.data.split_at_mut(self.range.start);
            let (prefix_b, rest) = rest.split_at_mut(self.mid - self.range.start);
            let (suffix_b, suffix) = rest.split_at_mut(self.range.end - self.mid);
            let mut bytes = [prefix_b, self.inner.as_mut(), suffix_b];
            f(prefix, bytes.as_fragmented_byte_slice(), suffix)
        }
    }

    struct ScatterGatherProvider;

    impl<B: BufferMut> BufferProvider<B, ScatterGatherBuf<B>> for ScatterGatherProvider {
        type Error = Never;

        fn reuse_or_realloc(
            self,
            buffer: B,
            prefix: usize,
            suffix: usize,
        ) -> Result<ScatterGatherBuf<B>, (Self::Error, B)> {
            let inner = buffer;
            let data = vec![0; prefix + suffix];
            let range = Range { start: prefix, end: prefix };
            let mid = prefix;
            Ok(ScatterGatherBuf { inner, data, range, mid })
        }
    }

    #[test]
    fn test_scatter_gather_serialize() {
        // Assert that a buffer composed of different allocations can be used as
        // a serialization target, while reusing an internal body buffer.
        let buf = Buf::new(vec![10, 20, 30, 40, 50], ..);
        let pb = DummyPacketBuilder::new(3, 2, 0, MAX_USIZE);
        let ser = buf.encapsulate(pb);
        let result = ser.serialize_outer(ScatterGatherProvider {}).unwrap();
        let flattened = result.to_flattened_vec();
        assert_eq!(&flattened[..], &[0xFF, 0xFF, 0xFF, 10, 20, 30, 40, 50, 0xFE, 0xFE]);
    }
}
