1use std::io::Read;
10use std::sync::Arc;
11
12use ciborium::de::Error as DeserializeError;
13use ciborium::ser::Error as SerializeError;
14use serde::{Deserialize, Serialize};
15use thiserror::Error;
16
17pub fn encode_cbor<T: Serialize>(value: &T) -> Result<Vec<u8>, EncodeError> {
19 let mut bytes = Vec::new();
20 ciborium::ser::into_writer(value, &mut bytes).map_err(Into::<EncodeError>::into)?;
21 Ok(bytes)
22}
23
24pub fn decode_cbor<T: for<'a> Deserialize<'a>, R: Read>(reader: R) -> Result<T, DecodeError> {
26 let value = ciborium::from_reader::<T, R>(reader).map_err(Into::<DecodeError>::into)?;
27 Ok(value)
28}
29
30#[derive(Debug, Error)]
32pub enum EncodeError {
33 #[error("an error occurred while reading bytes: {0}")]
37 Io(std::io::Error),
38
39 #[error("an error occurred while deserializing value: {0}")]
43 Value(String),
44}
45
46impl From<SerializeError<std::io::Error>> for EncodeError {
47 fn from(value: SerializeError<std::io::Error>) -> Self {
48 match value {
49 SerializeError::Io(err) => EncodeError::Io(err),
50 SerializeError::Value(err) => EncodeError::Value(err),
51 }
52 }
53}
54
55#[derive(Clone, Debug, Error)]
57pub enum DecodeError {
58 #[error("an error occurred while reading bytes: {0}")]
62 Io(Arc<std::io::Error>),
63
64 #[error("an error occurred while parsing bytes at position {0}")]
68 Syntax(usize),
69
70 #[error("an error occurred while processing a parsed value at position {0:?}: {1}")]
75 Semantic(Option<usize>, String),
76
77 #[error("recursion limit exceeded while decoding")]
81 RecursionLimitExceeded,
82}
83
84impl From<DeserializeError<std::io::Error>> for DecodeError {
85 fn from(value: DeserializeError<std::io::Error>) -> Self {
86 match value {
87 DeserializeError::Io(err) => DecodeError::Io(Arc::new(err)),
88 DeserializeError::Syntax(offset) => DecodeError::Syntax(offset),
89 DeserializeError::Semantic(offset, description) => {
90 DecodeError::Semantic(offset, description)
91 }
92 DeserializeError::RecursionLimitExceeded => DecodeError::RecursionLimitExceeded,
93 }
94 }
95}
96
97#[cfg(test)]
98mod tests {
99 use crate::{Body, Header, SigningKey};
100
101 use super::{DecodeError, decode_cbor, encode_cbor};
102
103 #[test]
104 fn encode_decode() {
105 let signing_key = SigningKey::generate();
106 let body = Body::new(&[1, 2, 3]);
107 let mut header = Header::<()> {
108 verifying_key: signing_key.verifying_key(),
109 payload_size: body.size(),
110 payload_hash: Some(body.hash()),
111 ..Default::default()
112 };
113 header.sign(&signing_key);
114
115 let bytes = encode_cbor(&header).unwrap();
116 let header_again: Header<()> = decode_cbor(&bytes[..]).unwrap();
117
118 assert_eq!(header.hash(), header_again.hash());
119 }
120
121 #[test]
122 fn decode_eof() {
123 let bytes = hex::decode("828901582014d59877a250").unwrap();
125 let err = decode_cbor::<(Header<()>, Option<Body>), _>(&bytes[..]);
126
127 assert!(matches!(err, Err(DecodeError::Io(_))));
130 }
131}