1pub mod codec;
2pub mod convert;
3
4pub mod serde;
5
6mod macros;
7
8#[doc(hidden)]
12pub mod __private_do_not_use {
13 pub use alloc::{collections::BTreeMap, vec};
14}
15
16use {
17 crate::cid::Cid,
18 ::alloc::{
19 borrow::ToOwned,
20 boxed::Box,
21 collections::BTreeMap,
22 string::{String, ToString},
23 vec::Vec,
24 *,
25 },
26 core::fmt,
27};
28
29#[derive(Clone, Debug)]
31#[non_exhaustive]
32pub enum IndexError {
33 ParseInteger(String),
35 WrongKind(IpldKind),
37}
38
39impl fmt::Display for IndexError {
40 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
41 match self {
42 Self::ParseInteger(key) => {
43 write!(f, "cannot parse key into integer: {}", key)
44 }
45 Self::WrongKind(kind) => {
46 write!(f, "expected IPLD List or Map but found: {:?}", kind)
47 }
48 }
49 }
50}
51
52#[derive(Clone)]
54pub enum Ipld {
55 Null,
57 Bool(bool),
59 Integer(i128),
61 Float(f64),
63 String(String),
65 Bytes(Vec<u8>),
67 List(Vec<Ipld>),
69 Map(BTreeMap<String, Ipld>),
71 Link(Cid),
73}
74
75impl fmt::Debug for Ipld {
76 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
77 if f.alternate() {
78 match self {
79 Self::Null => write!(f, "Null"),
80 Self::Bool(b) => write!(f, "Bool({:?})", b),
81 Self::Integer(i) => write!(f, "Integer({:?})", i),
82 Self::Float(i) => write!(f, "Float({:?})", i),
83 Self::String(s) => write!(f, "String({:?})", s),
84 Self::Bytes(b) => write!(f, "Bytes({:?})", b),
85 Self::List(l) => write!(f, "List({:#?})", l),
86 Self::Map(m) => write!(f, "Map({:#?})", m),
87 Self::Link(cid) => write!(f, "Link({})", cid),
88 }
89 } else {
90 match self {
91 Self::Null => write!(f, "null"),
92 Self::Bool(b) => write!(f, "{:?}", b),
93 Self::Integer(i) => write!(f, "{:?}", i),
94 Self::Float(i) => write!(f, "{:?}", i),
95 Self::String(s) => write!(f, "{:?}", s),
96 Self::Bytes(b) => write!(f, "{:?}", b),
97 Self::List(l) => write!(f, "{:?}", l),
98 Self::Map(m) => write!(f, "{:?}", m),
99 Self::Link(cid) => write!(f, "{}", cid),
100 }
101 }
102 }
103}
104
105impl PartialEq for Ipld {
109 fn eq(&self, other: &Self) -> bool {
110 match (self, other) {
111 (Self::Null, Self::Null) => true,
112 (Self::Bool(self_value), Self::Bool(other_value)) => {
113 self_value == other_value
114 }
115 (Self::Integer(self_value), Self::Integer(other_value)) => {
116 self_value == other_value
117 }
118 (Self::Float(self_value), Self::Float(other_value)) => {
119 self_value == other_value || self_value.is_nan() && other_value.is_nan()
121 }
122 (Self::String(self_value), Self::String(other_value)) => {
123 self_value == other_value
124 }
125 (Self::Bytes(self_value), Self::Bytes(other_value)) => {
126 self_value == other_value
127 }
128 (Self::List(self_value), Self::List(other_value)) => {
129 self_value == other_value
130 }
131 (Self::Map(self_value), Self::Map(other_value)) => {
132 self_value == other_value
133 }
134 (Self::Link(self_value), Self::Link(other_value)) => {
135 self_value == other_value
136 }
137 _ => false,
138 }
139 }
140}
141
142impl Eq for Ipld {}
143
144#[derive(Clone, Debug)]
149pub enum IpldKind {
150 Null,
152 Bool,
154 Integer,
156 Float,
158 String,
160 Bytes,
162 List,
164 Map,
166 Link,
168}
169
170pub enum IpldIndex<'a> {
174 List(usize),
176 Map(String),
178 MapRef(&'a str),
180}
181
182impl<'a> From<usize> for IpldIndex<'a> {
183 fn from(index: usize) -> Self {
184 Self::List(index)
185 }
186}
187
188impl<'a> From<String> for IpldIndex<'a> {
189 fn from(key: String) -> Self {
190 Self::Map(key)
191 }
192}
193
194impl<'a> From<&'a str> for IpldIndex<'a> {
195 fn from(key: &'a str) -> Self {
196 Self::MapRef(key)
197 }
198}
199
200impl<'a> TryFrom<IpldIndex<'a>> for usize {
201 type Error = IndexError;
202
203 fn try_from(index: IpldIndex<'a>) -> Result<Self, Self::Error> {
204 let parsed = match index {
205 IpldIndex::List(i) => i,
206 IpldIndex::Map(ref key) => key
207 .parse()
208 .map_err(|_| IndexError::ParseInteger(key.to_string()))?,
209 IpldIndex::MapRef(key) => key
210 .parse()
211 .map_err(|_| IndexError::ParseInteger(key.to_string()))?,
212 };
213 Ok(parsed)
214 }
215}
216
217impl<'a> From<IpldIndex<'a>> for String {
218 fn from(index: IpldIndex<'a>) -> Self {
219 match index {
220 IpldIndex::Map(ref key) => key.to_string(),
221 IpldIndex::MapRef(key) => key.to_string(),
222 IpldIndex::List(i) => i.to_string(),
223 }
224 }
225}
226
227impl Ipld {
228 pub fn kind(&self) -> IpldKind {
234 match self {
235 Ipld::Null => IpldKind::Null,
236 Ipld::Bool(_) => IpldKind::Bool,
237 Ipld::Integer(_) => IpldKind::Integer,
238 Ipld::Float(_) => IpldKind::Float,
239 Ipld::String(_) => IpldKind::String,
240 Ipld::Bytes(_) => IpldKind::Bytes,
241 Ipld::List(_) => IpldKind::List,
242 Ipld::Map(_) => IpldKind::Map,
243 Ipld::Link(_) => IpldKind::Link,
244 }
245 }
246
247 pub fn take<'a, T: Into<IpldIndex<'a>>>(
249 mut self,
250 index: T,
251 ) -> Result<Option<Self>, IndexError> {
252 let index = index.into();
253 match &mut self {
254 Ipld::List(ref mut list) => {
255 let parsed_index = usize::try_from(index)?;
256 if parsed_index < list.len() {
257 Ok(Some(list.swap_remove(parsed_index)))
258 } else {
259 Ok(None)
260 }
261 }
262 Ipld::Map(ref mut map) => {
263 let key = String::from(index);
264 Ok(map.remove(&key))
265 }
266 other => Err(IndexError::WrongKind(other.kind())),
267 }
268 }
269
270 pub fn get<'a, T: Into<IpldIndex<'a>>>(
272 &self,
273 index: T,
274 ) -> Result<Option<&Self>, IndexError> {
275 let index = index.into();
276 match self {
277 Ipld::List(list) => {
278 let parsed_index = usize::try_from(index)?;
279 Ok(list.get(parsed_index))
280 }
281 Ipld::Map(map) => {
282 let key = String::from(index);
283 Ok(map.get(&key))
284 }
285 other => Err(IndexError::WrongKind(other.kind())),
286 }
287 }
288
289 pub fn iter(&self) -> IpldIter<'_> {
291 IpldIter {
292 stack: vec![Box::new(vec![self].into_iter())],
293 }
294 }
295
296 pub fn references<E: Extend<Cid>>(&self, set: &mut E) {
298 for ipld in self.iter() {
299 if let Ipld::Link(cid) = ipld {
300 set.extend(core::iter::once(cid.to_owned()));
301 }
302 }
303 }
304}
305
306pub struct IpldIter<'a> {
308 stack: Vec<Box<dyn Iterator<Item = &'a Ipld> + 'a>>,
309}
310
311impl<'a> Iterator for IpldIter<'a> {
312 type Item = &'a Ipld;
313
314 fn next(&mut self) -> Option<Self::Item> {
315 loop {
316 if let Some(iter) = self.stack.last_mut() {
317 if let Some(ipld) = iter.next() {
318 match ipld {
319 Ipld::List(list) => {
320 self.stack.push(Box::new(list.iter()));
321 }
322 Ipld::Map(map) => {
323 self.stack.push(Box::new(map.values()));
324 }
325 _ => {}
326 }
327 return Some(ipld);
328 } else {
329 self.stack.pop();
330 }
331 } else {
332 return None;
333 }
334 }
335 }
336}
337
338#[cfg(test)]
339mod tests {
340 use super::*;
341
342 #[test]
343 fn test_ipld_bool_from() {
344 assert_eq!(Ipld::Bool(true), Ipld::from(true));
345 assert_eq!(Ipld::Bool(false), Ipld::from(false));
346 }
347
348 #[test]
349 fn test_ipld_integer_from() {
350 assert_eq!(Ipld::Integer(1), Ipld::from(1i8));
351 assert_eq!(Ipld::Integer(1), Ipld::from(1i16));
352 assert_eq!(Ipld::Integer(1), Ipld::from(1i32));
353 assert_eq!(Ipld::Integer(1), Ipld::from(1i64));
354 assert_eq!(Ipld::Integer(1), Ipld::from(1i128));
355
356 assert_eq!(Ipld::Integer(1), Ipld::from(1u16));
358 assert_eq!(Ipld::Integer(1), Ipld::from(1u32));
359 assert_eq!(Ipld::Integer(1), Ipld::from(1u64));
360 }
361
362 #[test]
363 fn test_ipld_float_from() {
364 assert_eq!(Ipld::Float(1.0), Ipld::from(1.0f32));
365 assert_eq!(Ipld::Float(1.0), Ipld::from(1.0f64));
366 }
367
368 #[test]
369 fn test_ipld_string_from() {
370 assert_eq!(Ipld::String("a string".into()), Ipld::from("a string"));
371 assert_eq!(
372 Ipld::String("a string".into()),
373 Ipld::from("a string".to_string())
374 );
375 }
376
377 #[test]
378 fn test_ipld_bytes_from() {
379 assert_eq!(
380 Ipld::Bytes(vec![0, 1, 2, 3]),
381 Ipld::from(&[0u8, 1u8, 2u8, 3u8][..])
382 );
383 assert_eq!(
384 Ipld::Bytes(vec![0, 1, 2, 3]),
385 Ipld::from(vec![0u8, 1u8, 2u8, 3u8])
386 );
387 }
388
389 #[test]
390 fn test_ipld_link_from() {
391 let cid = Cid::try_from(
392 "bafkreie74tgmnxqwojhtumgh5dzfj46gi4mynlfr7dmm7duwzyvnpw7h7m",
393 )
394 .unwrap();
395 assert_eq!(Ipld::Link(cid), Ipld::from(cid));
396 }
397
398 #[test]
399 fn test_take() {
400 let ipld =
401 Ipld::List(vec![Ipld::Integer(0), Ipld::Integer(1), Ipld::Integer(2)]);
402 assert_eq!(ipld.clone().take(0).unwrap(), Some(Ipld::Integer(0)));
403 assert_eq!(ipld.clone().take(1).unwrap(), Some(Ipld::Integer(1)));
404 assert_eq!(ipld.take(2).unwrap(), Some(Ipld::Integer(2)));
405
406 let mut map = BTreeMap::new();
407 map.insert("a".to_string(), Ipld::Integer(0));
408 map.insert("b".to_string(), Ipld::Integer(1));
409 map.insert("c".to_string(), Ipld::Integer(2));
410 let ipld = Ipld::Map(map);
411 assert_eq!(ipld.take("a").unwrap(), Some(Ipld::Integer(0)));
412 }
413
414 #[test]
415 fn test_get() {
416 let ipld =
417 Ipld::List(vec![Ipld::Integer(0), Ipld::Integer(1), Ipld::Integer(2)]);
418 assert_eq!(ipld.get(0).unwrap(), Some(&Ipld::Integer(0)));
419 assert_eq!(ipld.get(1).unwrap(), Some(&Ipld::Integer(1)));
420 assert_eq!(ipld.get(2).unwrap(), Some(&Ipld::Integer(2)));
421
422 let mut map = BTreeMap::new();
423 map.insert("a".to_string(), Ipld::Integer(0));
424 map.insert("b".to_string(), Ipld::Integer(1));
425 map.insert("c".to_string(), Ipld::Integer(2));
426 let ipld = Ipld::Map(map);
427 assert_eq!(ipld.get("a").unwrap(), Some(&Ipld::Integer(0)));
428 }
429
430 #[test]
433 fn test_partial_eq_nan() {
434 let invalid_ipld = Ipld::Float(f64::NAN);
435 assert_eq!(invalid_ipld, invalid_ipld);
436 }
437}