4 releases (2 breaking)

0.4.0 Mar 26, 2022
0.2.1 Dec 28, 2021
0.2.0 Feb 8, 2021
0.1.0 Dec 22, 2020

#1831 in Encoding

Download history 7/week @ 2024-02-19 19/week @ 2024-02-26 4/week @ 2024-03-04 18/week @ 2024-03-11 7/week @ 2024-03-18 83/week @ 2024-04-01

109 downloads per month
Used in 2 crates

MIT license

41KB
807 lines

Rust bindings for the nachricht data interchange format

This is a pure Rust implementation of the binary nachricht data interchange format.

Minimum supported Rust version

Since this crates makes use of the fallible collection API to pre-allocate Collections when deserializing values, the minimum required Rust version is 1.57.0.

Usage

Add this to your Cargo.toml:

[dependencies]
nachricht = "0.4.0"

Then you can construct, encode and decode nachricht messages:

use std::borrow::Cow;
use std::collections::BTreeMap;
use nachricht::*;

fn main() -> Result<(), Box<dyn Error>> {
    let mut buf = Vec::new();
    let nachricht = Value::Record(BTreeMap::from([(Cow::Borrowed("key"), Value::Str(Cow::Borrowed("value")))]));
    Encoder::encode(&nachricht, &mut buf)?;
    let decoded = Decoder::decode(&buf)?.0;
    assert_eq!(nachricht, decoded);
    Ok(())
}

lib.rs:

All encoding functions take &self and a writer and return the amount of written bytes. All decoding functions take a buffer and return Self and the number of consumed bytes.

A note on usize

nachricht internally uses 64 bit unsigned integers to signify field lengths. Rust however uses the architecture-dependent usize for slice indexing. This means that on architectures where usize is smaller than u64 (32 bit i386 for instance), some valid nachricht messages can not be decoded since there would be no way to efficiently index the containers. A DecodeError::Length will be raised in these instances. Likewise, on architectures where usize is larger than u64, some valid Rust datastructures can not be encoded since there is no way to represent them in the wire format. A EncodeError::Length will be raised in these instances.

A note on Maps

The variant Value::Map uses a Vec of key-value pairs internally because Rust's floating point types f32 and f64 implement neither Ord nor Hash and thus a nachricht Value cannot be used as a key in any of the standard library maps.

Likewise, Value::Record uses a BTreeMap instead of a HashMap because field names need to have a stable ordering when deciding if a record with the same layout has already been encoded so that it can be reused.

Examples

use nachricht::*;
use std::borrow::Cow;
use std::collections::BTreeMap;

let mut buf = Vec::new();
let value = Value::Record(BTreeMap::from([(Cow::Borrowed("key"), Value::Str(Cow::Borrowed("value")))]));
Encoder::encode(&value, &mut buf);
assert_eq!(buf, [
    0xa1, // Record of length 1
    0x63, // Symbol of length 3
    0x6b, // 'k'
    0x65, // 'e'
    0x79, // 'y'
    0x45, // Str of length 5
    0x76, // 'v'
    0x61, // 'a'
    0x6c, // 'l'
    0x75, // 'u',
    0x65, // 'e'
]);
let decoded = Decoder::decode(&buf).unwrap();
assert_eq!(value, decoded.0);
assert_eq!(11, decoded.1);

No runtime deps