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 crate::cid::Cid;
13use crate::error::TypeError;
14
15#[derive(Clone, PartialEq)]
17pub enum Ipld {
18 Null,
20 Bool(bool),
22 Integer(i128),
24 Float(f64),
26 String(String),
28 Bytes(Vec<u8>),
30 List(Vec<Ipld>),
32 Map(BTreeMap<String, Ipld>),
34 Link(Cid),
36}
37
38impl fmt::Debug for Ipld {
39 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
40 if f.alternate() {
41 match self {
42 Self::Null => write!(f, "Null"),
43 Self::Bool(b) => write!(f, "Bool({:?})", b),
44 Self::Integer(i) => write!(f, "Integer({:?})", i),
45 Self::Float(i) => write!(f, "Float({:?})", i),
46 Self::String(s) => write!(f, "String({:?})", s),
47 Self::Bytes(b) => write!(f, "Bytes({:?})", b),
48 Self::List(l) => write!(f, "List({:#?})", l),
49 Self::Map(m) => write!(f, "Map({:#?})", m),
50 Self::Link(cid) => write!(f, "Link({})", cid),
51 }
52 } else {
53 match self {
54 Self::Null => write!(f, "null"),
55 Self::Bool(b) => write!(f, "{:?}", b),
56 Self::Integer(i) => write!(f, "{:?}", i),
57 Self::Float(i) => write!(f, "{:?}", i),
58 Self::String(s) => write!(f, "{:?}", s),
59 Self::Bytes(b) => write!(f, "{:?}", b),
60 Self::List(l) => write!(f, "{:?}", l),
61 Self::Map(m) => write!(f, "{:?}", m),
62 Self::Link(cid) => write!(f, "{}", cid),
63 }
64 }
65 }
66}
67
68pub enum IpldIndex<'a> {
70 List(usize),
72 Map(String),
74 MapRef(&'a str),
76}
77
78impl<'a> From<usize> for IpldIndex<'a> {
79 fn from(index: usize) -> Self {
80 Self::List(index)
81 }
82}
83
84impl<'a> From<String> for IpldIndex<'a> {
85 fn from(key: String) -> Self {
86 Self::Map(key)
87 }
88}
89
90impl<'a> From<&'a str> for IpldIndex<'a> {
91 fn from(key: &'a str) -> Self {
92 Self::MapRef(key)
93 }
94}
95
96impl Ipld {
97 pub fn take<'a, T: Into<IpldIndex<'a>>>(mut self, index: T) -> Result<Self, TypeError> {
99 let index = index.into();
100 let ipld = match &mut self {
101 Ipld::List(ref mut l) => match index {
102 IpldIndex::List(i) => Some(i),
103 IpldIndex::Map(ref key) => key.parse().ok(),
104 IpldIndex::MapRef(key) => key.parse().ok(),
105 }
106 .map(|i| {
107 if i < l.len() {
108 Some(l.swap_remove(i))
109 } else {
110 None
111 }
112 }),
113 Ipld::Map(ref mut m) => match index {
114 IpldIndex::Map(ref key) => Some(m.remove(key)),
115 IpldIndex::MapRef(key) => Some(m.remove(key)),
116 IpldIndex::List(i) => Some(m.remove(&i.to_string())),
117 },
118 _ => None,
119 };
120 ipld.unwrap_or_default()
121 .ok_or_else(|| TypeError::new(index, self))
122 }
123
124 pub fn get<'a, T: Into<IpldIndex<'a>>>(&self, index: T) -> Result<&Self, TypeError> {
126 let index = index.into();
127 let ipld = match self {
128 Ipld::List(l) => match index {
129 IpldIndex::List(i) => Some(i),
130 IpldIndex::Map(ref key) => key.parse().ok(),
131 IpldIndex::MapRef(key) => key.parse().ok(),
132 }
133 .map(|i| l.get(i)),
134 Ipld::Map(m) => match index {
135 IpldIndex::Map(ref key) => Some(m.get(key)),
136 IpldIndex::MapRef(key) => Some(m.get(key)),
137 IpldIndex::List(i) => Some(m.get(&i.to_string())),
138 },
139 _ => None,
140 };
141 ipld.unwrap_or_default()
142 .ok_or_else(|| TypeError::new(index, self))
143 }
144
145 pub fn iter(&self) -> IpldIter<'_> {
147 IpldIter {
148 stack: vec![Box::new(vec![self].into_iter())],
149 }
150 }
151
152 pub fn references<E: Extend<Cid>>(&self, set: &mut E) {
154 for ipld in self.iter() {
155 if let Ipld::Link(cid) = ipld {
156 set.extend(core::iter::once(cid.to_owned()));
157 }
158 }
159 }
160}
161
162pub struct IpldIter<'a> {
164 stack: Vec<Box<dyn Iterator<Item = &'a Ipld> + 'a>>,
165}
166
167impl<'a> Iterator for IpldIter<'a> {
168 type Item = &'a Ipld;
169
170 fn next(&mut self) -> Option<Self::Item> {
171 loop {
172 if let Some(iter) = self.stack.last_mut() {
173 if let Some(ipld) = iter.next() {
174 match ipld {
175 Ipld::List(list) => {
176 self.stack.push(Box::new(list.iter()));
177 }
178 Ipld::Map(map) => {
179 self.stack.push(Box::new(map.values()));
180 }
181 _ => {}
182 }
183 return Some(ipld);
184 } else {
185 self.stack.pop();
186 }
187 } else {
188 return None;
189 }
190 }
191 }
192}
193
194#[cfg(test)]
195mod tests {
196 use super::*;
197 use crate::cid::Cid;
198 use crate::multihash::{Code, MultihashDigest};
199
200 #[test]
201 fn test_ipld_bool_from() {
202 assert_eq!(Ipld::Bool(true), Ipld::from(true));
203 assert_eq!(Ipld::Bool(false), Ipld::from(false));
204 }
205
206 #[test]
207 fn test_ipld_integer_from() {
208 assert_eq!(Ipld::Integer(1), Ipld::from(1i8));
209 assert_eq!(Ipld::Integer(1), Ipld::from(1i16));
210 assert_eq!(Ipld::Integer(1), Ipld::from(1i32));
211 assert_eq!(Ipld::Integer(1), Ipld::from(1i64));
212 assert_eq!(Ipld::Integer(1), Ipld::from(1i128));
213
214 assert_eq!(Ipld::Integer(1), Ipld::from(1u16));
216 assert_eq!(Ipld::Integer(1), Ipld::from(1u32));
217 assert_eq!(Ipld::Integer(1), Ipld::from(1u64));
218 }
219
220 #[test]
221 fn test_ipld_float_from() {
222 assert_eq!(Ipld::Float(1.0), Ipld::from(1.0f32));
223 assert_eq!(Ipld::Float(1.0), Ipld::from(1.0f64));
224 }
225
226 #[test]
227 fn test_ipld_string_from() {
228 assert_eq!(Ipld::String("a string".into()), Ipld::from("a string"));
229 assert_eq!(
230 Ipld::String("a string".into()),
231 Ipld::from("a string".to_string())
232 );
233 }
234
235 #[test]
236 fn test_ipld_bytes_from() {
237 assert_eq!(
238 Ipld::Bytes(vec![0, 1, 2, 3]),
239 Ipld::from(&[0u8, 1u8, 2u8, 3u8][..])
240 );
241 assert_eq!(
242 Ipld::Bytes(vec![0, 1, 2, 3]),
243 Ipld::from(vec![0u8, 1u8, 2u8, 3u8])
244 );
245 }
246
247 #[test]
248 fn test_ipld_link_from() {
249 let data = vec![0, 1, 2, 3];
250 let hash = Code::Blake3_256.digest(&data);
251 let cid = Cid::new_v1(0x55, hash);
252 assert_eq!(Ipld::Link(cid), Ipld::from(cid));
253 }
254
255 #[test]
256 fn test_take() {
257 let ipld = Ipld::List(vec![Ipld::Integer(0), Ipld::Integer(1), Ipld::Integer(2)]);
258 assert_eq!(ipld.clone().take(0).unwrap(), Ipld::Integer(0));
259 assert_eq!(ipld.clone().take(1).unwrap(), Ipld::Integer(1));
260 assert_eq!(ipld.take(2).unwrap(), Ipld::Integer(2));
261
262 let mut map = BTreeMap::new();
263 map.insert("a".to_string(), Ipld::Integer(0));
264 map.insert("b".to_string(), Ipld::Integer(1));
265 map.insert("c".to_string(), Ipld::Integer(2));
266 let ipld = Ipld::Map(map);
267 assert_eq!(ipld.take("a").unwrap(), Ipld::Integer(0));
268 }
269
270 #[test]
271 fn test_get() {
272 let ipld = Ipld::List(vec![Ipld::Integer(0), Ipld::Integer(1), Ipld::Integer(2)]);
273 assert_eq!(ipld.get(0).unwrap(), &Ipld::Integer(0));
274 assert_eq!(ipld.get(1).unwrap(), &Ipld::Integer(1));
275 assert_eq!(ipld.get(2).unwrap(), &Ipld::Integer(2));
276
277 let mut map = BTreeMap::new();
278 map.insert("a".to_string(), Ipld::Integer(0));
279 map.insert("b".to_string(), Ipld::Integer(1));
280 map.insert("c".to_string(), Ipld::Integer(2));
281 let ipld = Ipld::Map(map);
282 assert_eq!(ipld.get("a").unwrap(), &Ipld::Integer(0));
283 }
284}