Crate byte

source ·
Expand description

A low-level, zero-copy and panic-free binary serializer and deserializer.

§Usage

First, add the following to your Cargo.toml:

[dependencies]
byte = "0.3"

Byte is a no_std library; it can be used in any #![no_std] situation or crate.

§Overview

Byte is designed for encoding or decoding binary data in a fast and low level way. A classical use case is I2C communication packages encoding.

Byte provides two core traits TryRead and TryWrite. Types implement these traits can be serialized into or deserialized from byte slices.

The library is meant to be simple, and it will always be.

§Examples

Deserialize a u32 from bytes:

use byte::*;

let bytes: &[u8] = &[0xde, 0xad, 0xbe, 0xef];

let offset = &mut 0;
let num = bytes.read_with::<u32>(offset, BE).unwrap();
assert_eq!(num, 0xdeadbeef);
assert_eq!(*offset, 4);

Deserialize a &str from bytes:

use byte::*;
use byte::ctx::{Str, NULL};

let bytes: &[u8] = b"hello, world!\0dump";

let offset = &mut 0;
let str = bytes.read_with::<&str>(offset, Str::Delimiter(NULL)).unwrap();
assert_eq!(str, "hello, world!");
assert_eq!(*offset, 14);

Byte supports serializing and deserializing language primitives by default.

  • &str (with Str context)
  • &[u8] (with Byte context)
  • u8, i8, u64, f64 … (with Endian context)
  • bool

§Define custom serializable/deserializable types

In this example, we implement TryRead and TryWrite for the Header type, which has a variable-length name and a boolean field.

§Binary Structure

|       | Name's Length (Big Endian) |                Name              | Enabled |
| ----- | -------------------------- | ---- | ---- | ---- | ---- | ---- | ------- |
| Byte  | 0            | 5           | 'H'  | 'E'  | 'L'  | 'L'  | 'O'  | 0       |

§Example

The only thing you may be curious about is the returned usize; that’s the number of bytes consumed by the read/write operation.

use byte::*;
use byte::ctx::*;

struct Header<'a> {
    name: &'a str,
    enabled: bool,
}

impl<'a> TryRead<'a, Endian> for Header<'a> {
    fn try_read(bytes: &'a [u8], endian: Endian) -> Result<(Self, usize)> {
        let offset = &mut 0;

        let name_len = bytes.read_with::<u16>(offset, endian)? as usize;
        let header = Header {
            name: bytes.read_with::<&str>(offset, Str::Len(name_len))?,
            enabled: bytes.read::<bool>(offset)?,
        };

        Ok((header, *offset))
    }
}

impl<'a> TryWrite<Endian> for Header<'a> {
    fn try_write(self, bytes: &mut [u8], endian: Endian) -> Result<usize> {
        let offset = &mut 0;

        bytes.write_with::<u16>(offset, self.name.len() as u16, endian)?;
        bytes.write::<&str>(offset, self.name)?;
        bytes.write::<bool>(offset, self.enabled)?;

        Ok(*offset)
    }
}

§Usage

let bytes = [0, 5, b"H"[0], b"E"[0], b"L"[0], b"L"[0], b"O"[0], 0];

let header: Header = bytes.read_with(&mut 0, BE).unwrap();

assert_eq!(header.name, "HELLO");
assert_eq!(header.enabled, false);

let mut write = [0u8; 8];
write.write_with(&mut 0, header, BE).unwrap();
assert_eq!(write, bytes);

Re-exports§

  • pub use ctx::BE;
  • pub use ctx::LE;

Modules§

  • Context for primitives

Structs§

  • An iterator that reads values of the same type from a byte slice.

Enums§

  • The error type for the byte crate.

Traits§

  • Extension methods for byte slices.
  • A data structure that can be deserialized. Types implementing this trait can be read() from a byte slice.
  • A data structure that can be serialized. Types implement this trait can be write() into a byte slice.

Functions§

  • A helper function that checks whether the given length exceeded the length of the slice; returns Err(Error::Incomplete) otherwise.

Type Aliases§

  • A specialized Result type for Byte