sp_ipld/
lib.rs

1#![feature(map_first_last)]
2#![deny(
3  clippy::missing_errors_doc,
4  clippy::missing_panics_doc,
5  clippy::missing_safety_doc
6)]
7#![cfg_attr(not(any(feature = "std", test)), no_std)]
8
9#[macro_use]
10extern crate alloc;
11
12#[cfg(test)]
13extern crate quickcheck;
14#[cfg(test)]
15#[macro_use(quickcheck)]
16extern crate quickcheck_macros;
17#[cfg(test)]
18extern crate rand;
19
20pub mod codec;
21#[cfg(feature = "dag-cbor")]
22pub mod dag_cbor;
23#[cfg(feature = "dag-json")]
24pub mod dag_json;
25pub mod ipld;
26
27pub use codec::*;
28pub use ipld::*;
29
30#[cfg(test)]
31pub mod tests {
32  use super::*;
33  #[cfg(feature = "dag-cbor")]
34  use super::{
35    dag_cbor,
36    dag_cbor::DagCborCodec,
37  };
38  use bytecursor::ByteCursor;
39  use quickcheck::quickcheck;
40  use reqwest::multipart;
41  use tokio::runtime::Runtime;
42
43  #[cfg(feature = "dag-cbor")]
44  async fn dag_put_cbor(dag: Ipld) -> Result<String, reqwest::Error> {
45    let host = "http://127.0.0.1:5001";
46    let url = format!(
47      "{}{}?{}",
48      host,
49      "/api/v0/dag/put",
50      "format=dag-cbor&pin=true&input-enc=cbor&hash=blake2b-256"
51    );
52    let cbor = DagCborCodec.encode(&dag).unwrap().into_inner();
53    let client = reqwest::Client::new();
54    let form =
55      multipart::Form::new().part("file", multipart::Part::bytes(cbor));
56    let response: serde_json::Value =
57      client.post(url).multipart(form).send().await?.json().await?;
58    println!("PUT response: {:?}", response);
59
60    let ipfs_cid: String = response["Cid"]["/"].as_str().unwrap().to_string();
61    let local_cid: String = dag_cbor::cid(&dag).to_string();
62
63    if ipfs_cid == local_cid {
64      Ok(ipfs_cid)
65    }
66    else {
67      panic!("CIDs are different {} != {}", ipfs_cid, local_cid);
68    }
69  }
70
71  // #[cfg(feature = "dag-json")]
72  // pub async fn dag_put_json(dag: Ipld) -> Result<String, reqwest::Error> {
73  // let host = "http://127.0.0.1:5001";
74  // let url = format!(
75  // "{}{}?{}",
76  // host,
77  // "/api/v0/dag/put",
78  // "format=dag-cbor&pin=true&input-enc=json&hash=blake2b-256"
79  // );
80  // let cbor = DagJsonCodec.encode(&dag).unwrap().into_inner();
81  // let client = reqwest::Client::new();
82  // let form =
83  // multipart::Form::new().part("file", multipart::Part::bytes(cbor));
84  // let response: serde_json::Value =
85  // client.post(url).multipart(form).send().await?.json().await?;
86  // println!("response: {:?}", response);
87  //
88  // let ipfs_cid = response["Cid"]["/"].as_str().unwrap().to_string();
89  //
90  // assert_eq!(ipfs_cid, dag_cbor::cid(&dag).to_string());
91  //
92  // Ok(ipfs_cid)
93  // }
94
95  #[cfg(feature = "dag-cbor")]
96  async fn dag_get_cbor(cid: String) -> Result<Ipld, reqwest::Error> {
97    let host = "http://127.0.0.1:5001";
98    let url =
99      format!("{}{}?arg={}", host, "/api/v0/block/get", cid.to_string());
100    let client = reqwest::Client::new();
101    let response = client.post(url).send().await?.bytes().await?;
102    let response = response.to_vec();
103    println!("GET response: {:?}", response);
104    let ipld = DagCborCodec
105      .decode(ByteCursor::new(response))
106      .expect("invalid ipld cbor.");
107    println!("ipld: {:?}", ipld);
108
109    Ok(ipld)
110  }
111
112  // "input-enc=json" coerces numbers to floats and does not obey the ipld data
113  // model
114  // #[cfg(feature = "dag-json")]
115  // pub async fn dag_get_json(cid: String) -> Result<Ipld, reqwest::Error> {
116  // let host = "http://127.0.0.1:5001";
117  // let url =
118  // format!("{}{}?arg={}", host, "/api/v0/dag/get", cid.to_string());
119  // let client = reqwest::Client::new();
120  // let response = client.post(url).send().await?.bytes().await?;
121  // let response = response.to_vec();
122  // println!("response: {:?}", response);
123  // let ipld = DagJsonCodec
124  // .decode(ByteCursor::new(response))
125  // .expect("invalid ipld json.");
126  // println!("ipld: {:?}", ipld);
127  //
128  // Ok(ipld)
129  // }
130
131  #[cfg(feature = "dag-cbor")]
132  async fn async_ipld_ipfs_cbor(ipld: Ipld) -> bool {
133    match dag_put_cbor(ipld.clone()).await {
134      Ok(cid) => match dag_get_cbor(cid.clone()).await {
135        Ok(new_ipld) => {
136          if ipld.clone() == new_ipld {
137            true
138          }
139          else {
140            println!("Cid: {}", cid);
141            println!("Encoded ipld: {:?}", ipld);
142            println!("Decoded ipld: {:?}", new_ipld);
143            false
144          }
145        }
146        Err(e) => {
147          println!("Error during `dag_get`: {}", e);
148          false
149        }
150      },
151      Err(e) => {
152        println!("Error during `dag_put`: {}", e);
153        false
154      }
155    }
156  }
157
158  // "input-enc=json" coerces numbers to floats and does not obey the ipld data
159  // model
160  // #[cfg(feature = "dag-json")]
161  // async fn async_ipld_ipfs_json(ipld: Ipld) -> bool {
162  // match dag_put_json(ipld.clone()).await {
163  // Ok(cid) => match dag_get_json(cid.clone()).await {
164  // Ok(new_ipld) => {
165  // if ipld.clone() == new_ipld {
166  // true
167  // }
168  // else {
169  // println!("Cid: {}", cid);
170  // println!("Encoded ipld: {:?}", ipld);
171  // println!("Decoded ipld: {:?}", new_ipld);
172  // false
173  // }
174  // }
175  // Err(e) => {
176  // println!("Error during `dag_get`: {}", e);
177  // false
178  // }
179  // },
180  // Err(e) => {
181  // println!("Error during `dag_put`: {}", e);
182  // false
183  // }
184  // }
185  // }
186
187  #[cfg(feature = "dag-cbor")]
188  fn ipld_ipfs_cbor(ipld: Ipld) -> bool {
189    match Runtime::new() {
190      Ok(runtime) => runtime.block_on(async_ipld_ipfs_cbor(ipld)),
191      Err(e) => {
192        println!("Error creating runtime: {}", e);
193        false
194      }
195    }
196  }
197
198  // "input-enc=json" coerces numbers to floats and does not obey the ipld data
199  // model
200  // #[cfg(feature = "dag-json")]
201  // fn ipld_ipfs_json(ipld: Ipld) -> bool {
202  // match Runtime::new() {
203  // Ok(runtime) => runtime.block_on(async_ipld_ipfs_json(ipld)),
204  // Err(e) => {
205  // println!("Error creating runtime: {}", e);
206  // false
207  // }
208  // }
209  // }
210
211  #[cfg(feature = "dag-cbor")]
212  #[ignore]
213  #[quickcheck]
214  fn null_ipfs_cbor() -> bool { ipld_ipfs_cbor(Ipld::Null) }
215
216  // "input-enc=json" coerces numbers to floats and does not obey the ipld data
217  // model
218  // #[cfg(feature = "dag-json")]
219  // #[ignore]
220  // #[quickcheck]
221  // fn null_ipfs_json() -> bool { ipld_ipfs_json(Ipld::Null) }
222
223  #[cfg(feature = "dag-cbor")]
224  #[ignore]
225  #[quickcheck]
226  fn bool_ipfs_cbor(b: bool) -> bool { ipld_ipfs_cbor(Ipld::Bool(b)) }
227
228  // "input-enc=json" coerces numbers to floats and does not obey the ipld data
229  // model
230  // #[cfg(feature = "dag-json")]
231  // #[ignore]
232  // #[quickcheck]
233  // fn bool_ipfs_json(b: bool) -> bool { ipld_ipfs_json(Ipld::Bool(b)) }
234
235  #[cfg(feature = "dag-cbor")]
236  #[ignore]
237  #[quickcheck]
238  fn string_ipfs_cbor(x: String) -> bool { ipld_ipfs_cbor(Ipld::String(x)) }
239
240  // "input-enc=json" coerces numbers to floats and does not obey the ipld data
241  // model
242  // #[cfg(feature = "dag-json")]
243  // #[ignore]
244  // #[quickcheck]
245  // fn string_ipfs_json(x: String) -> bool { ipld_ipfs_json(Ipld::String(x)) }
246
247  #[cfg(feature = "dag-cbor")]
248  #[ignore]
249  #[test]
250  fn integers_ipfs_cbor() {
251    assert!(ipld_ipfs_cbor(Ipld::Integer(0i128)));
252    assert!(ipld_ipfs_cbor(Ipld::Integer(1i128)));
253    assert!(ipld_ipfs_cbor(Ipld::Integer(i128::from(i64::MAX))));
254    assert!(ipld_ipfs_cbor(Ipld::Integer(i128::from(i64::MIN))));
255  }
256
257  // "input-enc=json" coerces numbers to floats and does not obey the ipld data
258  // model, so this test fails
259  // #[cfg(feature = "dag-json")]
260  // #[ignore]
261  // #[test]
262  // fn integers_ipfs_json() {
263  // assert!(ipld_ipfs_json(Ipld::Integer(0i128)));
264  // assert!(ipld_ipfs_json(Ipld::Integer(1i128)));
265  // assert!(ipld_ipfs_json(Ipld::Integer(i128::from(i64::MAX))));
266  // assert!(ipld_ipfs_json(Ipld::Integer(i128::from(i64::MIN))));
267  // }
268
269  #[cfg(feature = "dag-cbor")]
270  #[ignore]
271  #[quickcheck]
272  fn integer_ipfs_cbor(x: i64) -> bool {
273    ipld_ipfs_cbor(Ipld::Integer(i128::from(x)))
274  }
275
276  // "input-enc=json" coerces numbers to floats and does not obey the ipld data
277  // model, so this test fails
278  // #[cfg(feature = "dag-json")]
279  // #[ignore]
280  // #[quickcheck]
281  // fn integer_ipfs_json(x: i64) -> bool {
282  // ipld_ipfs_json(Ipld::Integer(i128::from(x))) }
283
284  #[cfg(feature = "dag-cbor")]
285  #[ignore]
286  #[quickcheck]
287  fn ipfs_cbor(x: Ipld) -> bool { ipld_ipfs_cbor(x) }
288
289  // "input-enc=json" coerces numbers to floats and does not obey the ipld data
290  // model, so this test fails
291  // #[cfg(feature = "dag-json")]
292  // #[ignore]
293  // #[quickcheck]
294  // fn ipfs_json(x: Ipld) -> bool { ipld_ipfs_json(x) }
295}