atrium_api/types/
cid_link.rs

1use ipld_core::cid::{Cid, Error};
2use ipld_core::ipld::Ipld;
3use serde::{Deserialize, Serialize};
4
5/// Representation of an IPLD Link.
6#[derive(Debug, Clone, PartialEq, Eq)]
7pub struct CidLink(pub Cid);
8
9#[derive(Serialize, Deserialize)]
10struct Link {
11    #[serde(rename = "$link")]
12    link: crate::types::string::Cid,
13}
14
15impl Serialize for CidLink {
16    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
17        if serializer.is_human_readable() {
18            Link { link: crate::types::string::Cid::new(self.0) }.serialize(serializer)
19        } else {
20            self.0.serialize(serializer)
21        }
22    }
23}
24
25impl<'de> Deserialize<'de> for CidLink {
26    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
27        let ipld = Ipld::deserialize(deserializer)?;
28        match &ipld {
29            Ipld::Link(cid) => {
30                return Ok(Self(*cid));
31            }
32            Ipld::Map(map) => {
33                if map.len() == 1 {
34                    if let Some(Ipld::String(link)) = map.get("$link") {
35                        return Ok(Self(
36                            Cid::try_from(link.as_str()).map_err(serde::de::Error::custom)?,
37                        ));
38                    }
39                }
40            }
41            _ => {}
42        }
43        Err(serde::de::Error::custom("Invalid cid-link"))
44    }
45}
46
47impl TryFrom<&str> for CidLink {
48    type Error = Error;
49
50    fn try_from(s: &str) -> Result<Self, Self::Error> {
51        Ok(Self(Cid::try_from(s)?))
52    }
53}
54
55#[cfg(test)]
56mod tests {
57    use super::*;
58    use serde_ipld_dagcbor::{from_slice, to_vec};
59    use serde_json::{from_str, to_string};
60
61    const CID_LINK_JSON: &str =
62        r#"{"$link":"bafkreibme22gw2h7y2h7tg2fhqotaqjucnbc24deqo72b6mkl2egezxhvy"}"#;
63
64    const CID_LINK_DAGCBOR: [u8; 41] = [
65        0xd8, 0x2a, 0x58, 0x25, 0x00, 0x01, 0x55, 0x12, 0x20, 0x2c, 0x26, 0xb4, 0x6b, 0x68, 0xff,
66        0xc6, 0x8f, 0xf9, 0x9b, 0x45, 0x3c, 0x1d, 0x30, 0x41, 0x34, 0x13, 0x42, 0x2d, 0x70, 0x64,
67        0x83, 0xbf, 0xa0, 0xf9, 0x8a, 0x5e, 0x88, 0x62, 0x66, 0xe7, 0xae,
68    ];
69
70    fn cid() -> Cid {
71        Cid::try_from("bafkreibme22gw2h7y2h7tg2fhqotaqjucnbc24deqo72b6mkl2egezxhvy").unwrap()
72    }
73
74    #[test]
75    fn test_cid_link_serialize_json() {
76        let cid_link = CidLink(cid());
77
78        let serialized = to_string(&cid_link).expect("failed to serialize cid-link");
79        assert_eq!(serialized, CID_LINK_JSON);
80    }
81
82    #[test]
83    fn test_cid_link_serialize_dagcbor() {
84        let cid_link = CidLink(cid());
85
86        let serialized = to_vec(&cid_link).expect("failed to serialize cid-link");
87        assert_eq!(serialized, CID_LINK_DAGCBOR);
88    }
89
90    #[test]
91    fn test_cid_link_deserialize_json() {
92        let deserialized =
93            from_str::<CidLink>(CID_LINK_JSON).expect("failed to deserialize cid-link");
94
95        assert_eq!(deserialized, CidLink(cid()));
96    }
97
98    #[test]
99    fn test_cid_link_deserialize_dagcbor() {
100        let deserialized =
101            from_slice::<CidLink>(&CID_LINK_DAGCBOR).expect("failed to deserialize cid-link");
102
103        assert_eq!(deserialized, CidLink(cid()));
104    }
105
106    #[test]
107    fn test_cid_link_deserialize_any_json() {
108        #[derive(Deserialize, Debug, PartialEq, Eq)]
109        #[serde(untagged)]
110        enum Enum {
111            CidLink(CidLink),
112        }
113
114        let deserialized = from_str::<Enum>(CID_LINK_JSON).expect("failed to deserialize cid-link");
115        assert_eq!(deserialized, Enum::CidLink(CidLink(cid())));
116    }
117
118    #[test]
119    fn test_cid_link_deserialize_any_dagcbor() {
120        #[derive(Deserialize, Debug, PartialEq, Eq)]
121        #[serde(untagged)]
122        enum Enum {
123            CidLink(CidLink),
124        }
125
126        let deserialized =
127            from_slice::<Enum>(&CID_LINK_DAGCBOR).expect("failed to deserialize cid-link");
128        assert_eq!(deserialized, Enum::CidLink(CidLink(cid())));
129    }
130
131    #[test]
132    fn test_cid_link_serde_json() {
133        // let deserialized =
134        //     from_str::<CidLink>(CID_LINK_JSON).expect("failed to deserialize cid-link");
135        // let serialized = to_string(&deserialized).expect("failed to serialize cid-link");
136        // assert_eq!(serialized, CID_LINK_JSON);
137
138        let cid_link = CidLink(cid());
139        let serialized = to_string(&cid_link).expect("failed to serialize cid-link");
140        let deserialized =
141            from_str::<CidLink>(&serialized).expect("failed to deserialize cid-link");
142        assert_eq!(deserialized, cid_link);
143    }
144
145    #[test]
146    fn test_cid_link_serde_dagcbor() {
147        let deserialized =
148            from_slice::<Cid>(&CID_LINK_DAGCBOR).expect("failed to deserialize cid-link");
149        let serialized = to_vec(&deserialized).expect("failed to serialize cid-link");
150        assert_eq!(serialized, CID_LINK_DAGCBOR);
151
152        let cid_link = CidLink(cid());
153        let serialized = to_vec(&cid_link).expect("failed to serialize cid-link");
154        let deserialized =
155            from_slice::<CidLink>(&serialized).expect("failed to deserialize cid-link");
156        assert_eq!(deserialized, cid_link);
157    }
158}