Packable

Trait Packable 

Source
pub trait Packable: Sized + 'static {
    type UnpackError: Debug + From<Infallible>;
    type UnpackVisitor: Borrow<()>;

    // Required methods
    fn pack<P: Packer>(&self, packer: &mut P) -> Result<(), P::Error>;
    fn unpack<U: Unpacker>(
        unpacker: &mut U,
        visitor: Option<&Self::UnpackVisitor>,
    ) -> Result<Self, UnpackError<Self::UnpackError, U::Error>>;

    // Provided methods
    fn unpack_verified<U: Unpacker>(
        unpacker: &mut U,
        visitor: &Self::UnpackVisitor,
    ) -> Result<Self, UnpackError<Self::UnpackError, U::Error>> { ... }
    fn unpack_unverified<U: Unpacker>(
        unpacker: &mut U,
    ) -> Result<Self, UnpackError<Self::UnpackError, U::Error>> { ... }
    fn unpack_inner<V: Borrow<Self::UnpackVisitor>, U: Unpacker>(
        unpacker: &mut U,
        visitor: Option<&V>,
    ) -> Result<Self, UnpackError<Self::UnpackError, U::Error>> { ... }
}
Expand description

A type that can be packed and unpacked.

Almost all basic sized types implement this trait. This trait can be derived using the Packable macro. The following example shows how to implement this trait manually.

§Example

We will implement Packable for a type that encapsulates optional integer values (like Option<i32>).

We will use an integer prefix as a tag to determine which variant of the enum is being packed.

use core::convert::Infallible;

use packable::{
    error::{UnknownTagError, UnpackError, UnpackErrorExt},
    packer::Packer,
    unpacker::Unpacker,
    Packable,
};

pub enum Maybe {
    Nothing,
    Just(i32),
}

impl Packable for Maybe {
    type UnpackError = UnknownTagError<u8>;
    type UnpackVisitor = ();

    fn pack<P: Packer>(&self, packer: &mut P) -> Result<(), P::Error> {
        match self {
            // Pack a `0` byte and nothing else.
            Self::Nothing => 0u8.pack(packer),
            // Pack a `1` byte followed by the internal value.
            Self::Just(value) => {
                1u8.pack(packer)?;
                value.pack(packer)
            }
        }
    }

    fn unpack<U: Unpacker>(
        unpacker: &mut U,
        visitor: Option<&Self::UnpackVisitor>,
    ) -> Result<Self, UnpackError<Self::UnpackError, U::Error>> {
        match u8::unpack_inner(unpacker, visitor).coerce()? {
            0u8 => Ok(Self::Nothing),
            1u8 => Ok(Self::Just(i32::unpack_inner(unpacker, visitor).coerce()?)),
            tag => Err(UnpackError::Packable(UnknownTagError(tag))),
        }
    }
}

To understand the behavior of infallible and coerce check the UnpackError and UnpackErrorExt documentation.

We can also derive Packable for the Maybe type.

use packable::Packable;

#[derive(Packable)]
#[packable(tag_type = u8)]
pub enum Maybe {
    #[packable(tag = 0)]
    Nothing,
    #[packable(tag = 1)]
    Just(i32),
}

The code produced by this macro is equivalent to the one shown before.

§#[derive(Packable)] attributes

The derive implementation can be tweaked using #[packable(...)] attributes.

§Tags for enums

A very common pattern when implementing Packable for enums consists in introducing a prefix value to differentiate each variant of the enumeration when unpacking, this prefix value is known as a tag. The type of the tag is specified with the #[packable(tag_type = ...)] attribute and it can only be one of [u8], [u16], [u32] or [u64]. The tag value used for each variant is specified with the #[packable(tag = ...)] attribute and can only contain integer literal without any type prefixes (e.g. 42 is valid but 42u8 is not).

In the example above, the tag type is [u8], the Nothing variant has a tag value of 0 and the Just variant has a tag value of 1. This means that the packed version of Maybe::Nothing is [0] and the packed version of Maybe::Just(7) is [1, 0, 0, 0, 7].

