1pub use crate::codec::{PbLink, PbNode};
3use core::convert::TryInto;
4use libipld_base::cid;
5use libipld_base::codec::Codec;
6use libipld_base::error::{BlockError, IpldError};
7use libipld_base::ipld::Ipld;
8use thiserror::Error;
9
10mod codec;
11
12#[derive(Clone, Debug, Hash, PartialEq, Eq)]
14pub struct DagPbCodec;
15
16impl Codec for DagPbCodec {
17 const VERSION: cid::Version = cid::Version::V0;
18 const CODEC: cid::Codec = cid::Codec::DagProtobuf;
19
20 type Error = ProtobufError;
21
22 fn encode(ipld: &Ipld) -> Result<Box<[u8]>, Self::Error> {
23 let pb_node: PbNode = ipld.try_into()?;
24 Ok(pb_node.into_bytes())
25 }
26
27 fn decode(data: &[u8]) -> Result<Ipld, Self::Error> {
28 Ok(PbNode::from_bytes(data)?.into())
29 }
30}
31
32#[derive(Debug, Error)]
34pub enum ProtobufError {
35 #[error("{0}")]
36 Prost(#[from] prost::DecodeError),
37 #[error("{0}")]
38 Cid(#[from] cid::Error),
39 #[error("{0}")]
40 Ipld(#[from] IpldError),
41}
42
43impl From<ProtobufError> for BlockError {
44 fn from(error: ProtobufError) -> Self {
45 Self::CodecError(error.into())
46 }
47}
48
49#[cfg(test)]
50mod tests {
51 use super::*;
52 use libipld_base::cid::Cid;
53 use multihash::Sha2_256;
54 use std::collections::BTreeMap;
55
56 #[test]
57 fn test_encode_decode() {
58 let cid = Cid::new_v0(Sha2_256::digest(b"cid")).unwrap();
59 let mut pb_link = BTreeMap::<String, Ipld>::new();
60 pb_link.insert("Hash".to_string(), cid.into());
61 pb_link.insert("Name".to_string(), "block".to_string().into());
62 pb_link.insert("Tsize".to_string(), 13.into());
63
64 let links: Vec<Ipld> = vec![pb_link.into()];
65 let mut pb_node = BTreeMap::<String, Ipld>::new();
66 pb_node.insert("Data".to_string(), b"Here is some data\n".to_vec().into());
67 pb_node.insert("Links".to_string(), links.into());
68 let data: Ipld = pb_node.into();
69
70 let bytes = DagPbCodec::encode(&data).unwrap();
71 let data2 = DagPbCodec::decode(&bytes).unwrap();
72 assert_eq!(data, data2);
73 }
74}