1use crate::cid::Cid;
7use crate::error::{Error, Result};
8use serde::{Deserialize, Serialize};
9use std::collections::BTreeMap;
10
11const CID_TAG: u64 = 42;
13
14#[derive(Debug, Clone, PartialEq)]
19pub enum Ipld {
20 Null,
22 Bool(bool),
24 Integer(i128),
26 Float(f64),
28 String(String),
30 Bytes(Vec<u8>),
32 List(Vec<Ipld>),
34 Map(BTreeMap<String, Ipld>),
36 Link(crate::cid::SerializableCid),
38}
39
40impl Ipld {
41 pub fn link(cid: Cid) -> Self {
43 Ipld::Link(crate::cid::SerializableCid(cid))
44 }
45
46 pub fn is_link(&self) -> bool {
48 matches!(self, Ipld::Link(_))
49 }
50
51 pub fn as_link(&self) -> Option<&Cid> {
53 match self {
54 Ipld::Link(cid) => Some(&cid.0),
55 _ => None,
56 }
57 }
58
59 pub fn to_dag_cbor(&self) -> Result<Vec<u8>> {
66 let mut buffer = Vec::new();
67 encode_dag_cbor(self, &mut buffer)?;
68 Ok(buffer)
69 }
70
71 pub fn from_dag_cbor(data: &[u8]) -> Result<Self> {
73 decode_dag_cbor(&mut &data[..])
74 }
75
76 pub fn to_dag_json(&self) -> Result<String> {
82 let json_value = ipld_to_dag_json(self)?;
83 serde_json::to_string_pretty(&json_value)
84 .map_err(|e| Error::Serialization(format!("Failed to serialize DAG-JSON: {}", e)))
85 }
86
87 pub fn from_dag_json(json: &str) -> Result<Self> {
89 let json_value: serde_json::Value = serde_json::from_str(json)
90 .map_err(|e| Error::Deserialization(format!("Failed to parse DAG-JSON: {}", e)))?;
91 dag_json_to_ipld(&json_value)
92 }
93
94 pub fn to_json(&self) -> Result<String> {
96 self.to_dag_json()
97 }
98
99 pub fn from_json(json: &str) -> Result<Self> {
101 Self::from_dag_json(json)
102 }
103
104 pub fn links(&self) -> Vec<Cid> {
106 let mut result = Vec::new();
107 self.collect_links(&mut result);
108 result
109 }
110
111 fn collect_links(&self, result: &mut Vec<Cid>) {
112 match self {
113 Ipld::Link(cid) => result.push(cid.0),
114 Ipld::List(list) => {
115 for item in list {
116 item.collect_links(result);
117 }
118 }
119 Ipld::Map(map) => {
120 for value in map.values() {
121 value.collect_links(result);
122 }
123 }
124 _ => {}
125 }
126 }
127
128 #[inline]
130 pub const fn is_null(&self) -> bool {
131 matches!(self, Ipld::Null)
132 }
133
134 #[inline]
136 pub const fn is_bool(&self) -> bool {
137 matches!(self, Ipld::Bool(_))
138 }
139
140 #[inline]
142 pub const fn is_integer(&self) -> bool {
143 matches!(self, Ipld::Integer(_))
144 }
145
146 #[inline]
148 pub const fn is_float(&self) -> bool {
149 matches!(self, Ipld::Float(_))
150 }
151
152 #[inline]
154 pub const fn is_string(&self) -> bool {
155 matches!(self, Ipld::String(_))
156 }
157
158 #[inline]
160 pub const fn is_bytes(&self) -> bool {
161 matches!(self, Ipld::Bytes(_))
162 }
163
164 #[inline]
166 pub const fn is_list(&self) -> bool {
167 matches!(self, Ipld::List(_))
168 }
169
170 #[inline]
172 pub const fn is_map(&self) -> bool {
173 matches!(self, Ipld::Map(_))
174 }
175
176 #[inline]
178 pub const fn as_bool(&self) -> Option<bool> {
179 match self {
180 Ipld::Bool(b) => Some(*b),
181 _ => None,
182 }
183 }
184
185 #[inline]
187 pub const fn as_integer(&self) -> Option<i128> {
188 match self {
189 Ipld::Integer(i) => Some(*i),
190 _ => None,
191 }
192 }
193
194 #[inline]
196 pub const fn as_float(&self) -> Option<f64> {
197 match self {
198 Ipld::Float(f) => Some(*f),
199 _ => None,
200 }
201 }
202
203 #[inline]
205 pub fn as_string(&self) -> Option<&str> {
206 match self {
207 Ipld::String(s) => Some(s.as_str()),
208 _ => None,
209 }
210 }
211
212 #[inline]
214 pub fn as_bytes(&self) -> Option<&[u8]> {
215 match self {
216 Ipld::Bytes(b) => Some(b.as_slice()),
217 _ => None,
218 }
219 }
220
221 #[inline]
223 pub fn as_list(&self) -> Option<&[Ipld]> {
224 match self {
225 Ipld::List(l) => Some(l.as_slice()),
226 _ => None,
227 }
228 }
229
230 #[inline]
232 pub fn as_map(&self) -> Option<&BTreeMap<String, Ipld>> {
233 match self {
234 Ipld::Map(m) => Some(m),
235 _ => None,
236 }
237 }
238
239 #[inline]
241 pub fn get(&self, key: &str) -> Option<&Ipld> {
242 self.as_map()?.get(key)
243 }
244
245 #[inline]
247 pub fn index(&self, idx: usize) -> Option<&Ipld> {
248 self.as_list()?.get(idx)
249 }
250
251 pub fn len(&self) -> usize {
259 match self {
260 Ipld::List(l) => l.len(),
261 Ipld::Map(m) => m.len(),
262 Ipld::String(s) => s.len(),
263 Ipld::Bytes(b) => b.len(),
264 _ => 0,
265 }
266 }
267
268 pub fn is_empty(&self) -> bool {
274 match self {
275 Ipld::Null => true,
276 Ipld::List(l) => l.is_empty(),
277 Ipld::Map(m) => m.is_empty(),
278 Ipld::String(s) => s.is_empty(),
279 Ipld::Bytes(b) => b.is_empty(),
280 _ => false,
281 }
282 }
283
284 pub const fn type_name(&self) -> &'static str {
286 match self {
287 Ipld::Null => "null",
288 Ipld::Bool(_) => "bool",
289 Ipld::Integer(_) => "integer",
290 Ipld::Float(_) => "float",
291 Ipld::String(_) => "string",
292 Ipld::Bytes(_) => "bytes",
293 Ipld::List(_) => "list",
294 Ipld::Map(_) => "map",
295 Ipld::Link(_) => "link",
296 }
297 }
298}
299
300fn encode_dag_cbor(ipld: &Ipld, buffer: &mut Vec<u8>) -> Result<()> {
305 match ipld {
306 Ipld::Null => {
307 buffer.push(0xf6);
309 }
310 Ipld::Bool(b) => {
311 buffer.push(if *b { 0xf5 } else { 0xf4 });
313 }
314 Ipld::Integer(i) => {
315 encode_cbor_integer(*i, buffer)?;
316 }
317 Ipld::Float(f) => {
318 buffer.push(0xfb);
320 buffer.extend_from_slice(&f.to_be_bytes());
321 }
322 Ipld::String(s) => {
323 encode_cbor_length(3, s.len() as u64, buffer);
325 buffer.extend_from_slice(s.as_bytes());
326 }
327 Ipld::Bytes(b) => {
328 encode_cbor_length(2, b.len() as u64, buffer);
330 buffer.extend_from_slice(b);
331 }
332 Ipld::List(list) => {
333 encode_cbor_length(4, list.len() as u64, buffer);
335 for item in list {
336 encode_dag_cbor(item, buffer)?;
337 }
338 }
339 Ipld::Map(map) => {
340 encode_cbor_length(5, map.len() as u64, buffer);
342 for (key, value) in map {
344 encode_cbor_length(3, key.len() as u64, buffer);
345 buffer.extend_from_slice(key.as_bytes());
346 encode_dag_cbor(value, buffer)?;
347 }
348 }
349 Ipld::Link(cid) => {
350 encode_cbor_tag(CID_TAG, buffer);
352 let cid_bytes = cid.0.to_bytes();
354 let mut prefixed = vec![0x00];
355 prefixed.extend_from_slice(&cid_bytes);
356 encode_cbor_length(2, prefixed.len() as u64, buffer);
357 buffer.extend_from_slice(&prefixed);
358 }
359 }
360 Ok(())
361}
362
363fn encode_cbor_integer(value: i128, buffer: &mut Vec<u8>) -> Result<()> {
364 if value >= 0 {
365 let val = value as u64;
367 encode_cbor_length(0, val, buffer);
368 } else {
369 let val = (-1 - value) as u64;
371 encode_cbor_length(1, val, buffer);
372 }
373 Ok(())
374}
375
376fn encode_cbor_length(major_type: u8, length: u64, buffer: &mut Vec<u8>) {
377 let mt = major_type << 5;
378 if length < 24 {
379 buffer.push(mt | length as u8);
380 } else if length < 256 {
381 buffer.push(mt | 24);
382 buffer.push(length as u8);
383 } else if length < 65536 {
384 buffer.push(mt | 25);
385 buffer.extend_from_slice(&(length as u16).to_be_bytes());
386 } else if length < 4294967296 {
387 buffer.push(mt | 26);
388 buffer.extend_from_slice(&(length as u32).to_be_bytes());
389 } else {
390 buffer.push(mt | 27);
391 buffer.extend_from_slice(&length.to_be_bytes());
392 }
393}
394
395fn encode_cbor_tag(tag: u64, buffer: &mut Vec<u8>) {
396 encode_cbor_length(6, tag, buffer);
398}
399
400fn decode_dag_cbor<R: std::io::Read>(reader: &mut R) -> Result<Ipld> {
405 let mut first_byte = [0u8; 1];
406 reader
407 .read_exact(&mut first_byte)
408 .map_err(|e| Error::Deserialization(format!("Failed to read CBOR: {}", e)))?;
409
410 let major_type = first_byte[0] >> 5;
411 let additional_info = first_byte[0] & 0x1f;
412
413 match major_type {
414 0 => {
415 let value = decode_cbor_uint(additional_info, reader)?;
417 Ok(Ipld::Integer(value as i128))
418 }
419 1 => {
420 let value = decode_cbor_uint(additional_info, reader)?;
422 Ok(Ipld::Integer(-1 - value as i128))
423 }
424 2 => {
425 let len = decode_cbor_uint(additional_info, reader)? as usize;
427 let mut bytes = vec![0u8; len];
428 reader
429 .read_exact(&mut bytes)
430 .map_err(|e| Error::Deserialization(format!("Failed to read bytes: {}", e)))?;
431 Ok(Ipld::Bytes(bytes))
432 }
433 3 => {
434 let len = decode_cbor_uint(additional_info, reader)? as usize;
436 let mut bytes = vec![0u8; len];
437 reader
438 .read_exact(&mut bytes)
439 .map_err(|e| Error::Deserialization(format!("Failed to read string: {}", e)))?;
440 let s = String::from_utf8(bytes)
441 .map_err(|e| Error::Deserialization(format!("Invalid UTF-8: {}", e)))?;
442 Ok(Ipld::String(s))
443 }
444 4 => {
445 let len = decode_cbor_uint(additional_info, reader)? as usize;
447 let mut list = Vec::with_capacity(len);
448 for _ in 0..len {
449 list.push(decode_dag_cbor(reader)?);
450 }
451 Ok(Ipld::List(list))
452 }
453 5 => {
454 let len = decode_cbor_uint(additional_info, reader)? as usize;
456 let mut map = BTreeMap::new();
457 for _ in 0..len {
458 let key = decode_dag_cbor(reader)?;
459 let key_str = match key {
460 Ipld::String(s) => s,
461 _ => {
462 return Err(Error::Deserialization(
463 "Map keys must be strings in IPLD".to_string(),
464 ))
465 }
466 };
467 let value = decode_dag_cbor(reader)?;
468 map.insert(key_str, value);
469 }
470 Ok(Ipld::Map(map))
471 }
472 6 => {
473 let tag = decode_cbor_uint(additional_info, reader)?;
475 if tag == CID_TAG {
476 let bytes_ipld = decode_dag_cbor(reader)?;
478 match bytes_ipld {
479 Ipld::Bytes(mut bytes) => {
480 if bytes.first() == Some(&0x00) {
482 bytes.remove(0);
483 }
484 let cid = Cid::try_from(&bytes[..])
485 .map_err(|e| Error::Deserialization(format!("Invalid CID: {}", e)))?;
486 Ok(Ipld::Link(crate::cid::SerializableCid(cid)))
487 }
488 _ => Err(Error::Deserialization(
489 "CID tag must wrap bytes".to_string(),
490 )),
491 }
492 } else {
493 decode_dag_cbor(reader)
495 }
496 }
497 7 => {
498 match additional_info {
500 20 => Ok(Ipld::Bool(false)),
501 21 => Ok(Ipld::Bool(true)),
502 22 => Ok(Ipld::Null),
503 25 => {
504 let mut bytes = [0u8; 2];
506 reader.read_exact(&mut bytes).map_err(|e| {
507 Error::Deserialization(format!("Failed to read f16: {}", e))
508 })?;
509 let bits = u16::from_be_bytes(bytes);
510 Ok(Ipld::Float(f16_to_f64(bits)))
511 }
512 26 => {
513 let mut bytes = [0u8; 4];
515 reader.read_exact(&mut bytes).map_err(|e| {
516 Error::Deserialization(format!("Failed to read f32: {}", e))
517 })?;
518 let f = f32::from_be_bytes(bytes);
519 Ok(Ipld::Float(f as f64))
520 }
521 27 => {
522 let mut bytes = [0u8; 8];
524 reader.read_exact(&mut bytes).map_err(|e| {
525 Error::Deserialization(format!("Failed to read f64: {}", e))
526 })?;
527 let f = f64::from_be_bytes(bytes);
528 Ok(Ipld::Float(f))
529 }
530 _ => Err(Error::Deserialization(format!(
531 "Unknown simple value: {}",
532 additional_info
533 ))),
534 }
535 }
536 _ => Err(Error::Deserialization(format!(
537 "Unknown CBOR major type: {}",
538 major_type
539 ))),
540 }
541}
542
543fn decode_cbor_uint<R: std::io::Read>(additional_info: u8, reader: &mut R) -> Result<u64> {
544 match additional_info {
545 0..=23 => Ok(additional_info as u64),
546 24 => {
547 let mut buf = [0u8; 1];
548 reader
549 .read_exact(&mut buf)
550 .map_err(|e| Error::Deserialization(format!("Failed to read u8: {}", e)))?;
551 Ok(buf[0] as u64)
552 }
553 25 => {
554 let mut buf = [0u8; 2];
555 reader
556 .read_exact(&mut buf)
557 .map_err(|e| Error::Deserialization(format!("Failed to read u16: {}", e)))?;
558 Ok(u16::from_be_bytes(buf) as u64)
559 }
560 26 => {
561 let mut buf = [0u8; 4];
562 reader
563 .read_exact(&mut buf)
564 .map_err(|e| Error::Deserialization(format!("Failed to read u32: {}", e)))?;
565 Ok(u32::from_be_bytes(buf) as u64)
566 }
567 27 => {
568 let mut buf = [0u8; 8];
569 reader
570 .read_exact(&mut buf)
571 .map_err(|e| Error::Deserialization(format!("Failed to read u64: {}", e)))?;
572 Ok(u64::from_be_bytes(buf))
573 }
574 _ => Err(Error::Deserialization(format!(
575 "Invalid additional info for integer: {}",
576 additional_info
577 ))),
578 }
579}
580
581fn f16_to_f64(bits: u16) -> f64 {
583 let sign = ((bits >> 15) & 1) as u64;
584 let exp = ((bits >> 10) & 0x1f) as i32;
585 let frac = (bits & 0x3ff) as u64;
586
587 if exp == 0 {
588 if frac == 0 {
590 f64::from_bits(sign << 63)
591 } else {
592 let mut e = -14;
594 let mut f = frac;
595 while (f & 0x400) == 0 {
596 f <<= 1;
597 e -= 1;
598 }
599 let new_exp = (e + 1023) as u64;
600 let new_frac = (f & 0x3ff) << 42;
601 f64::from_bits((sign << 63) | (new_exp << 52) | new_frac)
602 }
603 } else if exp == 31 {
604 if frac == 0 {
606 f64::from_bits((sign << 63) | (0x7ff << 52))
607 } else {
608 f64::from_bits((sign << 63) | (0x7ff << 52) | (frac << 42))
609 }
610 } else {
611 let new_exp = ((exp - 15) + 1023) as u64;
613 let new_frac = frac << 42;
614 f64::from_bits((sign << 63) | (new_exp << 52) | new_frac)
615 }
616}
617
618fn ipld_to_dag_json(ipld: &Ipld) -> Result<serde_json::Value> {
623 use serde_json::Value;
624
625 match ipld {
626 Ipld::Null => Ok(Value::Null),
627 Ipld::Bool(b) => Ok(Value::Bool(*b)),
628 Ipld::Integer(i) => {
629 if *i >= i64::MIN as i128 && *i <= i64::MAX as i128 {
631 Ok(Value::Number((*i as i64).into()))
632 } else {
633 Ok(Value::String(i.to_string()))
635 }
636 }
637 Ipld::Float(f) => serde_json::Number::from_f64(*f)
638 .map(Value::Number)
639 .ok_or_else(|| Error::Serialization("Cannot encode NaN/Inf as JSON".to_string())),
640 Ipld::String(s) => Ok(Value::String(s.clone())),
641 Ipld::Bytes(b) => {
642 use multibase::Base;
644 let encoded = multibase::encode(Base::Base64, b);
645 let data = &encoded[1..]; let mut inner = serde_json::Map::new();
648 inner.insert("bytes".to_string(), Value::String(data.to_string()));
649 let mut outer = serde_json::Map::new();
650 outer.insert("/".to_string(), Value::Object(inner));
651 Ok(Value::Object(outer))
652 }
653 Ipld::List(list) => {
654 let arr: Result<Vec<Value>> = list.iter().map(ipld_to_dag_json).collect();
655 Ok(Value::Array(arr?))
656 }
657 Ipld::Map(map) => {
658 let mut obj = serde_json::Map::new();
659 for (k, v) in map {
660 obj.insert(k.clone(), ipld_to_dag_json(v)?);
661 }
662 Ok(Value::Object(obj))
663 }
664 Ipld::Link(cid) => {
665 let mut obj = serde_json::Map::new();
667 obj.insert("/".to_string(), Value::String(cid.0.to_string()));
668 Ok(Value::Object(obj))
669 }
670 }
671}
672
673fn dag_json_to_ipld(value: &serde_json::Value) -> Result<Ipld> {
674 use serde_json::Value;
675
676 match value {
677 Value::Null => Ok(Ipld::Null),
678 Value::Bool(b) => Ok(Ipld::Bool(*b)),
679 Value::Number(n) => {
680 if let Some(i) = n.as_i64() {
681 Ok(Ipld::Integer(i as i128))
682 } else if let Some(f) = n.as_f64() {
683 Ok(Ipld::Float(f))
684 } else {
685 Err(Error::Deserialization("Invalid number".to_string()))
686 }
687 }
688 Value::String(s) => Ok(Ipld::String(s.clone())),
689 Value::Array(arr) => {
690 let list: Result<Vec<Ipld>> = arr.iter().map(dag_json_to_ipld).collect();
691 Ok(Ipld::List(list?))
692 }
693 Value::Object(obj) => {
694 if let Some(slash_value) = obj.get("/") {
696 if obj.len() == 1 {
697 match slash_value {
699 Value::String(cid_str) => {
700 let cid: Cid = cid_str.parse().map_err(|e| {
702 Error::Deserialization(format!("Invalid CID: {}", e))
703 })?;
704 return Ok(Ipld::Link(crate::cid::SerializableCid(cid)));
705 }
706 Value::Object(inner) => {
707 if let Some(Value::String(bytes_str)) = inner.get("bytes") {
708 let decoded = multibase::decode(format!("m{}", bytes_str))
710 .map_err(|e| {
711 Error::Deserialization(format!(
712 "Invalid base64 bytes: {}",
713 e
714 ))
715 })?
716 .1;
717 return Ok(Ipld::Bytes(decoded));
718 }
719 }
720 _ => {}
721 }
722 }
723 }
724
725 let mut map = BTreeMap::new();
727 for (k, v) in obj {
728 map.insert(k.clone(), dag_json_to_ipld(v)?);
729 }
730 Ok(Ipld::Map(map))
731 }
732 }
733}
734
735impl Serialize for Ipld {
740 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
741 where
742 S: serde::Serializer,
743 {
744 match self {
745 Ipld::Null => serializer.serialize_none(),
746 Ipld::Bool(b) => serializer.serialize_bool(*b),
747 Ipld::Integer(i) => {
748 if *i >= i64::MIN as i128 && *i <= i64::MAX as i128 {
750 serializer.serialize_i64(*i as i64)
751 } else {
752 serializer.serialize_i128(*i)
753 }
754 }
755 Ipld::Float(f) => serializer.serialize_f64(*f),
756 Ipld::String(s) => serializer.serialize_str(s),
757 Ipld::Bytes(b) => serializer.serialize_bytes(b),
758 Ipld::List(list) => list.serialize(serializer),
759 Ipld::Map(map) => map.serialize(serializer),
760 Ipld::Link(cid) => cid.serialize(serializer),
761 }
762 }
763}
764
765impl<'de> Deserialize<'de> for Ipld {
766 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
767 where
768 D: serde::Deserializer<'de>,
769 {
770 use serde::de::{MapAccess, SeqAccess, Visitor};
771
772 struct IpldVisitor;
773
774 impl<'de> Visitor<'de> for IpldVisitor {
775 type Value = Ipld;
776
777 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
778 formatter.write_str("an IPLD value")
779 }
780
781 fn visit_bool<E>(self, value: bool) -> std::result::Result<Ipld, E> {
782 Ok(Ipld::Bool(value))
783 }
784
785 fn visit_i64<E>(self, value: i64) -> std::result::Result<Ipld, E> {
786 Ok(Ipld::Integer(value as i128))
787 }
788
789 fn visit_i128<E>(self, value: i128) -> std::result::Result<Ipld, E> {
790 Ok(Ipld::Integer(value))
791 }
792
793 fn visit_u64<E>(self, value: u64) -> std::result::Result<Ipld, E> {
794 Ok(Ipld::Integer(value as i128))
795 }
796
797 fn visit_f64<E>(self, value: f64) -> std::result::Result<Ipld, E> {
798 Ok(Ipld::Float(value))
799 }
800
801 fn visit_str<E>(self, value: &str) -> std::result::Result<Ipld, E>
802 where
803 E: serde::de::Error,
804 {
805 Ok(Ipld::String(value.to_string()))
806 }
807
808 fn visit_string<E>(self, value: String) -> std::result::Result<Ipld, E> {
809 Ok(Ipld::String(value))
810 }
811
812 fn visit_bytes<E>(self, value: &[u8]) -> std::result::Result<Ipld, E> {
813 Ok(Ipld::Bytes(value.to_vec()))
814 }
815
816 fn visit_byte_buf<E>(self, value: Vec<u8>) -> std::result::Result<Ipld, E> {
817 Ok(Ipld::Bytes(value))
818 }
819
820 fn visit_none<E>(self) -> std::result::Result<Ipld, E> {
821 Ok(Ipld::Null)
822 }
823
824 fn visit_unit<E>(self) -> std::result::Result<Ipld, E> {
825 Ok(Ipld::Null)
826 }
827
828 fn visit_seq<A>(self, mut seq: A) -> std::result::Result<Ipld, A::Error>
829 where
830 A: SeqAccess<'de>,
831 {
832 let mut list = Vec::new();
833 while let Some(elem) = seq.next_element()? {
834 list.push(elem);
835 }
836 Ok(Ipld::List(list))
837 }
838
839 fn visit_map<A>(self, mut map: A) -> std::result::Result<Ipld, A::Error>
840 where
841 A: MapAccess<'de>,
842 {
843 let mut result = BTreeMap::new();
844 while let Some((key, value)) = map.next_entry()? {
845 result.insert(key, value);
846 }
847 Ok(Ipld::Map(result))
848 }
849 }
850
851 deserializer.deserialize_any(IpldVisitor)
852 }
853}
854
855impl From<bool> for Ipld {
856 fn from(b: bool) -> Self {
857 Ipld::Bool(b)
858 }
859}
860
861impl From<i64> for Ipld {
862 fn from(i: i64) -> Self {
863 Ipld::Integer(i as i128)
864 }
865}
866
867impl From<i128> for Ipld {
868 fn from(i: i128) -> Self {
869 Ipld::Integer(i)
870 }
871}
872
873impl From<u64> for Ipld {
874 fn from(u: u64) -> Self {
875 Ipld::Integer(u as i128)
876 }
877}
878
879impl From<f64> for Ipld {
880 fn from(f: f64) -> Self {
881 Ipld::Float(f)
882 }
883}
884
885impl From<String> for Ipld {
886 fn from(s: String) -> Self {
887 Ipld::String(s)
888 }
889}
890
891impl From<&str> for Ipld {
892 fn from(s: &str) -> Self {
893 Ipld::String(s.to_string())
894 }
895}
896
897impl From<Vec<u8>> for Ipld {
898 fn from(bytes: Vec<u8>) -> Self {
899 Ipld::Bytes(bytes)
900 }
901}
902
903impl From<Cid> for Ipld {
904 fn from(cid: Cid) -> Self {
905 Ipld::Link(crate::cid::SerializableCid(cid))
906 }
907}
908
909#[cfg(test)]
910mod tests {
911 use super::*;
912
913 #[test]
914 fn test_dag_cbor_roundtrip_simple() {
915 let values = vec![
916 Ipld::Null,
917 Ipld::Bool(true),
918 Ipld::Bool(false),
919 Ipld::Integer(0),
920 Ipld::Integer(42),
921 Ipld::Integer(-1),
922 Ipld::Integer(-100),
923 Ipld::Float(2.5),
924 Ipld::String("hello".to_string()),
925 Ipld::Bytes(vec![1, 2, 3]),
926 ];
927
928 for value in values {
929 let encoded = value.to_dag_cbor().unwrap();
930 let decoded = Ipld::from_dag_cbor(&encoded).unwrap();
931 assert_eq!(value, decoded, "Failed roundtrip for {:?}", value);
932 }
933 }
934
935 #[test]
936 fn test_dag_cbor_roundtrip_complex() {
937 let mut map = BTreeMap::new();
938 map.insert("name".to_string(), Ipld::String("test".to_string()));
939 map.insert("count".to_string(), Ipld::Integer(42));
940
941 let value = Ipld::Map(map);
942 let encoded = value.to_dag_cbor().unwrap();
943 let decoded = Ipld::from_dag_cbor(&encoded).unwrap();
944 assert_eq!(value, decoded);
945 }
946
947 #[test]
948 fn test_dag_json_roundtrip() {
949 let mut map = BTreeMap::new();
950 map.insert("name".to_string(), Ipld::String("test".to_string()));
951 map.insert("count".to_string(), Ipld::Integer(42));
952
953 let value = Ipld::Map(map);
954 let json = value.to_dag_json().unwrap();
955 let decoded = Ipld::from_dag_json(&json).unwrap();
956 assert_eq!(value, decoded);
957 }
958
959 #[test]
960 fn test_dag_json_bytes_encoding() {
961 let value = Ipld::Bytes(vec![1, 2, 3, 4, 5]);
962 let json = value.to_dag_json().unwrap();
963 assert!(json.contains("\"/\""));
965 assert!(json.contains("\"bytes\""));
966
967 let decoded = Ipld::from_dag_json(&json).unwrap();
968 assert_eq!(value, decoded);
969 }
970}