The tag_type and tag attributes are mandatory for enums unless the enum has a #[repr(...)] attribute identifier, in which case the repr type will be used as the tag_type and each variant discriminant will be used as the tag. The tag_type and tag attributes take precedence over the repr attribute.

§The UnpackError associated type

The derive macro provides the optional attribute and #[packable(unpack_error = ...)] to specify the UnpackError associated type. The macro also provides sensible defaults for cases when the attribute is not used.

For structs, the default UnpackError type is the UnpackError of any of the fields type or Infallible in case the struct has no fields.

For enums, the default UnpackError type is UnknownTagError<T> where T is the type specified according to the tag_type or repr attributes.

Following the example above, Maybe::UnpackError is UnknownTagError<u8> because no unpack_error attribute was specified.

§Error conversion

The unpack_error attribute can also receive an optional additional argument using the with identifier: #[packable(unpack_error = ..., with = ...)]. This with argument must be a Rust expression and it is used to map the UnpackError produced while unpacking each one of the fields of the type.

Sometimes it is required to map the UnpackError for each field individually. The #[packable(unpack_error_with = ...)] attribute can be applied to each field for this purpose. This attribute takes precedence over the with expression specified in the unpack_error attribute.

The error produced when an invalid tag is found while unpacking an enum can also be specified using the with_error optional argument for the tag_type attribute: #[packable(tag_type = ..., with_error = ...)]. This argument must be a valid Rust expression.

§Additional semantic verifications

From time to time it is required to do additional semantic verifications over one of more fields of a struct or an enum’s variant. This can be done using the #[packable(verify_with = ...)] attribute which must receive a valid Rust path refering to a function with the signature

fn<P: Packable, F>(field: &F, visitor: &P::UnpackVisitor) -> Result<(), P::UnpackError>

where F is the type of the field being verified, P is the type of the struct or enum. This verification function will be run immediately after unpacking the field. The visitor param can be excluded if it is not needed for verification.

Required Associated Types§

Source

type UnpackError: Debug + From<Infallible>

The error type that can be returned if some semantic error occurs while unpacking.

It is recommended to use Infallible if this kind of error is impossible or UnknownTagError when implementing this trait for an enum.

Source

type UnpackVisitor: Borrow<()>

FIXME: docs

Required Methods§

Source

fn pack<P: Packer>(&self, packer: &mut P) -> Result<(), P::Error>

Packs this value into the given Packer.

Source

fn unpack<U: Unpacker>( unpacker: &mut U, visitor: Option<&Self::UnpackVisitor>, ) -> Result<Self, UnpackError<Self::UnpackError, U::Error>>

Unpacks this value from the given Unpacker. The optional visitor can be used to make additional syntactic checks.

Provided Methods§

Source

fn unpack_verified<U: Unpacker>( unpacker: &mut U, visitor: &Self::UnpackVisitor, ) -> Result<Self, UnpackError<Self::UnpackError, U::Error>>

Unpacks this value from the given Unpacker with a visitor for validation.

Source

fn unpack_unverified<U: Unpacker>( unpacker: &mut U, ) -> Result<Self, UnpackError<Self::UnpackError, U::Error>>

Unpacks this value from the given Unpacker without validation.

Source

fn unpack_inner<V: Borrow<Self::UnpackVisitor>, U: Unpacker>( unpacker: &mut U, visitor: Option<&V>, ) -> Result<Self, UnpackError<Self::UnpackError, U::Error>>

Unpacks an inner value whose visitor type can be borrowed from the outer visitor.

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.

Implementations on Foreign Types§

Source§

impl Packable for bool

Source§

fn pack<P: Packer>(&self, packer: &mut P) -> Result<(), P::Error>

Booleans are packed as u8 integers following Rust’s data layout.

Source§

fn unpack<U: Unpacker>( unpacker: &mut U, visitor: Option<&Self::UnpackVisitor>, ) -> Result<Self, UnpackError<Self::UnpackError, U::Error>>

Booleans are unpacked if the byte used to represent them is non-zero.

Source§

type UnpackError = Infallible

Source§

