sp_ipld/
dag_json.rs

1use crate::{
2  codec::*,
3  Ipld,
4  References,
5};
6use alloc::string::{
7  String,
8  ToString,
9};
10use bytecursor::ByteCursor;
11use core::convert::TryFrom;
12use sp_cid::Cid;
13use sp_multihash::{
14  Code,
15  MultihashDigest,
16};
17
18mod codec;
19
20#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
21pub struct DagJsonCodec;
22
23impl Codec for DagJsonCodec {}
24
25impl From<DagJsonCodec> for u64 {
26  fn from(_: DagJsonCodec) -> Self { 0x0129 }
27}
28
29impl TryFrom<u64> for DagJsonCodec {
30  type Error = UnsupportedCodec;
31
32  fn try_from(_: u64) -> core::result::Result<Self, Self::Error> { Ok(Self) }
33}
34
35impl Encode<DagJsonCodec> for Ipld {
36  fn encode(&self, _: DagJsonCodec, w: &mut ByteCursor) -> Result<(), String> {
37    codec::encode(self, w).map_err(|x| x.to_string())
38  }
39}
40
41impl Decode<DagJsonCodec> for Ipld {
42  fn decode(_: DagJsonCodec, r: &mut ByteCursor) -> Result<Self, String> {
43    codec::decode(r).map_err(|e| e.to_string())
44  }
45}
46
47impl References<DagJsonCodec> for Ipld {
48  fn references<E: Extend<Cid>>(
49    c: DagJsonCodec,
50    r: &mut ByteCursor,
51    set: &mut E,
52  ) -> Result<(), String> {
53    Ipld::decode(c, r)?.references(set);
54    Ok(())
55  }
56}
57
58/// Returns the corresponding dag-json v1 Cid
59/// to the passed IPLD
60/// # Panics
61/// Panics if dag could not be encoded into a
62/// dag-json bytecursor.
63pub fn cid(dag: &Ipld) -> Cid {
64  Cid::new_v1(
65    0x0129,
66    Code::Blake2b256
67      .digest(DagJsonCodec.encode(dag).unwrap().into_inner().as_ref()),
68  )
69}
70
71/// This function takes a String representation of a dag JSON
72/// data structure and returns the corresponding IPLD structure.
73/// # Errors
74/// Will return `Err` if `s` is not valid dag JSON, with a description
75/// of the error.
76pub fn from_dag_json_string(s: String) -> Result<Ipld, String> {
77  let mut r = ByteCursor::new(s.into_bytes());
78  codec::decode(&mut r).map_err(|e| e.to_string())
79}
80
81/// This function takes an IPLD structure and returns the corresponding
82/// JSON serialized into a String.
83/// # Errors
84/// Will return `Err` if there was an error converting the IPLD to JSON.
85pub fn to_dag_json_string(ipld: Ipld) -> Result<String, String> {
86  let mut w = ByteCursor::new(vec![]);
87  codec::encode(&ipld, &mut w).map_err(|e| e.to_string())?;
88  Ok(String::from(String::from_utf8_lossy(&w.into_inner())))
89}
90
91#[cfg(test)]
92pub mod tests {
93  use super::*;
94  use crate::ipld::*;
95  use bytecursor::ByteCursor;
96  use quickcheck::{
97    quickcheck,
98    Arbitrary,
99    Gen,
100  };
101
102  use alloc::collections::btree_map::BTreeMap;
103
104  fn encode_decode_id<
105    T: Encode<DagJsonCodec> + Decode<DagJsonCodec> + PartialEq<T> + Clone,
106  >(
107    value: T,
108  ) -> bool {
109    let mut bc = ByteCursor::new(Vec::new());
110    match Encode::encode(&value, DagJsonCodec, &mut bc) {
111      Ok(()) => {
112        bc.set_position(0);
113        match Decode::decode(DagJsonCodec, &mut bc) {
114          Ok(new_value) => return value == new_value,
115          Err(e) => println!("Error occurred during decoding: {}", e),
116        }
117      }
118      Err(e) => println!("Error occurred during encoding: {}", e),
119    }
120    false
121  }
122
123  #[quickcheck]
124  pub fn edid_null() -> bool { encode_decode_id(Ipld::Null) }
125
126  #[quickcheck]
127  pub fn edid_bool(x: bool) -> bool { encode_decode_id(Ipld::Bool(x)) }
128
129  #[quickcheck]
130  pub fn edid_integer(x: i64) -> bool {
131    encode_decode_id(Ipld::Integer(x as i128))
132  }
133
134  #[quickcheck]
135  pub fn edid_bytes(x: Vec<u8>) -> bool { encode_decode_id(Ipld::Bytes(x)) }
136
137  #[quickcheck]
138  pub fn edid_string(x: String) -> bool { encode_decode_id(Ipld::String(x)) }
139
140  // fails on `Vec<Float(inf)>`
141  #[quickcheck]
142  pub fn edid_list(x: Vec<Ipld>) -> bool { encode_decode_id(Ipld::List(x)) }
143
144  #[quickcheck]
145  pub fn edid_string_map(x: BTreeMap<String, Ipld>) -> bool {
146    encode_decode_id(Ipld::StringMap(x))
147  }
148
149  #[derive(Debug, Clone)]
150  pub struct ACid(pub Cid);
151
152  impl Arbitrary for ACid {
153    fn arbitrary(g: &mut Gen) -> Self {
154      ACid(crate::ipld::tests::arbitrary_cid(g))
155    }
156  }
157
158  #[quickcheck]
159  pub fn edid_link(x: ACid) -> bool { encode_decode_id(Ipld::Link(x.0)) }
160}