cbor2 1.0.5

Full-featured CBOR (RFC 8949) for serde: async item I/O, canonical encoding, no_std, Value/RawValue, tags, COSE keys, validation and diagnostics.
Documentation
use serde::{Deserialize, Serialize};

#[derive(Debug, PartialEq, Deserialize, Serialize)]
struct Packet {
    #[serde(with = "serde_bytes")]
    payload: Vec<u8>,
}

#[derive(Debug, PartialEq, Deserialize)]
struct Borrowed<'a> {
    #[serde(borrow)]
    name: &'a str,
    #[serde(borrow, with = "serde_bytes")]
    body: &'a [u8],
}

#[derive(Debug, PartialEq, Deserialize, Serialize)]
struct Signed {
    #[serde(with = "serde_bytes")]
    signature: Vec<u8>,
    payload: cbor2::RawValue,
}

fn exact_item() -> Result<(), Box<dyn std::error::Error>> {
    let bytes = cbor2::to_vec(&("ok", 7u8))?;
    cbor2::validate(&bytes[..])?;

    let decoded: (String, u8) = cbor2::from_slice(&bytes)?;
    assert_eq!(decoded, ("ok".to_string(), 7));

    let mut with_trailing = bytes.clone();
    with_trailing.push(0);
    assert!(cbor2::validate(&with_trailing[..]).is_err());

    let leading: (String, u8) = cbor2::from_slice(&with_trailing)?;
    assert_eq!(leading, decoded);
    Ok(())
}

fn byte_strings() -> Result<(), Box<dyn std::error::Error>> {
    let raw = vec![1u8, 2, 3, 4];
    assert_eq!(hex::encode(cbor2::to_vec(&raw)?), "8401020304");

    let packet = Packet {
        payload: raw.clone(),
    };
    assert_eq!(
        hex::encode(cbor2::to_vec(&packet)?),
        "a1677061796c6f61644401020304"
    );

    let borrowed = serde_bytes::Bytes::new(&raw);
    assert_eq!(hex::encode(cbor2::to_vec(&borrowed)?), "4401020304");
    Ok(())
}

fn borrowed_from_slice() -> Result<(), Box<dyn std::error::Error>> {
    let bytes = hex::decode("a2646e616d656361706964626f647942cafe")?;
    let value: Borrowed<'_> = cbor2::from_slice(&bytes)?;
    assert_eq!(value.name, "api");
    assert_eq!(value.body, &[0xca, 0xfe]);
    Ok(())
}

fn raw_value_for_signatures() -> Result<(), Box<dyn std::error::Error>> {
    let signed = Signed {
        signature: vec![0xde, 0xad],
        payload: cbor2::RawValue::serialized(&("keep", 1u8))?,
    };

    let bytes = cbor2::to_vec(&signed)?;
    let decoded: Signed = cbor2::from_slice(&bytes)?;
    assert_eq!(decoded.signature, signed.signature);
    assert_eq!(decoded.payload.as_bytes(), signed.payload.as_bytes());

    let payload: (String, u8) = decoded.payload.deserialized()?;
    assert_eq!(payload, ("keep".to_string(), 1));
    Ok(())
}

fn cbor_sequence() -> Result<(), Box<dyn std::error::Error>> {
    let mut stream = Vec::new();
    cbor2::to_writer(&"start", &mut stream)?;
    cbor2::to_writer(&42u8, &mut stream)?;

    let items: Vec<cbor2::Value> = cbor2::de::Deserializer::from_reader(&stream[..])
        .into_iter()
        .collect::<Result<_, _>>()?;

    assert_eq!(
        items,
        vec![cbor2::Value::from("start"), cbor2::Value::from(42)]
    );
    assert!(cbor2::validate(&stream[..]).is_err());
    Ok(())
}

fn canonical_bytes() -> Result<(), Box<dyn std::error::Error>> {
    let map: std::collections::HashMap<&str, u8> = [("z", 1), ("aa", 2), ("b", 3)].into();
    let first = cbor2::to_canonical_vec(&map)?;
    let second = cbor2::to_canonical_vec(&map)?;
    assert_eq!(first, second);
    assert_eq!(hex::encode(&first), "a3616203617a0162616102");
    Ok(())
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    exact_item()?;
    byte_strings()?;
    borrowed_from_slice()?;
    raw_value_for_signatures()?;
    cbor_sequence()?;
    canonical_bytes()?;

    println!("agent patterns ok");
    Ok(())
}