#serialization #endian #deserialize #encode-decode #encode #decode


resend is a easy to use, performant, customizable and extendable Rust library for little-endian/big-endian serializing and deserializing

4 releases

0.1.3 Feb 18, 2023
0.1.2 Feb 18, 2023
0.1.1 Dec 21, 2022
0.1.0 Dec 19, 2022

#1112 in Encoding


2.5K SLoC


Resend is a easy to use, performant, customizable and extendable Rust library for little-endian/big-endian serializing and deserializing.


Two functions only:

snd() for any Write implementors (File, TcpStream etc)

rcv() for any Read implementors (File, TcpStream etc)


#with little-endian feature
resend = {version = "0.1", features = ["little"]}


use resend::{Snd, Rcv};

let mut vec = Vec::new();
vec.snd(0xFFABCDEF as u32)?;

let mut buf = &vec[..];
let v: i8 = buf.rcv()?;
let v: u16 = buf.rcv()?;
let v: u32 = buf.rcv()?;
let v: String = buf.rcv()?;


resend = {version = "0.1", features = ["little"]}
resend_derive = "0.1"
use resend::{Snd, Rcv, endian::{Ascii, UTF16}};
use resend_derive::{Snd, Rcv};

#[derive(Snd, Rcv)]
pub enum DeviceType {
    PrinterType(IoPrinter) = 4,
    ScardType = 0x20,
#[derive(Snd, Rcv)]
struct Device{
    device_id: u32,
    dos_name: Ascii,

#[derive(Snd, Rcv)]
pub struct IoPrinter{
    device: Device,
    length: u32,
    flags: u32,
    code_page: u32,
    pnp_name_len: u32,
    driver_name_len: u32,
    pnp_name: UTF16,
    driver_name: UTF16,

let dt: DeviceType = stream.rcv()?;


Write/Read trait based, no intermediate variables.


  • bool is serialized as 0_u8 (false) or 1_u8 (true).
  • String, Vec, Array, Slice, Collections, Ascii, UTF16: u32_length_header + data, no lengh header if "len" attribute is used.
  • Option is serialized as bool_header + optional data, no bool_header if "when" attribute is used.
  • Enum is serialized as tag value(int) + optional data. Use "repr" attribute for the size of tag value.
#[derive(Snd, Rcv)]
enum Color {
    Blue = 32,
    Green =4,

Color::Red is serialized as 0_u16. Color::Blue is serialized as 32_u16.

#[derive(Snd, Rcv)]
pub enum DeviceType {
    PrinterType(IoPrinter) = 4,
    ScardType = 0x20,

DeviceType::PrinterType(printer) is serialized as 4_u32 + IoPrinter data. DeviceType::ScardType is serialized as 0x20_u32.

Please be aware: discriminants on non-unit variants are stable since Rust 1.66), you have to use Rust nightly for previous versions.

Customizable (attributes)

  1. Send both little-endian and big-endian at the same time with the resend::endian::little::LE and resend::endian::big::BE:
  1. No serialization with #[skip] attribute.

  2. The length of String, Vector etc. can be from another field or constant with #[len(field_name_or_const)] attribute:

  1. #[when(expr)] attribute is used on Option field. This field will be deserialized only if the expr is true. Warning: "expr" is not checked on serializing, no extra bool value in this case.
#[when(code_page > 0)]
#[when((flags & 2) != 0)]
  1. Length can be u16 or VLQ with features (u32 by default)
resend = {version = "0.1", features = ["little", "len_16"]}
resend = {version = "0.1", features = ["big", "len_vlq"]}
  1. Restricted length with features: MAX_LEN_100M, MAX_LEN_500M, MAX_LEN_2G
resend = {version = "0.1", features = ["little", "len_16", "MAX_LEN_100M"]}


For example, you want a string with variable-length quantity

pub struct VarLenString (pub String);

impl Sendable for VarLenString {
    fn snd_to<S>(&self, writer: &mut S) -> io::Result<()>
        S: resend::Sender {

impl Receivable for VarLenString {
    fn rcv_from<R>(reader: &mut R) -> io::Result<Self>
        R: resend::Receiver {
        let len: VLQ = reader.rcv()?;
        let b = reader.rcv_bytes(*len)?;
        let s = std::str::from_utf8(&b)?;

Resend includes the following types for your convenience:

use resend::endian::{Ascii, UTF16, UTF16Char, VLQ};

Implements resend::FromReader and resend::IntoWriter if you need the "len(field_name)" attribute working on your type. For example:

impl FromReader for Vec<u8> {
    fn from_reader<R: Receiver>(reader: &mut R, len: usize) -> crate::Result<Self> {

impl IntoWriter for Vec<u8> {
    fn into_writer<S: Sender>(&self, writer: &mut S, len: usize) -> crate::Result<()> {
        let len_s = self.len();
        let (l, left) = if len > len_s {
            (len_s, len - len_s)
        } else {
            (len, 0)

        let b = &self[..l];


        if left > 0 {
            writer.snd_all(&vec![0; left])?;



  1. String, Ascii and UTF16 with #[len(field_name_or_const)] attribute: if the specified length is bigger then the actual length: extra '\0' will be appended when it's serialized, and extra '\0' will be removed after it's deserialized; if the specified length is smaller, the string will be truncated to that length. This is useful if you need null terminated, fixed length string.

  2. Convert int to Enum

//Conver little-endian u16 to Blue ("little" feature)
//[u8] doesn't implement Read, convert it to &[u8] with as_ref()
let c: Color = [32_u8, 0].as_ref().rcv()?;
  1. Use enumeration to serialize Object Oriented classes:
//type value (enum tag value) after the parent class
struct YourObject {
    parent: ParentClass,
    child: EnumOfChildClass,
//type value (enum tag value) before the parent class
struct Child {
    parent: ParentClass,
enum {

  1. resend::endian:Length handles 3 types: u32, u16, VLQ. It's better to use this Length type directly in your object.


MIT OR Apache-2.0


This library is developed for Remote Spark Corp's RDP (Remote Desktop Protocol) Project.


~34K SLoC