1use alloc::{
3 borrow::ToOwned,
4 boxed::Box,
5 collections::BTreeMap,
6 string::{String, ToString},
7 vec,
8 vec::Vec,
9};
10use core::fmt;
11
12use cid::Cid;
13
14#[derive(Clone, Debug)]
16#[non_exhaustive]
17pub enum IndexError {
18 ParseInteger(String),
20 WrongKind(IpldKind),
22}
23
24impl fmt::Display for IndexError {
25 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26 match self {
27 Self::ParseInteger(key) => write!(f, "cannot parse key into integer: {}", key),
28 Self::WrongKind(kind) => write!(f, "expected IPLD List or Map but found: {:?}", kind),
29 }
30 }
31}
32
33#[cfg(feature = "std")]
34impl std::error::Error for IndexError {}
35
36#[derive(Clone)]
38pub enum Ipld {
39 Null,
41 Bool(bool),
43 Integer(i128),
45 Float(f64),
47 String(String),
49 Bytes(Vec<u8>),
51 List(Vec<Ipld>),
53 Map(BTreeMap<String, Ipld>),
55 Link(Cid),
57}
58
59impl fmt::Debug for Ipld {
60 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
61 if f.alternate() {
62 match self {
63 Self::Null => write!(f, "Null"),
64 Self::Bool(b) => write!(f, "Bool({:?})", b),
65 Self::Integer(i) => write!(f, "Integer({:?})", i),
66 Self::Float(i) => write!(f, "Float({:?})", i),
67 Self::String(s) => write!(f, "String({:?})", s),
68 Self::Bytes(b) => write!(f, "Bytes({:?})", b),
69 Self::List(l) => write!(f, "List({:#?})", l),
70 Self::Map(m) => write!(f, "Map({:#?})", m),
71 Self::Link(cid) => write!(f, "Link({})", cid),
72 }
73 } else {
74 match self {
75 Self::Null => write!(f, "null"),
76 Self::Bool(b) => write!(f, "{:?}", b),
77 Self::Integer(i) => write!(f, "{:?}", i),
78 Self::Float(i) => write!(f, "{:?}", i),
79 Self::String(s) => write!(f, "{:?}", s),
80 Self::Bytes(b) => write!(f, "{:?}", b),
81 Self::List(l) => write!(f, "{:?}", l),
82 Self::Map(m) => write!(f, "{:?}", m),
83 Self::Link(cid) => write!(f, "{}", cid),
84 }
85 }
86 }
87}
88
89impl PartialEq for Ipld {
93 fn eq(&self, other: &Self) -> bool {
94 match (self, other) {
95 (Self::Null, Self::Null) => true,
96 (Self::Bool(self_value), Self::Bool(other_value)) => self_value == other_value,
97 (Self::Integer(self_value), Self::Integer(other_value)) => self_value == other_value,
98 (Self::Float(self_value), Self::Float(other_value)) => {
99 self_value == other_value || self_value.is_nan() && other_value.is_nan()
101 }
102 (Self::String(self_value), Self::String(other_value)) => self_value == other_value,
103 (Self::Bytes(self_value), Self::Bytes(other_value)) => self_value == other_value,
104 (Self::List(self_value), Self::List(other_value)) => self_value == other_value,
105 (Self::Map(self_value), Self::Map(other_value)) => self_value == other_value,
106 (Self::Link(self_value), Self::Link(other_value)) => self_value == other_value,
107 _ => false,
108 }
109 }
110}
111
112impl Eq for Ipld {}
113
114#[derive(Clone, Debug)]
119pub enum IpldKind {
120 Null,
122 Bool,
124 Integer,
126 Float,
128 String,
130 Bytes,
132 List,
134 Map,
136 Link,
138}
139
140pub enum IpldIndex<'a> {
144 List(usize),
146 Map(String),
148 MapRef(&'a str),
150}
151
152impl From<usize> for IpldIndex<'_> {
153 fn from(index: usize) -> Self {
154 Self::List(index)
155 }
156}
157
158impl From<String> for IpldIndex<'_> {
159 fn from(key: String) -> Self {
160 Self::Map(key)
161 }
162}
163
164impl<'a> From<&'a str> for IpldIndex<'a> {
165 fn from(key: &'a str) -> Self {
166 Self::MapRef(key)
167 }
168}
169
170impl<'a> TryFrom<IpldIndex<'a>> for usize {
171 type Error = IndexError;
172
173 fn try_from(index: IpldIndex<'a>) -> Result<Self, Self::Error> {
174 let parsed = match index {
175 IpldIndex::List(i) => i,
176 IpldIndex::Map(ref key) => key
177 .parse()
178 .map_err(|_| IndexError::ParseInteger(key.to_string()))?,
179 IpldIndex::MapRef(key) => key
180 .parse()
181 .map_err(|_| IndexError::ParseInteger(key.to_string()))?,
182 };
183 Ok(parsed)
184 }
185}
186
187impl<'a> From<IpldIndex<'a>> for String {
188 fn from(index: IpldIndex<'a>) -> Self {
189 match index {
190 IpldIndex::Map(ref key) => key.to_string(),
191 IpldIndex::MapRef(key) => key.to_string(),
192 IpldIndex::List(i) => i.to_string(),
193 }
194 }
195}
196
197impl Ipld {
198 pub fn kind(&self) -> IpldKind {
203 match self {
204 Ipld::Null => IpldKind::Null,
205 Ipld::Bool(_) => IpldKind::Bool,
206 Ipld::Integer(_) => IpldKind::Integer,
207 Ipld::Float(_) => IpldKind::Float,
208 Ipld::String(_) => IpldKind::String,
209 Ipld::Bytes(_) => IpldKind::Bytes,
210 Ipld::List(_) => IpldKind::List,
211 Ipld::Map(_) => IpldKind::Map,
212 Ipld::Link(_) => IpldKind::Link,
213 }
214 }
215
216 pub fn take<'a, T: Into<IpldIndex<'a>>>(
218 mut self,
219 index: T,
220 ) -> Result<Option<Self>, IndexError> {
221 let index = index.into();
222 match &mut self {
223 Ipld::List(ref mut list) => {
224 let parsed_index = usize::try_from(index)?;
225 if parsed_index < list.len() {
226 Ok(Some(list.swap_remove(parsed_index)))
227 } else {
228 Ok(None)
229 }
230 }
231 Ipld::Map(ref mut map) => {
232 let key = String::from(index);
233 Ok(map.remove(&key))
234 }
235 other => Err(IndexError::WrongKind(other.kind())),
236 }
237 }
238
239 pub fn get<'a, T: Into<IpldIndex<'a>>>(&self, index: T) -> Result<Option<&Self>, IndexError> {
241 let index = index.into();
242 match self {
243 Ipld::List(list) => {
244 let parsed_index = usize::try_from(index)?;
245 Ok(list.get(parsed_index))
246 }
247 Ipld::Map(map) => {
248 let key = String::from(index);
249 Ok(map.get(&key))
250 }
251 other => Err(IndexError::WrongKind(other.kind())),
252 }
253 }
254
255 pub fn iter(&self) -> IpldIter<'_> {
257 IpldIter {
258 stack: vec![Box::new(vec![self].into_iter())],
259 }
260 }
261
262 pub fn references<E: Extend<Cid>>(&self, set: &mut E) {
264 for ipld in self.iter() {
265 if let Ipld::Link(cid) = ipld {
266 set.extend(core::iter::once(cid.to_owned()));
267 }
268 }
269 }
270}
271
272pub struct IpldIter<'a> {
274 stack: Vec<Box<dyn Iterator<Item = &'a Ipld> + 'a>>,
275}
276
277impl<'a> Iterator for IpldIter<'a> {
278 type Item = &'a Ipld;
279
280 fn next(&mut self) -> Option<Self::Item> {
281 loop {
282 if let Some(iter) = self.stack.last_mut() {
283 if let Some(ipld) = iter.next() {
284 match ipld {
285 Ipld::List(list) => {
286 self.stack.push(Box::new(list.iter()));
287 }
288 Ipld::Map(map) => {
289 self.stack.push(Box::new(map.values()));
290 }
291 _ => {}
292 }
293 return Some(ipld);
294 } else {
295 self.stack.pop();
296 }
297 } else {
298 return None;
299 }
300 }
301 }
302}
303
304#[cfg(test)]
305mod tests {
306 use super::*;
307
308 #[test]
309 fn test_ipld_bool_from() {
310 assert_eq!(Ipld::Bool(true), Ipld::from(true));
311 assert_eq!(Ipld::Bool(false), Ipld::from(false));
312 }
313
314 #[test]
315 fn test_ipld_integer_from() {
316 assert_eq!(Ipld::Integer(1), Ipld::from(1i8));
317 assert_eq!(Ipld::Integer(1), Ipld::from(1i16));
318 assert_eq!(Ipld::Integer(1), Ipld::from(1i32));
319 assert_eq!(Ipld::Integer(1), Ipld::from(1i64));
320 assert_eq!(Ipld::Integer(1), Ipld::from(1i128));
321
322 assert_eq!(Ipld::Integer(1), Ipld::from(1u16));
324 assert_eq!(Ipld::Integer(1), Ipld::from(1u32));
325 assert_eq!(Ipld::Integer(1), Ipld::from(1u64));
326 }
327
328 #[test]
329 fn test_ipld_float_from() {
330 assert_eq!(Ipld::Float(1.0), Ipld::from(1.0f32));
331 assert_eq!(Ipld::Float(1.0), Ipld::from(1.0f64));
332 }
333
334 #[test]
335 fn test_ipld_string_from() {
336 assert_eq!(Ipld::String("a string".into()), Ipld::from("a string"));
337 assert_eq!(
338 Ipld::String("a string".into()),
339 Ipld::from("a string".to_string())
340 );
341 }
342
343 #[test]
344 fn test_ipld_bytes_from() {
345 assert_eq!(
346 Ipld::Bytes(vec![0, 1, 2, 3]),
347 Ipld::from(&[0u8, 1u8, 2u8, 3u8][..])
348 );
349 assert_eq!(
350 Ipld::Bytes(vec![0, 1, 2, 3]),
351 Ipld::from(vec![0u8, 1u8, 2u8, 3u8])
352 );
353 }
354
355 #[test]
356 fn test_ipld_link_from() {
357 let cid =
358 Cid::try_from("bafkreie74tgmnxqwojhtumgh5dzfj46gi4mynlfr7dmm7duwzyvnpw7h7m").unwrap();
359 assert_eq!(Ipld::Link(cid), Ipld::from(cid));
360 }
361
362 #[test]
363 fn test_take() {
364 let ipld = Ipld::List(vec![Ipld::Integer(0), Ipld::Integer(1), Ipld::Integer(2)]);
365 assert_eq!(ipld.clone().take(0).unwrap(), Some(Ipld::Integer(0)));
366 assert_eq!(ipld.clone().take(1).unwrap(), Some(Ipld::Integer(1)));
367 assert_eq!(ipld.take(2).unwrap(), Some(Ipld::Integer(2)));
368
369 let mut map = BTreeMap::new();
370 map.insert("a".to_string(), Ipld::Integer(0));
371 map.insert("b".to_string(), Ipld::Integer(1));
372 map.insert("c".to_string(), Ipld::Integer(2));
373 let ipld = Ipld::Map(map);
374 assert_eq!(ipld.take("a").unwrap(), Some(Ipld::Integer(0)));
375 }
376
377 #[test]
378 fn test_get() {
379 let ipld = Ipld::List(vec![Ipld::Integer(0), Ipld::Integer(1), Ipld::Integer(2)]);
380 assert_eq!(ipld.get(0).unwrap(), Some(&Ipld::Integer(0)));
381 assert_eq!(ipld.get(1).unwrap(), Some(&Ipld::Integer(1)));
382 assert_eq!(ipld.get(2).unwrap(), Some(&Ipld::Integer(2)));
383
384 let mut map = BTreeMap::new();
385 map.insert("a".to_string(), Ipld::Integer(0));
386 map.insert("b".to_string(), Ipld::Integer(1));
387 map.insert("c".to_string(), Ipld::Integer(2));
388 let ipld = Ipld::Map(map);
389 assert_eq!(ipld.get("a").unwrap(), Some(&Ipld::Integer(0)));
390 }
391
392 #[test]
395 fn test_partial_eq_nan() {
396 let invalid_ipld = Ipld::Float(f64::NAN);
397 assert_eq!(invalid_ipld, invalid_ipld);
398 }
399}