type UnpackVisitor = ()

Source§

impl Packable for f32

Source§

type UnpackError = Infallible

Source§

type UnpackVisitor = ()

Source§

fn pack<P: Packer>(&self, packer: &mut P) -> Result<(), P::Error>

Source§

fn unpack<U: Unpacker>( unpacker: &mut U, _: Option<&Self::UnpackVisitor>, ) -> Result<Self, UnpackError<Self::UnpackError, U::Error>>

Source§

impl Packable for f64

Source§

type UnpackError = Infallible

Source§

type UnpackVisitor = ()

Source§

fn pack<P: Packer>(&self, packer: &mut P) -> Result<(), P::Error>

Source§

fn unpack<U: Unpacker>( unpacker: &mut U, _: Option<&Self::UnpackVisitor>, ) -> Result<Self, UnpackError<Self::UnpackError, U::Error>>

Source§

impl Packable for i8

Source§

type UnpackError = Infallible

Source§

type UnpackVisitor = ()

Source§

fn pack<P: Packer>(&self, packer: &mut P) -> Result<(), P::Error>

Source§

fn unpack<U: Unpacker>( unpacker: &mut U, _: Option<&Self::UnpackVisitor>, ) -> Result<Self, UnpackError<Self::UnpackError, U::Error>>

Source§

impl Packable for i16

Source§

type UnpackError = Infallible

Source§

type UnpackVisitor = ()

Source§

fn pack<P: Packer>(&self, packer: &mut P) -> Result<(), P::Error>

Source§

fn unpack<U: Unpacker>( unpacker: &mut U, _: Option<&Self::UnpackVisitor>, ) -> Result<Self, UnpackError<Self::UnpackError, U::Error>>

Source§

impl Packable for i32

Source§

type UnpackError = Infallible

Source§

type UnpackVisitor = ()

Source§

fn pack<P: Packer>(&self, packer: &mut P) -> Result<(), P::Error>

Source§

fn unpack<U: Unpacker>( unpacker: &mut U, _: Option<&Self::UnpackVisitor>, ) -> Result<Self, UnpackError<Self::UnpackError, U::Error>>

Source§

impl Packable for i64

Source§

type UnpackError = Infallible

Source§

type UnpackVisitor = ()

Source§

fn pack<P: Packer>(&self, packer: &mut P) -> Result<(), P::Error>

Source§

fn unpack<U: Unpacker>( unpacker: &mut U, _: Option<&Self::UnpackVisitor>, ) -> Result<Self, UnpackError<Self::UnpackError, U::Error>>

Source§

impl Packable for i128

Source§

type UnpackError = Infallible

Source§

type UnpackVisitor = ()

Source§

fn pack<P: Packer>(&self, packer: &mut P) -> Result<(), P::Error>

Source§

fn unpack<U: Unpacker>( unpacker: &mut U, _: Option<&Self::UnpackVisitor>, ) -> Result<Self, UnpackError<Self::UnpackError, U::Error>>

Source§

impl Packable for u8

Source§

type UnpackError = Infallible

Source§

type UnpackVisitor = ()

Source§

fn pack<P: Packer>(&self, packer: &mut P) -> Result<(), P::Error>

Source§

fn unpack<U: Unpacker>( unpacker: &mut U, _: Option<&Self::UnpackVisitor>, ) -> Result<Self, UnpackError<Self::UnpackError, U::Error>>

Source§

impl Packable for u16

Source§

type UnpackError = Infallible

Source§

type UnpackVisitor = ()

Source§

fn pack<P: Packer>(&self, packer: &mut P) -> Result<(), P::Error>

Source§

fn unpack<U: Unpacker>( unpacker: &mut U, _: Option<&Self::UnpackVisitor>, ) -> Result<Self, UnpackError<Self::UnpackError, U::Error>>

Source§

impl Packable for u32

Source§

type UnpackError = Infallible

Source§

type UnpackVisitor = ()

Source§

fn pack<P: Packer>(&self, packer: &mut P) -> Result<(), P::Error>

Source§

