sp_ipld/
dag_cbor.rs

1use crate::{
2  codec::{
3    Codec,
4    Decode,
5    Encode,
6    UnsupportedCodec,
7  },
8  ipld::Ipld,
9};
10
11use sp_cid::Cid;
12use sp_multihash::{
13  Code,
14  MultihashDigest,
15};
16
17use core::convert::TryFrom;
18
19pub mod decode;
20pub mod encode;
21
22/// A struct representing the dag-cbor IPLD codec.
23#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
24pub struct DagCborCodec;
25
26impl Codec for DagCborCodec {}
27
28impl From<DagCborCodec> for u64 {
29  fn from(_: DagCborCodec) -> Self { 0x71 }
30}
31
32impl TryFrom<u64> for DagCborCodec {
33  type Error = UnsupportedCodec;
34
35  fn try_from(_: u64) -> core::result::Result<Self, Self::Error> { Ok(Self) }
36}
37
38/// A trait representing the capability to both decode and encode
39/// the type using the dag-cbor codec
40pub trait DagCbor: Encode<DagCborCodec> + Decode<DagCborCodec> {}
41
42impl<T: Encode<DagCborCodec> + Decode<DagCborCodec>> DagCbor for T {}
43
44/// Returns the corresponding dag-cbor v1 Cid
45/// to the passed IPLD
46/// # Panics
47/// Panics if x could not be encoded into a dag-cbor bytecursor
48pub fn cid(x: &Ipld) -> Cid {
49  Cid::new_v1(
50    0x71,
51    Code::Blake2b256
52      .digest(DagCborCodec.encode(x).unwrap().into_inner().as_ref()),
53  )
54}
55
56#[cfg(test)]
57pub mod tests {
58  use super::*;
59  use crate::ipld::*;
60  use bytecursor::ByteCursor;
61  use quickcheck::{
62    quickcheck,
63    Arbitrary,
64    Gen,
65  };
66
67  use alloc::collections::btree_map::BTreeMap;
68
69  fn encode_decode_id<T: DagCbor + PartialEq<T> + Clone>(value: T) -> bool {
70    let mut bc = ByteCursor::new(Vec::new());
71    match Encode::encode(&value, DagCborCodec, &mut bc) {
72      Ok(()) => {
73        bc.set_position(0);
74        match Decode::decode(DagCborCodec, &mut bc) {
75          Ok(new_value) => return value == new_value,
76          Err(e) => println!("Error occurred during decoding: {}", e),
77        }
78      }
79      Err(e) => println!("Error occurred during encoding: {}", e),
80    }
81    false
82  }
83
84  #[quickcheck]
85  pub fn edid_null() -> bool { encode_decode_id(Ipld::Null) }
86
87  #[quickcheck]
88  pub fn edid_bool(x: bool) -> bool { encode_decode_id(Ipld::Bool(x)) }
89
90  #[quickcheck]
91  pub fn edid_integer(x: i64) -> bool {
92    encode_decode_id(Ipld::Integer(x as i128))
93  }
94
95  #[quickcheck]
96  pub fn edid_bytes(x: Vec<u8>) -> bool { encode_decode_id(Ipld::Bytes(x)) }
97
98  #[quickcheck]
99  pub fn edid_string(x: String) -> bool { encode_decode_id(Ipld::String(x)) }
100
101  // fails on `Vec<Float(inf)>`
102  #[quickcheck]
103  pub fn edid_list(x: Vec<Ipld>) -> bool { encode_decode_id(Ipld::List(x)) }
104
105  #[quickcheck]
106  pub fn edid_string_map(x: BTreeMap<String, Ipld>) -> bool {
107    encode_decode_id(Ipld::StringMap(x))
108  }
109
110  #[derive(Debug, Clone)]
111  pub struct ACid(pub Cid);
112
113  impl Arbitrary for ACid {
114    fn arbitrary(g: &mut Gen) -> Self {
115      ACid(crate::ipld::tests::arbitrary_cid(g))
116    }
117  }
118
119  #[quickcheck]
120  pub fn edid_link(x: ACid) -> bool { encode_decode_id(Ipld::Link(x.0)) }
121}