1use crate::{borrowed::Ipld, CodecExt, Error};
6use cid::Cid;
7use failure::format_err;
8use std::{convert::TryFrom, marker::PhantomData};
9
10#[doc(hidden)]
12#[macro_export(local_inner_macros)]
13macro_rules! borrowed_ipld_from_ref {
14 ($type:ty : $member:ident) => {
15 impl<'a, C> From<&'a $type> for Ipld<'a, C>
16 where
17 C: CodecExt,
18 {
19 #[inline]
20 fn from(t: &'a $type) -> Ipld<'a, C> {
21 Ipld::$member(*t)
22 }
23 }
24 };
25}
26
27impl<'a, C> TryFrom<Ipld<'a, C>> for ()
30where
31 C: CodecExt,
32{
33 type Error = Error;
34
35 #[inline]
36 fn try_from(ipld: Ipld<'a, C>) -> Result<Self, Self::Error> {
37 match ipld {
38 Ipld::Null(_) => Ok(()),
39 _ => Err(Error::Ipld(format_err!("Not Null"))),
40 }
41 }
42}
43
44impl<'a, C> From<&'a ()> for Ipld<'a, C>
45where
46 C: CodecExt,
47{
48 #[inline]
49 fn from(_: &'a ()) -> Ipld<'a, C> {
50 Ipld::Null(PhantomData)
51 }
52}
53
54borrowed_ipld_from_ref!(bool: Bool);
57impl<'a, C> TryFrom<Ipld<'a, C>> for bool
58where
59 C: CodecExt,
60{
61 type Error = Error;
62
63 #[inline]
64 fn try_from(ipld: Ipld<'a, C>) -> Result<Self, Self::Error> {
65 match ipld {
66 Ipld::Bool(b) => Ok(b),
67 _ => Err(Error::Ipld(format_err!("Not Bool"))),
68 }
69 }
70}
71
72#[doc(hidden)]
75#[macro_export(local_inner_macros)]
76macro_rules! try_from_num {
77 ($type:ty : $member:ident) => {
78 impl<'a, C> TryFrom<Ipld<'a, C>> for $type
79 where
80 C: CodecExt,
81 {
82 type Error = Error;
83
84 #[inline]
85 fn try_from(ipld: Ipld<'a, C>) -> Result<Self, Self::Error> {
86 match ipld {
87 Ipld::$member(i) => Ok(i),
88 _ => Err(Error::Ipld(::failure::format_err!(
89 "Not {}",
90 ::std::stringify!($type)
91 ))),
92 }
93 }
94 }
95
96 borrowed_ipld_from_ref!($type: $member);
97 };
98}
99
100try_from_num!(i8: Int8);
101try_from_num!(i16: Int16);
102try_from_num!(i32: Int32);
103try_from_num!(i64: Int64);
104try_from_num!(i128: Int128);
105try_from_num!(u8: Uint8);
106try_from_num!(u16: Uint16);
107try_from_num!(u32: Uint32);
108try_from_num!(u64: Uint64);
109try_from_num!(u128: Uint128);
110try_from_num!(f32: Float32);
111try_from_num!(f64: Float64);
112
113impl<'a, C> TryFrom<Ipld<'a, C>> for &'a str
116where
117 C: CodecExt,
118{
119 type Error = Error;
120
121 #[inline]
122 fn try_from(ipld: Ipld<'a, C>) -> Result<Self, Self::Error> {
123 match ipld {
124 Ipld::String(s) => Ok(s),
125 _ => Err(Error::Ipld(format_err!("Not String"))),
126 }
127 }
128}
129
130impl<'a, C> TryFrom<Ipld<'a, C>> for String
131where
132 C: CodecExt,
133{
134 type Error = Error;
135
136 #[inline]
137 fn try_from(ipld: Ipld<'a, C>) -> Result<Self, Self::Error> {
138 match ipld {
139 Ipld::String(s) => Ok(s.into()),
140 _ => Err(Error::Ipld(format_err!("Not String"))),
141 }
142 }
143}
144
145impl<'a, C> From<&'a String> for Ipld<'a, C>
146where
147 C: CodecExt,
148{
149 #[inline]
150 fn from(s: &'a String) -> Ipld<'a, C> {
151 Ipld::String(&*s)
152 }
153}
154
155impl<'a, C> TryFrom<Ipld<'a, C>> for &'a [u8]
158where
159 C: CodecExt,
160{
161 type Error = Error;
162
163 #[inline]
164 fn try_from(ipld: Ipld<'a, C>) -> Result<Self, Self::Error> {
165 match ipld {
166 Ipld::Bytes(b) => Ok(b),
167 _ => Err(Error::Ipld(format_err!("Not Bytes"))),
168 }
169 }
170}
171
172impl<'a, C> From<&'a Box<[u8]>> for Ipld<'a, C>
173where
174 C: CodecExt,
175{
176 #[inline]
177 fn from(bytes: &'a Box<[u8]>) -> Ipld<'a, C> {
178 Ipld::Bytes(&*bytes)
179 }
180}
181
182#[cfg(feature = "bytes_")]
183impl<'a, C> TryFrom<Ipld<'a, C>> for bytes::Bytes
184where
185 C: CodecExt,
186{
187 type Error = Error;
188
189 #[inline]
190 fn try_from(ipld: Ipld<'a, C>) -> Result<Self, Self::Error> {
191 match ipld {
192 Ipld::Bytes(b) => Ok(bytes::Bytes::copy_from_slice(b)),
193 _ => Err(Error::Ipld(format_err!("Not Bytes"))),
194 }
195 }
196}
197
198#[cfg(feature = "bytes_")]
199impl<'a, C> From<&'a bytes::Bytes> for Ipld<'a, C>
200where
201 C: CodecExt,
202{
203 #[inline]
204 fn from(bytes: &'a bytes::Bytes) -> Ipld<'a, C> {
205 Ipld::Bytes(bytes.as_ref())
206 }
207}
208
209impl<'a, C> TryFrom<Ipld<'a, C>> for Cid
212where
213 C: CodecExt,
214{
215 type Error = Error;
216
217 #[inline]
218 fn try_from(ipld: Ipld<'a, C>) -> Result<Self, Self::Error> {
219 match ipld {
220 Ipld::Link(cid) => Ok(cid),
221 _ => Err(Error::Ipld(format_err!("Not Link"))),
222 }
223 }
224}
225
226impl<'a, C> From<&'a Cid> for Ipld<'a, C>
227where
228 C: CodecExt,
229{
230 #[inline]
231 fn from(link: &'a Cid) -> Ipld<'a, C> {
232 Ipld::Link(link.to_owned())
233 }
234}
235
236#[macro_export]
239macro_rules! derive_ipld_for_struct {
240 ($name:ident { $($member:ident : $value_type:ty,)* }) => {
241 ::paste::item! {
242 #[doc(hidden)]
243 enum [<$name Field>] {
244 $(
245 [<Field $member>],
246 )*
247 }
248 }
249 ::paste::item! {
250 #[doc(hidden)]
251 #[derive(Default)]
252 struct [<$name Builder>] { $($member : Option<$value_type>,)* }
253
254 impl [<$name Builder>] {
255 $(
256 #[inline]
257 fn [<set_ $member>](&mut self, value: $value_type) -> &mut Self {
258 self.$member = Some(value);
259 self
260 }
261 )*
262
263 #[inline]
264 fn field(key: &str) -> Result<[<$name Field>], Error> {
265 match key {
266 $(::std::stringify!($member) => Ok([<$name Field>]::[<Field $member>]),)*
267 _ => Err(Error::Codec(::failure::format_err!("missing key: {}", key).into())),
268 }
269 }
270
271 #[inline]
272 fn build(self) -> Result<$name, Error> {
273 Ok($name {
274 $($member: self.$member
275 .ok_or(Error::Codec(::failure::format_err!("Missing key: {}", ::std::stringify!($member))))?,)*
276 })
277 }
278 }
279 }
280
281 ::paste::item! {
282 impl<'a, C> TryFrom<Ipld<'a, C>> for $name
283 where
284 C: CodecExt,
285 {
286 type Error = Error;
287
288 #[inline]
289 fn try_from(ipld: Ipld<'a, C>) -> Result<Self, Self::Error> {
290 match ipld {
291 Ipld::Map(map_iter) => match map_iter {
292 IpldMapIter::Vec(iter) => {
293 let mut iter = iter.into_inner();
294 let mut builder = [<$name Builder>]::default();
295
296 while let Some((key, value)) = iter.next() {
297 match [<$name Builder>]::field(key)? {
298 $([<$name Field>]::[<Field $member>] => {
299 builder.[<set_ $member>]($value_type::try_from(value)?)
300 },)*
301 };
302 };
303
304 builder.build()
305 }
306 },
307 _ => Err(Error::Ipld(IpldError::NotMap)),
308 }
309 }
310 }
311 }
312
313 ::paste::item! {
314 impl<'a, C> TryInto<Ipld<'a, C>> for &'a $name
315 where
316 C: CodecExt,
317 {
318 type Error = Error;
319
320 #[inline]
321 fn try_into(self) -> Result<Ipld<'a, C>, Self::Error> {
322
323
324 }
328 }
329 }
330 };
331 (@count $t1:tt, $($t:tt),+) => { 1 + derive_ipld_for_struct!(@count $($t),+) };
332 (@count $t:tt) => { 1 };
333}
334
335#[macro_export]
336macro_rules! derive_ipld_for_enum {
337 ($name:ident { $(| $member:ident,)* }) => {};
338}
339
340#[macro_export]
341macro_rules! derive_ipld_for_union {
342 ($name:ident { $($member:ident : $value_type:ty,)* }) => {};
343}