fn unpack<U: Unpacker>( unpacker: &mut U, _: Option<&Self::UnpackVisitor>, ) -> Result<Self, UnpackError<Self::UnpackError, U::Error>>

Source§

impl Packable for u64

Source§

type UnpackError = Infallible

Source§

type UnpackVisitor = ()

Source§

fn pack<P: Packer>(&self, packer: &mut P) -> Result<(), P::Error>

Source§

fn unpack<U: Unpacker>( unpacker: &mut U, _: Option<&Self::UnpackVisitor>, ) -> Result<Self, UnpackError<Self::UnpackError, U::Error>>

Source§

impl Packable for u128

Source§

type UnpackError = Infallible

Source§

type UnpackVisitor = ()

Source§

fn pack<P: Packer>(&self, packer: &mut P) -> Result<(), P::Error>

Source§

fn unpack<U: Unpacker>( unpacker: &mut U, _: Option<&Self::UnpackVisitor>, ) -> Result<Self, UnpackError<Self::UnpackError, U::Error>>

Source§

impl<A: Packable> Packable for (A,)

Source§

type UnpackError = <A as Packable>::UnpackError

Source§

type UnpackVisitor = <A as Packable>::UnpackVisitor

Source§

fn pack<P: Packer>(&self, packer: &mut P) -> Result<(), P::Error>

Source§

fn unpack<U: Unpacker>( unpacker: &mut U, visitor: Option<&Self::UnpackVisitor>, ) -> Result<Self, UnpackError<Self::UnpackError, U::Error>>

Source§

impl<A: Packable, B: Packable> Packable for (A, B)

Source§

type UnpackError = <A as Packable>::UnpackError

Source§

type UnpackVisitor = <A as Packable>::UnpackVisitor

Source§

fn pack<P: Packer>(&self, packer: &mut P) -> Result<(), P::Error>

Source§

fn unpack<U: Unpacker>( unpacker: &mut U, visitor: Option<&Self::UnpackVisitor>, ) -> Result<Self, UnpackError<Self::UnpackError, U::Error>>

Source§

impl<A: Packable, B: Packable, C: Packable> Packable for (A, B, C)

Source§

type UnpackError = <A as Packable>::UnpackError

Source§

type UnpackVisitor = <A as Packable>::UnpackVisitor

Source§

fn pack<P: Packer>(&self, packer: &mut P) -> Result<(), P::Error>

Source§

fn unpack<U: Unpacker>( unpacker: &mut U, visitor: Option<&Self::UnpackVisitor>, ) -> Result<Self, UnpackError<Self::UnpackError, U::Error>>

Source§

impl<A: Packable, B: Packable, C: Packable, D: Packable> Packable for (A, B, C, D)

Source§

type UnpackError = <A as Packable>::UnpackError

Source§

type UnpackVisitor = <A as Packable>::UnpackVisitor

Source§

fn pack<P: Packer>(&self, packer: &mut P) -> Result<(), P::Error>

Source§

fn unpack<U: Unpacker>( unpacker: &mut U, visitor: Option<&Self::UnpackVisitor>, ) -> Result<Self, UnpackError<Self::UnpackError, U::Error>>

Source§

impl<A: Packable, B: Packable, C: Packable, D: Packable, E: Packable> Packable for (A, B, C, D, E)

Source§

type UnpackError = <A as Packable>::UnpackError

Source§

type UnpackVisitor = <A as Packable>::UnpackVisitor

Source§

fn pack<P: Packer>(&self, packer: &mut P) -> Result<(), P::Error>

Source§

fn unpack<U: Unpacker>( unpacker: &mut U, visitor: Option<&Self::UnpackVisitor>, ) -> Result<Self, UnpackError<Self::UnpackError, U::Error>>

Source§

impl<A: Packable, B: Packable, C: Packable, D: Packable, E: Packable, F: Packable> Packable for (A, B, C, D, E, F)

Source§

type UnpackError = <A as Packable>::UnpackError

Source§

type UnpackVisitor = <A as Packable>::UnpackVisitor

Source§

fn pack<P: Packer>(&self, packer: &mut P) -> Result<(), P::Error>

