use std::io::Read;
use std::sync::Arc;
use cbor_core::DecodeOptions;
use serde::{Deserialize, Serialize};
use thiserror::Error;
pub fn encode_cbor<T: Serialize>(value: &T) -> Result<Vec<u8>, EncodeError> {
let value = cbor_core::Value::serialized(&value)?;
Ok(value.encode())
}
pub fn decode_cbor<T: for<'a> Deserialize<'a>, R: Read>(reader: R) -> Result<T, DecodeError> {
let value = DecodeOptions::default()
.strictness(cbor_core::Strictness::LENIENT)
.read_from(reader)
.map_err(|err| DecodeError::Io(Arc::new(err)))?;
Ok(cbor_core::Value::deserialized(&value)?)
}
pub fn decode_cbor_strict<T: for<'a> Deserialize<'a>, R: Read>(
reader: R,
) -> Result<T, DecodeError> {
let value =
cbor_core::Value::read_from(reader).map_err(|err| DecodeError::Io(Arc::new(err)))?;
Ok(cbor_core::Value::deserialized(&value)?)
}
#[derive(Debug, Error)]
#[error(transparent)]
pub struct EncodeError(#[from] cbor_core::SerdeError);
#[derive(Clone, Debug, Error)]
pub enum DecodeError {
#[error("an error occurred while reading bytes: {0}")]
Io(Arc<cbor_core::IoError>),
#[error(transparent)]
Serde(#[from] cbor_core::SerdeError),
}
#[cfg(test)]
mod tests {
use cbor_core::{Value, array, map};
use super::{decode_cbor, decode_cbor_strict};
#[test]
fn lenient_cbor_decoding() {
let value = map! {
2 => array![10, 20, 30],
1 => "hello",
};
let hex = value.encode_hex();
let non_canonical_hex = "a202830a14181e016568656c6c6f".to_string();
assert!(hex != non_canonical_hex, "hex encodings are not the same");
let non_canonical_bytes = hex::decode(non_canonical_hex).unwrap();
assert!(
Value::decode_hex(hex).is_ok(),
"decoding canonical encoding is valid"
);
assert!(
decode_cbor_strict::<Value, _>(&non_canonical_bytes[..]).is_err(),
"decoding non-canonical fails by default"
);
assert!(
decode_cbor::<Value, _>(&non_canonical_bytes[..]).is_ok(),
"decoding non-canonical doesn't fail when using decode_cbor fn"
);
}
}