Expand description
§dusk-bytes
dusk-bytes is a small, no_std friendly crate that helps you implement
fixed-size (de)serialization for your types using const generics.
A type that can be represented by exactly N bytes implements Serializable<N>. From there, the crate provides convenience traits to:
- deserialize from slices and byte readers (
DeserializableSlice). - parse hex strings (
ParseHexStr). - parse hex literals at compile time (
hex()). - and format types as hex (
Hex/HexDebug).
This crate is used as the foundation for a number of Dusk types where a compact, allocation-free byte representation is desirable.
§Features
#.- Const-generic byte sizes (e.g.
Serializable<32>). - Default helpers that work with custom error types via the
BadLengthandInvalidChartraits. - Built-in
Serializableimplementations for common integer primitives (little-endian).
§Quick start
Implement Serializable<N> for your type:
use dusk_bytes::{DeserializableSlice, ParseHexStr, Serializable};
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
struct Point {
x: u16,
y: u16,
}
impl Serializable<4> for Point {
type Error = dusk_bytes::Error;
fn from_bytes(buf: &[u8; 4]) -> Result<Self, Self::Error> {
let x = u16::from_le_bytes([buf[0], buf[1]]);
let y = u16::from_le_bytes([buf[2], buf[3]]);
Ok(Self { x, y })
}
fn to_bytes(&self) -> [u8; 4] {
let mut out = [0u8; 4];
out[0..2].copy_from_slice(&self.x.to_le_bytes());
out[2..4].copy_from_slice(&self.y.to_le_bytes());
out
}
}
// `DeserializableSlice` is auto-implemented for any `Serializable` type.
let p = Point::from_slice(&[1, 0, 2, 0]).unwrap();
assert_eq!(p, Point { x: 1, y: 2 });
// `ParseHexStr` is also auto-implemented.
let p2 = Point::from_hex_str("01000200").unwrap();
assert_eq!(p2, p);§Hex parsing
§Runtime: ParseHexStr::from_hex_str
from_hex_str parses the first N * 2 characters of a string slice (two hex
characters per byte).
- If the string is shorter than
N * 2, it returns aBadLengtherror. - If a non-hex character is found, it returns an
InvalidCharerror. - If the string is longer, extra characters are ignored.
§Compile-time: hex()
hex() is a const fn that parses an ASCII hex byte string like
b"deadbeef" into a byte array.
use dusk_bytes::hex;
const MAGIC: [u8; 4] = hex(b"deadbeef");
assert_eq!(MAGIC, [0xde, 0xad, 0xbe, 0xef]);The input byte string must have an even length (two hex digits per output byte). Invalid characters cause a compile-time panic during const evaluation.
§Hex formatting: Hex and HexDebug
dusk-bytes re-exports two derive macros from the companion derive-hex crate:
#[derive(Hex)]implementscore::fmt::LowerHexandcore::fmt::UpperHex.#[derive(HexDebug)]additionally implementscore::fmt::Debugand formats the value as hex for{:x?}/{:X?}.
Both derives expect your type to expose a to_bytes() method (which the
Serializable trait already provides).
use dusk_bytes::HexDebug;
#[derive(Copy, Clone, HexDebug)]
struct IdPrefix([u8; 4]);
impl IdPrefix {
pub fn to_bytes(&self) -> [u8; 4] {
self.0
}
}
let p = IdPrefix([0xde, 0xad, 0xbe, 0xef]);
assert_eq!(format!("{:x}", p), "deadbeef");
assert_eq!(format!("{:#x}", p), "0xdeadbeef");
assert_eq!(format!("{:x?}", p), "deadbeef");§Readers and writers
For embedded / no_std environments, the crate provides minimal Read / Write
traits (inspired by std::io) and implements them for:
&[u8](reader)&mut [u8](writer)
use dusk_bytes::{DeserializableSlice, Read, Serializable, Write};
let value: u32 = 0x01020304;
let mut buf = [0u8; 4];
{
let mut w = &mut buf[..];
w.write(&value.to_bytes()).unwrap();
}
let mut r = &buf[..];
let parsed = u32::from_reader(&mut r).unwrap();
assert_eq!(parsed, value);
assert!(r.is_empty());§Error handling
The crate provides a small default Error enum that is used by the built-in
primitive implementations.
If you want to keep your own error type, implement:
BadLength(for slice/reader underflow), andInvalidChar(for hex parsing).
Those traits are used by the default implementations of DeserializableSlice
and ParseHexStr.
§License
Licensed under the Mozilla Public License 2.0 (MPL-2.0).
Enums§
- Error
- Dusk Bytes operation error variants
Traits§
- BadLength
- Trait to be implemented for the associated Error used in
[
DeserializableSlice::from_slice]. The function is called if the slice given is smaller than the mandatory size for the struct. - Deserializable
Slice - An optional trait used to implement [
from_slice] on top of types that usesSerializabletrait. The default implementation makes use ofSerializabletrait to provide the necessary deserialization functionality without additional code from the consumer. - Invalid
Char - Trait to be implemented for the associated Error used in
[
ParseHexStr::from_hex_str]. The function is called if an invalid character is found in the string slice. - Parse
HexStr - An optional trait used to parse a string slice for types that implements
the
Serializabletrait. The default implementation makes use ofSerializabletrait to provide the necessary parsing functionality without additional code from the consumer. - Read
- Implementors of the
Readtrait are called ‘readers’. - Serializable
- The core trait used to implement [
from_bytes] and [to_bytes] - Write
- Implementors of the
Writetrait are sometimes called ‘writers’.
Functions§
- hex
- A constant funtion to parse a bytes string representing hexadecimals
(e.g.
b"fe12c6") into bytes (e.g[0xfe, 0x12, 0xc6]). If a smaller destination buffer is provided, the value will be truncated (e.g[0xfe, 0x12]); if a bigger destination buffer is provided, it will be padded with zeroes (e.g. `[0xfe, 0x12, 0xc6, 0x0, 0x0])