1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
// Copyright 2020 ChainSafe Systems // SPDX-License-Identifier: Apache-2.0, MIT mod de; mod error; mod path; mod path_segment; pub mod selector; mod ser; #[cfg(feature = "json")] pub mod json; #[macro_use] mod macros; pub use self::error::Error; pub use path::Path; pub use path_segment::PathSegment; use cid::Cid; use encoding::{from_slice, to_vec, Cbor}; use ser::Serializer; use serde::de::DeserializeOwned; use serde::Serialize; use std::collections::BTreeMap; /// Represents IPLD data structure used when serializing and deserializing data. #[derive(Debug, Clone, PartialEq)] pub enum Ipld { /// Represents a null value. /// /// ```no_run /// # use forest_ipld::ipld; /// let v = ipld!(null); /// ``` Null, /// Represents a boolean value. /// /// ```no_run /// # use forest_ipld::ipld; /// let v = ipld!(true); /// ``` Bool(bool), /// Represents a signed integer value. /// /// ```no_run /// # use forest_ipld::ipld; /// let v = ipld!(28); /// ``` Integer(i128), /// Represents a floating point value. /// /// ```no_run /// # use forest_ipld::ipld; /// let v = ipld!(8.5); /// ``` Float(f64), /// Represents a String. /// /// ```no_run /// # use forest_ipld::ipld; /// let v = ipld!("string"); /// ``` String(String), /// Represents Bytes. /// /// ```no_run /// # use forest_ipld::ipld; /// let v = ipld!(Bytes(vec![0x98, 0x8, 0x2a, 0xff])); /// ``` Bytes(Vec<u8>), /// Represents List of IPLD objects. /// /// ```no_run /// # use forest_ipld::ipld; /// let v = ipld!([1, "string", null]); /// ``` List(Vec<Ipld>), /// Represents a map of strings to Ipld objects. /// /// ```no_run /// # use forest_ipld::ipld; /// let v = ipld!({"key": "value", "bool": true}); /// ``` Map(BTreeMap<String, Ipld>), /// Represents a link to another piece of data through a content identifier (`Cid`). /// Using `ipld` macro, can wrap Cid with Link to be explicit of Link type, or let it resolve. /// /// ``` /// # use forest_ipld::ipld; /// # use cid::Cid; /// let cid: Cid = "QmdfTbBqBPQ7VNxZEYEj14VmRuZBkqFbiwReogJgS1zR1n".parse().unwrap(); /// let v1 = ipld!(Link(cid.clone())); /// let v2 = ipld!(cid); /// assert_eq!(v1, v2); /// ``` Link(Cid), } impl Ipld { pub(crate) fn lookup_segment(&self, segment: &PathSegment) -> Option<&Self> { match self { Self::Map(map) => match segment { PathSegment::String(s) => map.get(s), PathSegment::Int(i) => map.get(&i.to_string()), }, Self::List(list) => list.get(segment.to_index()?), _ => None, } } } impl Cbor for Ipld {} /// Convert any object into an IPLD object pub fn to_ipld<T>(ipld: T) -> Result<Ipld, Error> where T: Serialize, { ipld.serialize(Serializer) } /// Convert a `Ipld` structure into a type `T` /// Currently converts using a byte buffer with serde_cbor pub fn from_ipld<T>(value: &Ipld) -> Result<T, String> where T: DeserializeOwned, { // TODO update to not go through byte buffer to convert // There is a good amount of overhead for this (having to implement serde::Deserializer) // for Ipld, but possible. The benefit isn't worth changing yet since if the value is not // passed by reference as needed by HAMT, then the values will have to be cloned. let buf = to_vec(value).map_err(|e| e.to_string())?; from_slice(buf.as_slice()).map_err(|e| e.to_string()) }