Source§

fn unpack<U: Unpacker>( unpacker: &mut U, visitor: Option<&Self::UnpackVisitor>, ) -> Result<Self, UnpackError<Self::UnpackError, U::Error>>

Source§

impl<A: Packable, B: Packable, C: Packable, D: Packable, E: Packable, F: Packable, G: Packable> Packable for (A, B, C, D, E, F, G)

Source§

type UnpackError = <A as Packable>::UnpackError

Source§

type UnpackVisitor = <A as Packable>::UnpackVisitor

Source§

fn pack<P: Packer>(&self, packer: &mut P) -> Result<(), P::Error>

Source§

fn unpack<U: Unpacker>( unpacker: &mut U, visitor: Option<&Self::UnpackVisitor>, ) -> Result<Self, UnpackError<Self::UnpackError, U::Error>>

Source§

impl<A: Packable, B: Packable, C: Packable, D: Packable, E: Packable, F: Packable, G: Packable, H: Packable> Packable for (A, B, C, D, E, F, G, H)

Source§

type UnpackError = <A as Packable>::UnpackError

Source§

type UnpackVisitor = <A as Packable>::UnpackVisitor

Source§

fn pack<P: Packer>(&self, packer: &mut P) -> Result<(), P::Error>

Source§

fn unpack<U: Unpacker>( unpacker: &mut U, visitor: Option<&Self::UnpackVisitor>, ) -> Result<Self, UnpackError<Self::UnpackError, U::Error>>

Source§

impl<A: Packable, B: Packable, C: Packable, D: Packable, E: Packable, F: Packable, G: Packable, H: Packable, I: Packable> Packable for (A, B, C, D, E, F, G, H, I)

Source§

type UnpackError = <A as Packable>::UnpackError

Source§

type UnpackVisitor = <A as Packable>::UnpackVisitor

Source§

fn pack<P: Packer>(&self, packer: &mut P) -> Result<(), P::Error>

Source§

fn unpack<U: Unpacker>( unpacker: &mut U, visitor: Option<&Self::UnpackVisitor>, ) -> Result<Self, UnpackError<Self::UnpackError, U::Error>>

Source§

impl<A: Packable, B: Packable, C: Packable, D: Packable, E: Packable, F: Packable, G: Packable, H: Packable, I: Packable, J: Packable> Packable for (A, B, C, D, E, F, G, H, I, J)

Source§

type UnpackError = <A as Packable>::UnpackError

Source§

type UnpackVisitor = <A as Packable>::UnpackVisitor

Source§

fn pack<P: Packer>(&self, packer: &mut P) -> Result<(), P::Error>

Source§

fn unpack<U: Unpacker>( unpacker: &mut U, visitor: Option<&Self::UnpackVisitor>, ) -> Result<Self, UnpackError<Self::UnpackError, U::Error>>

Source§

impl<A: Packable, B: Packable, C: Packable, D: Packable, E: Packable, F: Packable, G: Packable, H: Packable, I: Packable, J: Packable, K: Packable> Packable for (A, B, C, D, E, F, G, H, I, J, K)

Source§

type UnpackError = <A as Packable>::UnpackError

Source§

type UnpackVisitor = <A as Packable>::UnpackVisitor

Source§

fn pack<P: Packer>(&self, packer: &mut P) -> Result<(), P::Error>

Source§

fn unpack<U: Unpacker>( unpacker: &mut U, visitor: Option<&Self::UnpackVisitor>, ) -> Result<Self, UnpackError<Self::UnpackError, U::Error>>

Source§

impl<A: Packable, B: Packable, C: Packable, D: Packable, E: Packable, F: Packable, G: Packable, H: Packable, I: Packable, J: Packable, K: Packable, L: Packable> Packable for (A, B, C, D, E, F, G, H, I, J, K, L)

Source§

type UnpackError = <A as Packable>::UnpackError

Source§

type UnpackVisitor = <A as Packable>::UnpackVisitor

Source§

fn pack<P: Packer>(&self, packer: &mut P) -> Result<(), P::Error>

Source§

