#bytes #generic #macro

macro generic-bytes-derive

A macro for derivation of SizedBytes, a trait for conversion to and from an array of bytes with a type-level size

3 unstable releases

0.2.2 Sep 19, 2022
0.2.1 Dec 28, 2021
0.2.0 Dec 28, 2021
0.1.0 Sep 16, 2020

#1295 in Procedural macros

MIT license

453 lines

SizedBytes Build Status

SizedBytes is a trait that embodies conversion to and from an array of bytes with a type-level length. It leverages the generic-array and typenum crates which offer this emulation of dependent types for type-level array lengths.

/// A trait for sized key material that can be represented within a fixed byte
/// array size, used to represent our DH key types. This trait being
/// implemented with Error = SomeError allows you to derive
/// `TryFrom<&[u8], Error = SomeError>`.
pub trait SizedBytes: Sized {
    /// The typed representation of the byte length
    type Len: ArrayLength<u8> + 'static;

    /// Converts this sized key material to a `GenericArray` of the same
    /// size. One can convert this to a `&[u8]` with `GenericArray::as_slice()`
    /// but the size information is then lost from the type.
    fn to_arr(&self) -> GenericArray<u8, Self::Len>;

    /// How to parse such sized material from a correctly-sized byte slice.
    fn from_arr(arr: &GenericArray<u8, Self::Len>) -> Result<Self, TryFromSizedBytesError>;

The crate generic-bytes-derive provides a derive macro that lets you derive a SizedBytes impl for any :

  • tuple of which all the elements satisfy a SizedBytes bound,
  • struct of which all the fields satisfy a SizeBytes bound.

The fields or components are serialized in (resp. deserialized from) their byte representation in the order in which they appear in the original struct or tuple.

For example:

struct Foo <T: SizedBytes>{
    f1: T,
    f2: GenericArray<u8, U32>,
// you can now call `to_arr` and `from_arr` on any Foo

A blanket implementation of SizedBytes is also provided for GenericArray<u8, N>.


Many applications in Rust do a lot of conversions to and from byte slices, manually or using methods such as bincode or bytes for performance. Nonetheless, composing those representations has always been tedious and has led to length checks which can be error-prone and cumbersome.

This lets you define conversion to a byte slice that bears its length in the type, and compose such conversions, thereby offering a safer and more automated way to deal with byte representations.


The API can be found here.


Add the following line to the dependencies of your Cargo.toml:

generic_bytes = "0.2.1"
generic_bytes_derive = "0.2.1"


The authors of this code are François Garillot (@huitseeker). To learn more about contributing to this project, see this document.


This project is MIT licensed.


~31K SLoC