1#[cfg(feature = "dag-cbor")]
3use crate::cbor::DagCborCodec;
4use crate::cid::Cid;
5use crate::codec::{Codec, Decode, Encode, References};
6use crate::error::{Result, UnsupportedCodec};
7use crate::ipld::Ipld;
8#[cfg(feature = "dag-json")]
9use crate::json::DagJsonCodec;
10#[cfg(feature = "dag-pb")]
11use crate::pb::DagPbCodec;
12use crate::raw::RawCodec;
13use core::convert::TryFrom;
14use std::io::{Read, Seek, Write};
15
16#[derive(Clone, Copy, Debug, PartialEq, Eq)]
18pub enum IpldCodec {
19 Raw,
21 #[cfg(feature = "dag-cbor")]
23 DagCbor,
24 #[cfg(feature = "dag-json")]
26 DagJson,
27 #[cfg(feature = "dag-pb")]
29 DagPb,
30}
31
32impl TryFrom<u64> for IpldCodec {
33 type Error = UnsupportedCodec;
34
35 fn try_from(ccode: u64) -> core::result::Result<Self, Self::Error> {
36 Ok(match ccode {
37 0x55 => Self::Raw,
38 #[cfg(feature = "dag-cbor")]
39 0x71 => Self::DagCbor,
40 #[cfg(feature = "dag-json")]
41 0x0129 => Self::DagJson,
42 #[cfg(feature = "dag-pb")]
43 0x70 => Self::DagPb,
44 _ => return Err(UnsupportedCodec(ccode)),
45 })
46 }
47}
48
49impl From<IpldCodec> for u64 {
50 fn from(mc: IpldCodec) -> Self {
51 match mc {
52 IpldCodec::Raw => 0x55,
53 #[cfg(feature = "dag-cbor")]
54 IpldCodec::DagCbor => 0x71,
55 #[cfg(feature = "dag-json")]
56 IpldCodec::DagJson => 0x0129,
57 #[cfg(feature = "dag-pb")]
58 IpldCodec::DagPb => 0x70,
59 }
60 }
61}
62
63impl From<RawCodec> for IpldCodec {
64 fn from(_: RawCodec) -> Self {
65 Self::Raw
66 }
67}
68
69#[cfg(feature = "dag-cbor")]
70impl From<DagCborCodec> for IpldCodec {
71 fn from(_: DagCborCodec) -> Self {
72 Self::DagCbor
73 }
74}
75
76#[cfg(feature = "dag-cbor")]
77impl From<IpldCodec> for DagCborCodec {
78 fn from(_: IpldCodec) -> Self {
79 Self
80 }
81}
82
83#[cfg(feature = "dag-json")]
84impl From<DagJsonCodec> for IpldCodec {
85 fn from(_: DagJsonCodec) -> Self {
86 Self::DagJson
87 }
88}
89
90#[cfg(feature = "dag-json")]
91impl From<IpldCodec> for DagJsonCodec {
92 fn from(_: IpldCodec) -> Self {
93 Self
94 }
95}
96
97#[cfg(feature = "dag-pb")]
98impl From<DagPbCodec> for IpldCodec {
99 fn from(_: DagPbCodec) -> Self {
100 Self::DagPb
101 }
102}
103
104#[cfg(feature = "dag-pb")]
105impl From<IpldCodec> for DagPbCodec {
106 fn from(_: IpldCodec) -> Self {
107 Self
108 }
109}
110
111impl Codec for IpldCodec {}
112
113impl Encode<IpldCodec> for Ipld {
114 fn encode<W: Write>(&self, c: IpldCodec, w: &mut W) -> Result<()> {
115 match c {
116 IpldCodec::Raw => self.encode(RawCodec, w)?,
117 #[cfg(feature = "dag-cbor")]
118 IpldCodec::DagCbor => self.encode(DagCborCodec, w)?,
119 #[cfg(feature = "dag-json")]
120 IpldCodec::DagJson => self.encode(DagJsonCodec, w)?,
121 #[cfg(feature = "dag-pb")]
122 IpldCodec::DagPb => self.encode(DagPbCodec, w)?,
123 };
124 Ok(())
125 }
126}
127
128impl Decode<IpldCodec> for Ipld {
129 fn decode<R: Read + Seek>(c: IpldCodec, r: &mut R) -> Result<Self> {
130 Ok(match c {
131 IpldCodec::Raw => Self::decode(RawCodec, r)?,
132 #[cfg(feature = "dag-cbor")]
133 IpldCodec::DagCbor => Self::decode(DagCborCodec, r)?,
134 #[cfg(feature = "dag-json")]
135 IpldCodec::DagJson => Self::decode(DagJsonCodec, r)?,
136 #[cfg(feature = "dag-pb")]
137 IpldCodec::DagPb => Self::decode(DagPbCodec, r)?,
138 })
139 }
140}
141
142impl References<IpldCodec> for Ipld {
143 fn references<R: Read + Seek, E: Extend<Cid>>(
144 c: IpldCodec,
145 r: &mut R,
146 set: &mut E,
147 ) -> Result<()> {
148 match c {
149 IpldCodec::Raw => <Self as References<RawCodec>>::references(RawCodec, r, set)?,
150 #[cfg(feature = "dag-cbor")]
151 IpldCodec::DagCbor => {
152 <Self as References<DagCborCodec>>::references(DagCborCodec, r, set)?
153 }
154 #[cfg(feature = "dag-json")]
155 IpldCodec::DagJson => {
156 <Self as References<DagJsonCodec>>::references(DagJsonCodec, r, set)?
157 }
158 #[cfg(feature = "dag-pb")]
159 IpldCodec::DagPb => <Self as References<DagPbCodec>>::references(DagPbCodec, r, set)?,
160 };
161 Ok(())
162 }
163}
164
165#[cfg(test)]
166mod tests {
167 use super::*;
168
169 #[test]
170 fn raw_encode() {
171 let data = Ipld::Bytes([0x22, 0x33, 0x44].to_vec());
172 let result = IpldCodec::Raw.encode(&data).unwrap();
173 assert_eq!(result, vec![0x22, 0x33, 0x44]);
174 }
175
176 #[test]
177 fn raw_decode() {
178 let data = [0x22, 0x33, 0x44];
179 let result: Ipld = IpldCodec::Raw.decode(&data).unwrap();
180 assert_eq!(result, Ipld::Bytes(data.to_vec()));
181 }
182
183 #[cfg(feature = "dag-cbor")]
184 #[test]
185 fn dag_cbor_encode() {
186 let data = Ipld::Bytes([0x22, 0x33, 0x44].to_vec());
187 let result = IpldCodec::DagCbor.encode(&data).unwrap();
188 assert_eq!(result, vec![0x43, 0x22, 0x33, 0x44]);
189 }
190
191 #[cfg(feature = "dag-cbor")]
192 #[test]
193 fn dag_cbor_decode() {
194 let data = [0x43, 0x22, 0x33, 0x44];
195 let result: Ipld = IpldCodec::DagCbor.decode(&data).unwrap();
196 assert_eq!(result, Ipld::Bytes(vec![0x22, 0x33, 0x44]));
197 }
198
199 #[cfg(feature = "dag-json")]
200 #[test]
201 fn dag_json_encode() {
202 let data = Ipld::Bool(true);
203 let result = String::from_utf8(IpldCodec::DagJson.encode(&data).unwrap().to_vec()).unwrap();
204 assert_eq!(result, "true");
205 }
206
207 #[cfg(feature = "dag-json")]
208 #[test]
209 fn dag_json_decode() {
210 let data = b"true";
211 let result: Ipld = IpldCodec::DagJson.decode(data).unwrap();
212 assert_eq!(result, Ipld::Bool(true));
213 }
214
215 #[cfg(feature = "dag-pb")]
216 #[test]
217 fn dag_pb_encode() {
218 let mut data_map = std::collections::BTreeMap::<String, Ipld>::new();
219 data_map.insert("Data".to_string(), Ipld::Bytes(b"data".to_vec()));
220 data_map.insert("Links".to_string(), Ipld::List(vec![]));
221
222 let data = Ipld::Map(data_map);
223 let result = IpldCodec::DagPb.encode(&data).unwrap();
224 assert_eq!(result, vec![0x0a, 0x04, 0x64, 0x61, 0x74, 0x61]);
225 }
226
227 #[cfg(feature = "dag-pb")]
228 #[test]
229 fn dag_pb_decode() {
230 let mut data_map = std::collections::BTreeMap::<String, Ipld>::new();
231 data_map.insert("Data".to_string(), Ipld::Bytes(b"data".to_vec()));
232 data_map.insert("Links".to_string(), Ipld::List(vec![]));
233 let expected = Ipld::Map(data_map);
234
235 let data = [0x0a, 0x04, 0x64, 0x61, 0x74, 0x61];
236 let result: Ipld = IpldCodec::DagPb.decode(&data).unwrap();
237 assert_eq!(result, expected);
238 }
239}