fcpw 0.1.1

Fast, variation-tolerant CBOR codec
Documentation
#![cfg(feature = "serde")]

use fcpw::{Value, from_slice, to_vec, value};
use serde::{Deserialize, Serialize};

#[derive(Debug, PartialEq, Serialize, Deserialize)]
struct Record {
    name: String,
    bytes: serde_bytes::ByteBuf,
    wide: u128,
    optional: Option<u32>,
}

#[derive(Debug, PartialEq, Serialize, Deserialize)]
enum Choice {
    Unit,
    Tuple(u32, String),
    Struct { enabled: bool },
}

#[test]
fn value_works_with_one_shot_serde_apis_and_preserves_cbor_extensions() {
    let values = [
        Value::Unsigned(42),
        Value::Negative(-2),
        Value::Bytes(vec![1, 2]),
        Value::Text("hello".into()),
        Value::Array(vec![Value::Bool(true), Value::Null]),
        Value::Map(vec![(Value::Text("k".into()), Value::Float(1.5))]),
        Value::Tag(100, Box::new(Value::Undefined)),
        Value::Simple(32),
        Value::Bool(false),
        Value::Null,
        Value::Undefined,
        Value::Float(-0.0),
    ];
    for expected in values {
        let bytes = to_vec(&expected).unwrap();
        assert_eq!(from_slice::<Value>(&bytes).unwrap(), expected);
    }
}

#[test]
fn value_conversion_round_trips_structs_enums_and_large_integers() {
    let record = Record {
        name: "record".into(),
        bytes: vec![0, 1, 2].into(),
        wide: u64::MAX as u128 + 1,
        optional: Some(7),
    };
    let dynamic = value::to_value(&record).unwrap();
    assert_eq!(value::from_value::<Record>(dynamic).unwrap(), record);

    for choice in [
        Choice::Unit,
        Choice::Tuple(4, "four".into()),
        Choice::Struct { enabled: true },
    ] {
        let dynamic = value::to_value(&choice).unwrap();
        assert_eq!(value::from_value::<Choice>(dynamic).unwrap(), choice);
    }
}

#[test]
fn null_and_undefined_are_distinct_values_but_both_deserialize_as_none() {
    assert_ne!(Value::Null, Value::Undefined);
    assert_eq!(value::from_value::<Option<u8>>(Value::Null).unwrap(), None);
    assert_eq!(
        value::from_value::<Option<u8>>(Value::Undefined).unwrap(),
        None
    );
}

#[test]
fn from_value_preserves_cbor_extensions_for_value_and_typed_tags() {
    let dynamic = Value::Tag(100, Box::new(Value::Simple(32)));
    assert_eq!(
        value::from_value::<Value>(dynamic.clone()).unwrap(),
        dynamic
    );

    let tagged = value::from_value::<fcpw::Tagged<Record>>(
        value::to_value(&fcpw::Tagged::with_tag(
            100,
            Record {
                name: "tagged".into(),
                bytes: vec![1, 2, 3].into(),
                wide: 7,
                optional: None,
            },
        ))
        .unwrap(),
    )
    .unwrap();
    assert_eq!(tagged.tag, Some(100));
    assert_eq!(tagged.value.name, "tagged");
}