#![allow(missing_docs)]
use std::collections::BTreeMap;
use wolfcose::{
from_slice, to_slice, to_vec, ByteBuf, ByteStr, CborDeserialize, CborDeserializer,
CborSerialize, CborSerializer, CborValue, Error,
};
#[derive(Debug, Eq, PartialEq)]
struct SensorReading {
id: u32,
label: String,
samples: Vec<i32>,
signature: ByteBuf,
}
impl CborSerialize for SensorReading {
fn serialize(&self, serializer: &mut CborSerializer<'_>) -> wolfcose::Result<()> {
serializer.map(4)?;
"id".serialize(serializer)?;
self.id.serialize(serializer)?;
"label".serialize(serializer)?;
self.label.serialize(serializer)?;
"samples".serialize(serializer)?;
self.samples.serialize(serializer)?;
"signature".serialize(serializer)?;
self.signature.serialize(serializer)?;
Ok(())
}
}
impl<'de> CborDeserialize<'de> for SensorReading {
fn deserialize(deserializer: &mut CborDeserializer<'de>) -> wolfcose::Result<Self> {
let len = deserializer.map()?;
let mut id = None;
let mut label = None;
let mut samples = None;
let mut signature = None;
for _ in 0..len {
match <&str>::deserialize(deserializer)? {
"id" => id = Some(u32::deserialize(deserializer)?),
"label" => label = Some(String::deserialize(deserializer)?),
"samples" => samples = Some(Vec::<i32>::deserialize(deserializer)?),
"signature" => signature = Some(ByteBuf::deserialize(deserializer)?),
_ => return Err(Error::CborType),
}
}
Ok(Self {
id: id.ok_or(Error::CborMalformed)?,
label: label.ok_or(Error::CborMalformed)?,
samples: samples.ok_or(Error::CborMalformed)?,
signature: signature.ok_or(Error::CborMalformed)?,
})
}
}
#[test]
fn serde_like_struct_round_trip() {
let reading = SensorReading {
id: 7,
label: "temp".to_owned(),
samples: vec![-1, 0, 1],
signature: ByteBuf(vec![0xaa, 0xbb, 0xcc]),
};
let encoded = to_vec(&reading).unwrap();
let decoded: SensorReading = from_slice(&encoded).unwrap();
assert_eq!(decoded, reading);
}
#[test]
fn to_slice_reports_small_buffer() {
let mut out = [0u8; 1];
assert_eq!(to_slice(&1000u64, &mut out), Err(Error::BufferTooSmall));
}
#[test]
fn primitives_options_tuples_and_maps_round_trip() {
let tuple = (true, Some(42u8), None::<u16>, "wolfCOSE".to_owned());
let encoded = to_vec(&tuple).unwrap();
let decoded: (bool, Option<u8>, Option<u16>, String) = from_slice(&encoded).unwrap();
assert_eq!(decoded, tuple);
let mut map = BTreeMap::new();
map.insert("a".to_owned(), 1u64);
map.insert("b".to_owned(), 2u64);
let decoded_map: BTreeMap<String, u64> = from_slice(&to_vec(&map).unwrap()).unwrap();
assert_eq!(decoded_map, map);
}
#[test]
fn byte_string_wrapper_round_trip() {
let encoded = to_vec(&ByteStr(b"raw bytes")).unwrap();
let borrowed: &[u8] = from_slice(&encoded).unwrap();
assert_eq!(borrowed, b"raw bytes");
let owned: ByteBuf = from_slice(&encoded).unwrap();
assert_eq!(owned, ByteBuf(b"raw bytes".to_vec()));
}
#[test]
fn dynamic_value_round_trip() {
let value = CborValue::Map(vec![
(
CborValue::Text("alg".to_owned()),
CborValue::Integer(wolfcose::Algorithm::ES256.id() as i64),
),
(
CborValue::Text("payload".to_owned()),
CborValue::Array(vec![
CborValue::Bool(true),
CborValue::Null,
CborValue::Bytes(vec![1, 2, 3]),
]),
),
]);
let encoded = to_vec(&value).unwrap();
let decoded: CborValue = from_slice(&encoded).unwrap();
assert_eq!(decoded, value);
}
#[test]
fn from_slice_rejects_trailing_data() {
let mut encoded = to_vec(&1u8).unwrap();
encoded.push(0);
assert_eq!(from_slice::<u8>(&encoded), Err(Error::CborMalformed));
}