fn unpack<U: Unpacker>( unpacker: &mut U, visitor: Option<&Self::UnpackVisitor>, ) -> Result<Self, UnpackError<Self::UnpackError, U::Error>>

Source§

impl<T: Packable> Packable for Option<T>

Options are packed and unpacked using 0u8 as the prefix for None and 1u8 as the prefix for Some.

Source§

impl<T: Packable> Packable for Box<T>

Source§

type UnpackError = <T as Packable>::UnpackError

Source§

type UnpackVisitor = <T as Packable>::UnpackVisitor

Source§

fn pack<P: Packer>(&self, packer: &mut P) -> Result<(), P::Error>

Source§

fn unpack<U: Unpacker>( unpacker: &mut U, visitor: Option<&Self::UnpackVisitor>, ) -> Result<Self, UnpackError<Self::UnpackError, U::Error>>

Source§

impl<T: Packable, const N: usize> Packable for [T; N]

Source§

type UnpackError = <T as Packable>::UnpackError

Source§

type UnpackVisitor = <T as Packable>::UnpackVisitor

Source§

fn pack<P: Packer>(&self, packer: &mut P) -> Result<(), P::Error>

Source§

fn unpack<U: Unpacker>( unpacker: &mut U, visitor: Option<&Self::UnpackVisitor>, ) -> Result<Self, UnpackError<Self::UnpackError, U::Error>>

Implementors§

Source§

impl<B> Packable for StringPrefix<B>
where B: Bounded + Packable<UnpackVisitor = ()>, <B::Bounds as TryInto<B>>::Error: Debug, <B as TryFrom<usize>>::Error: Debug, Range<B::Bounds>: Iterator<Item = B::Bounds>,

Source§

impl<K, V, B> Packable for BTreeMapPrefix<K, V, B>
where K: Packable + Ord, V: Packable, B: Bounded + Packable<UnpackVisitor = ()>, <B::Bounds as TryInto<B>>::Error: Debug, <B as TryFrom<usize>>::Error: Debug, Range<B::Bounds>: Iterator<Item = B::Bounds>, V::UnpackVisitor: Borrow<K::UnpackVisitor>,

Source§

impl<K, V, B> Packable for HashMapPrefix<K, V, B>
where K: Packable + Eq + Hash, V: Packable + PartialEq, B: Bounded + Packable<UnpackVisitor = ()>, <B::Bounds as TryInto<B>>::Error: Debug, <B as TryFrom<usize>>::Error: Debug, Range<B::Bounds>: Iterator<Item = B::Bounds>, V::UnpackVisitor: Borrow<K::UnpackVisitor>,

Source§

impl<T, B> Packable for BTreeSetPrefix<T, B>
where T: Packable + Ord, B: Bounded + Packable<UnpackVisitor = ()>, <B::Bounds as TryInto<B>>::Error: Debug, <B as TryFrom<usize>>::Error: Debug, Range<B::Bounds>: Iterator<Item = B::Bounds>,

Source§

impl<T, B> Packable for BoxedSlicePrefix<T, B>
where T: Packable, B: Bounded + Packable<UnpackVisitor = ()>, <B::Bounds as TryInto<B>>::Error: Debug, <B as TryFrom<usize>>::Error: Debug, Range<B::Bounds>: Iterator<Item = B::Bounds>,

Source§

impl<T, B> Packable for VecPrefix<T, B>
where T: Packable, B: Bounded + Packable<UnpackVisitor = ()>, <B::Bounds as TryInto<B>>::Error: Debug, <B as TryFrom<usize>>::Error: Debug, Range<B::Bounds>: Iterator<Item = B::Bounds>,

Source§

impl<const MIN: u8, const MAX: u8> Packable for BoundedU8<MIN, MAX>

Source§

impl<const MIN: u16, const MAX: u16> Packable for BoundedU16<MIN, MAX>

Source§

impl<const MIN: u32, const MAX: u32> Packable for BoundedU32<MIN, MAX>

Source§

impl<const MIN: u64, const MAX: u64> Packable for BoundedU64<MIN, MAX>