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, with the default
derivefeature, 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).
§Cargo features
derive(enabled by default) re-exports theHexandHexDebugprocedural macros fromderive-hex.
Consumers that only need serialization and parsing can disable default
features to keep dusk-bytes dependency-free:
dusk-bytes = { version = "0.1", default-features = false }§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.
§Const-capable: hex()
hex() is a const fn that parses an ASCII hex byte string like
b"deadbeef" into a byte array. It can be called at runtime or evaluated in a
constant context.
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 byte). An
odd trailing character is rejected even if the destination is already full;
it is not ignored like extra input to from_hex_str. An odd input length or
an invalid character in the portion consumed to fill the destination panics
at runtime. When hex() is evaluated in a constant context, the same panic is
reported during compilation.
§Hex formatting: Hex and HexDebug
With the default derive feature, 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?}.
Do not derive Hex or HexDebug for types containing secrets or other
confidential material. Both expose the complete to_bytes() output: Hex
through hexadecimal formatting such as {:x} and HexDebug additionally
through every Debug formatting path, including ordinary {:?}.
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!("{:?}", p), "deadbeef");
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 implemented by error types used by
DeserializableSlice::from_slice. The method is called when the given slice is shorter than the required size. - Deserializable
Slice - An optional trait used to implement
DeserializableSlice::from_sliceon top of types that use theSerializabletrait. The default implementation makes use ofSerializabletrait to provide the necessary deserialization functionality without additional code from the consumer. - Invalid
Char - Trait implemented by error types used by
ParseHexStr::from_hex_str. The method is called when 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
Serializable::from_bytesandSerializable::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])