cbor_data/
codec.rs

1//! This module is experimental!
2
3use super::TypeError;
4use crate::{value::Number, Cbor, CborOwned, Encoder, ItemKind, TaggedItem, Writer};
5use std::{
6    any::TypeId,
7    borrow::Cow,
8    collections::{BTreeMap, BTreeSet, HashMap, HashSet},
9    convert::TryInto,
10    error::Error,
11    hash::Hash,
12};
13
14#[cfg(feature = "derive")]
15pub use cbor_data_derive::{ReadCbor, WriteCbor};
16
17#[derive(Debug)]
18pub enum CodecError {
19    TypeError(TypeError),
20    WrongNumber(&'static str),
21    TupleSize {
22        expected: usize,
23        found: usize,
24    },
25    NoKnownVariant {
26        known: &'static [&'static str],
27        present: Vec<String>,
28    },
29    MissingField(&'static str),
30    Custom(Box<dyn Error + Send + Sync>),
31    String(String),
32    WithContext(String, Box<CodecError>),
33}
34
35impl PartialEq for CodecError {
36    fn eq(&self, other: &Self) -> bool {
37        match (self, other) {
38            (Self::TypeError(l0), Self::TypeError(r0)) => l0 == r0,
39            (
40                Self::TupleSize {
41                    expected: l_expected,
42                    found: l_found,
43                },
44                Self::TupleSize {
45                    expected: r_expected,
46                    found: r_found,
47                },
48            ) => l_expected == r_expected && l_found == r_found,
49            (Self::WrongNumber(l0), Self::WrongNumber(r0)) => l0 == r0,
50            (
51                Self::NoKnownVariant {
52                    known: l_known,
53                    present: l_present,
54                },
55                Self::NoKnownVariant {
56                    known: r_known,
57                    present: r_present,
58                },
59            ) => l_known == r_known && l_present == r_present,
60            (Self::MissingField(l0), Self::MissingField(r0)) => l0 == r0,
61            (Self::Custom(l0), Self::Custom(r0)) => l0.to_string() == r0.to_string(),
62            (Self::String(l0), Self::String(r0)) => l0 == r0,
63            (Self::WithContext(l0, l1), Self::WithContext(r0, r1)) => l0 == r0 && l1 == r1,
64            _ => false,
65        }
66    }
67}
68
69impl CodecError {
70    pub fn type_error(target: &'static str, item: &TaggedItem<'_>) -> Self {
71        Self::TypeError(TypeError {
72            target,
73            kind: item.kind().into(),
74            tags: item.tags().into(),
75        })
76    }
77
78    pub fn tuple_size(expected: usize, found: usize) -> Self {
79        Self::TupleSize { expected, found }
80    }
81
82    pub fn custom(err: impl Error + Send + Sync + 'static) -> Self {
83        Self::Custom(Box::new(err))
84    }
85
86    pub fn str(err: impl Into<String>) -> Self {
87        Self::String(err.into())
88    }
89
90    pub fn with_ctx(self, f: impl FnOnce(&mut String)) -> Self {
91        match self {
92            Self::WithContext(mut ctx, err) => {
93                ctx.push_str(" <- ");
94                f(&mut ctx);
95                Self::WithContext(ctx, err)
96            }
97            err => {
98                let mut ctx = String::new();
99                f(&mut ctx);
100                Self::WithContext(ctx, Box::new(err))
101            }
102        }
103    }
104}
105
106impl std::fmt::Display for CodecError {
107    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
108        match self {
109            CodecError::TypeError(e) => write!(f, "{}", e),
110            CodecError::WrongNumber(s) => write!(f, "wrong number format (found {})", s),
111            CodecError::TupleSize { expected, found } => write!(
112                f,
113                "wrong tuple size: expected {}, found {}",
114                expected, found
115            ),
116            CodecError::NoKnownVariant { known, present } => {
117                write!(f, "unknown variant: known [")?;
118                for (idx, k) in known.iter().enumerate() {
119                    if idx > 0 {
120                        write!(f, ", ")?;
121                    }
122                    write!(f, "{}", k)?;
123                }
124                write!(f, "], present [")?;
125                for (idx, p) in present.iter().enumerate() {
126                    if idx > 0 {
127                        write!(f, ", ")?;
128                    }
129                    write!(f, "{}", p)?;
130                }
131                write!(f, "]")?;
132                Ok(())
133            }
134            CodecError::MissingField(name) => write!(f, "missing field `{}`", name),
135            CodecError::Custom(err) => write!(f, "codec error: {}", err),
136            CodecError::String(err) => write!(f, "codec error: {}", err),
137            CodecError::WithContext(ctx, err) => write!(f, "error decoding {}: {}", ctx, err),
138        }
139    }
140}
141impl Error for CodecError {}
142
143impl From<TypeError> for CodecError {
144    fn from(te: TypeError) -> Self {
145        Self::TypeError(te)
146    }
147}
148
149pub type Result<T> = std::result::Result<T, CodecError>;
150
151pub trait WriteCbor {
152    fn write_cbor<W: Writer>(&self, w: W) -> W::Output;
153}
154
155pub trait ReadCbor {
156    fn fmt(f: &mut impl std::fmt::Write) -> std::fmt::Result;
157
158    fn name() -> String {
159        let mut s = String::new();
160        Self::fmt(&mut s).unwrap();
161        s
162    }
163
164    fn read_cbor(cbor: &Cbor) -> Result<Self>
165    where
166        Self: Sized,
167    {
168        Self::read_cbor_impl(cbor).map_err(|err| {
169            err.with_ctx(|ctx| {
170                Self::fmt(ctx).ok();
171            })
172        })
173    }
174
175    fn read_cbor_impl(cbor: &Cbor) -> Result<Self>
176    where
177        Self: Sized;
178}
179
180pub trait ReadCborBorrowed<'a>: ToOwned + 'a {
181    fn read_cbor_borrowed(cbor: &'a Cbor) -> Result<Cow<'a, Self>>;
182}
183
184impl<T: WriteCbor> WriteCbor for Vec<T> {
185    fn write_cbor<W: Writer>(&self, w: W) -> W::Output {
186        w.encode_array(|mut b| {
187            for item in self {
188                item.write_cbor(&mut b);
189            }
190        })
191    }
192}
193
194impl<T: WriteCbor> WriteCbor for [T] {
195    fn write_cbor<W: Writer>(&self, w: W) -> W::Output {
196        w.encode_array(|mut w| {
197            for item in self {
198                item.write_cbor(&mut w);
199            }
200        })
201    }
202}
203
204impl<T: ReadCbor> ReadCbor for Vec<T> {
205    fn fmt(f: &mut impl std::fmt::Write) -> std::fmt::Result {
206        write!(f, "Vec<")?;
207        T::fmt(f)?;
208        write!(f, ">")?;
209        Ok(())
210    }
211
212    fn read_cbor_impl(cbor: &Cbor) -> Result<Self>
213    where
214        Self: Sized,
215    {
216        let a = cbor.try_array()?;
217        let mut v = Vec::with_capacity(a.len());
218        for item in a {
219            v.push(T::read_cbor(item.as_ref())?);
220        }
221        Ok(v)
222    }
223}
224
225#[repr(transparent)]
226pub struct AsByteString<T>(pub T);
227
228impl<T: AsRef<[u8]>> WriteCbor for AsByteString<T> {
229    fn write_cbor<W: Writer>(&self, w: W) -> W::Output {
230        w.encode_bytes(self.0.as_ref())
231    }
232}
233
234impl<'a> ReadCborBorrowed<'a> for [u8] {
235    fn read_cbor_borrowed(cbor: &'a Cbor) -> Result<Cow<'a, Self>> {
236        cbor.try_bytes().map_err(Into::into)
237    }
238}
239
240impl<T: for<'a> From<&'a [u8]> + 'static> ReadCbor for AsByteString<T> {
241    fn fmt(f: &mut impl std::fmt::Write) -> std::fmt::Result {
242        write!(f, "AsByteString({:?})", TypeId::of::<T>())
243    }
244
245    fn read_cbor_impl(cbor: &Cbor) -> Result<Self>
246    where
247        Self: Sized,
248    {
249        Ok(AsByteString(T::from(
250            <[u8]>::read_cbor_borrowed(cbor)?.as_ref(),
251        )))
252    }
253}
254
255impl<'a, T: ToOwned + WriteCbor> WriteCbor for Cow<'a, T> {
256    fn write_cbor<W: Writer>(&self, w: W) -> W::Output {
257        self.as_ref().write_cbor(w)
258    }
259}
260
261impl<'a, T: ToOwned> ReadCbor for Cow<'a, T>
262where
263    T::Owned: ReadCbor,
264{
265    fn fmt(f: &mut impl std::fmt::Write) -> std::fmt::Result {
266        write!(f, "Cow<")?;
267        T::Owned::fmt(f)?;
268        write!(f, ">")?;
269        Ok(())
270    }
271
272    fn read_cbor_impl(cbor: &Cbor) -> Result<Self>
273    where
274        Self: Sized,
275    {
276        Ok(Cow::Owned(ReadCbor::read_cbor(cbor)?))
277    }
278}
279
280impl WriteCbor for String {
281    fn write_cbor<W: Writer>(&self, w: W) -> W::Output {
282        w.encode_str(self)
283    }
284}
285
286impl<'a> WriteCbor for &'a str {
287    fn write_cbor<W: Writer>(&self, w: W) -> W::Output {
288        w.encode_str(self)
289    }
290}
291
292impl<'a> ReadCborBorrowed<'a> for str {
293    fn read_cbor_borrowed(cbor: &'a Cbor) -> Result<Cow<'a, Self>> {
294        cbor.try_str().map_err(Into::into)
295    }
296}
297
298impl ReadCbor for String {
299    fn fmt(f: &mut impl std::fmt::Write) -> std::fmt::Result {
300        write!(f, "String")
301    }
302
303    fn read_cbor_impl(cbor: &Cbor) -> Result<Self>
304    where
305        Self: Sized,
306    {
307        Ok(str::read_cbor_borrowed(cbor)?.into_owned())
308    }
309}
310
311impl<T: WriteCbor> WriteCbor for Option<T> {
312    fn write_cbor<W: Writer>(&self, w: W) -> W::Output {
313        if let Some(this) = self {
314            this.write_cbor(w)
315        } else {
316            w.encode_null()
317        }
318    }
319}
320
321impl<T: ReadCbor> ReadCbor for Option<T> {
322    fn read_cbor_impl(cbor: &Cbor) -> Result<Self>
323    where
324        Self: Sized,
325    {
326        if let ItemKind::Null = cbor.tagged_item().kind() {
327            Ok(None)
328        } else {
329            Ok(Some(T::read_cbor(cbor)?))
330        }
331    }
332
333    fn fmt(f: &mut impl std::fmt::Write) -> std::fmt::Result {
334        write!(f, "Option<")?;
335        T::fmt(f)?;
336        write!(f, ">")?;
337        Ok(())
338    }
339}
340
341impl<K: WriteCbor, V: WriteCbor> WriteCbor for BTreeMap<K, V> {
342    fn write_cbor<W: Writer>(&self, w: W) -> W::Output {
343        w.encode_dict(|w| {
344            for (k, v) in self {
345                w.with_cbor_key(|w| k.write_cbor(w), |w| v.write_cbor(w));
346            }
347        })
348    }
349}
350
351impl<K: ReadCbor + Ord, V: ReadCbor> ReadCbor for BTreeMap<K, V> {
352    fn read_cbor_impl(cbor: &Cbor) -> Result<Self>
353    where
354        Self: Sized,
355    {
356        let mut map = BTreeMap::new();
357        for (k, v) in cbor.try_dict()? {
358            map.insert(K::read_cbor(k.as_ref())?, V::read_cbor(v.as_ref())?);
359        }
360        Ok(map)
361    }
362
363    fn fmt(f: &mut impl std::fmt::Write) -> std::fmt::Result {
364        write!(f, "BTreeMap<")?;
365        K::fmt(f)?;
366        write!(f, ", ")?;
367        V::fmt(f)?;
368        write!(f, ">")?;
369        Ok(())
370    }
371}
372
373impl<K: WriteCbor, V: WriteCbor> WriteCbor for HashMap<K, V> {
374    fn write_cbor<W: Writer>(&self, w: W) -> W::Output {
375        w.encode_dict(|w| {
376            for (k, v) in self {
377                w.with_cbor_key(|w| k.write_cbor(w), |w| v.write_cbor(w));
378            }
379        })
380    }
381}
382
383impl<K: ReadCbor + Hash + Eq, V: ReadCbor> ReadCbor for HashMap<K, V> {
384    fn read_cbor_impl(cbor: &Cbor) -> Result<Self>
385    where
386        Self: Sized,
387    {
388        let mut map = HashMap::new();
389        for (k, v) in cbor.try_dict()? {
390            map.insert(K::read_cbor(k.as_ref())?, V::read_cbor(v.as_ref())?);
391        }
392        Ok(map)
393    }
394
395    fn fmt(f: &mut impl std::fmt::Write) -> std::fmt::Result {
396        write!(f, "HashMap<")?;
397        K::fmt(f)?;
398        write!(f, ", ")?;
399        V::fmt(f)?;
400        write!(f, ">")?;
401        Ok(())
402    }
403}
404
405impl<K: WriteCbor> WriteCbor for BTreeSet<K> {
406    fn write_cbor<W: Writer>(&self, w: W) -> W::Output {
407        w.encode_array(|mut w| {
408            for k in self {
409                k.write_cbor(&mut w);
410            }
411        })
412    }
413}
414
415impl<K: ReadCbor + Ord> ReadCbor for BTreeSet<K> {
416    fn fmt(f: &mut impl std::fmt::Write) -> std::fmt::Result {
417        write!(f, "BTreeSet<")?;
418        K::fmt(f)?;
419        write!(f, ">")?;
420        Ok(())
421    }
422
423    fn read_cbor_impl(cbor: &Cbor) -> Result<Self>
424    where
425        Self: Sized,
426    {
427        let mut set = Self::new();
428        for k in cbor.try_array()? {
429            set.insert(K::read_cbor(k.as_ref())?);
430        }
431        Ok(set)
432    }
433}
434
435impl<K: WriteCbor> WriteCbor for HashSet<K> {
436    fn write_cbor<W: Writer>(&self, w: W) -> W::Output {
437        w.encode_array(|mut w| {
438            for k in self {
439                k.write_cbor(&mut w);
440            }
441        })
442    }
443}
444
445impl<K: ReadCbor + Hash + Eq> ReadCbor for HashSet<K> {
446    fn fmt(f: &mut impl std::fmt::Write) -> std::fmt::Result {
447        write!(f, "HashSet<")?;
448        K::fmt(f)?;
449        write!(f, ">")?;
450        Ok(())
451    }
452
453    fn read_cbor_impl(cbor: &Cbor) -> Result<Self>
454    where
455        Self: Sized,
456    {
457        let mut set = Self::new();
458        for k in cbor.try_array()? {
459            set.insert(K::read_cbor(k.as_ref())?);
460        }
461        Ok(set)
462    }
463}
464
465impl WriteCbor for i128 {
466    fn write_cbor<W: Writer>(&self, w: W) -> W::Output {
467        w.encode_number(&Number::Int(*self))
468    }
469}
470
471impl ReadCbor for i128 {
472    fn read_cbor_impl(cbor: &Cbor) -> Result<Self>
473    where
474        Self: Sized,
475    {
476        match cbor.try_number()? {
477            Number::Int(x) => Ok(x),
478            x => Err(CodecError::WrongNumber(x.get_type())),
479        }
480    }
481
482    fn fmt(f: &mut impl std::fmt::Write) -> std::fmt::Result {
483        write!(f, "i128")
484    }
485}
486
487impl WriteCbor for f64 {
488    fn write_cbor<W: Writer>(&self, w: W) -> W::Output {
489        w.encode_number(&Number::IEEE754(*self))
490    }
491}
492
493impl ReadCbor for f64 {
494    fn read_cbor_impl(cbor: &Cbor) -> Result<Self>
495    where
496        Self: Sized,
497    {
498        match cbor.try_number()? {
499            Number::IEEE754(x) => Ok(x),
500            x => Err(CodecError::WrongNumber(x.get_type())),
501        }
502    }
503
504    fn fmt(f: &mut impl std::fmt::Write) -> std::fmt::Result {
505        write!(f, "f64")
506    }
507}
508
509impl WriteCbor for Number<'_> {
510    fn write_cbor<W: Writer>(&self, w: W) -> W::Output {
511        w.encode_number(self)
512    }
513}
514
515impl ReadCbor for Number<'static> {
516    fn fmt(f: &mut impl std::fmt::Write) -> std::fmt::Result {
517        write!(f, "Number")
518    }
519
520    fn read_cbor_impl(cbor: &Cbor) -> Result<Self>
521    where
522        Self: Sized,
523    {
524        Ok(cbor.try_number()?.make_static())
525    }
526}
527
528impl WriteCbor for Cbor {
529    fn write_cbor<W: Writer>(&self, w: W) -> W::Output {
530        w.write_trusting(self.as_slice())
531    }
532}
533
534impl WriteCbor for CborOwned {
535    fn write_cbor<W: Writer>(&self, w: W) -> W::Output {
536        w.write_trusting(self.as_slice())
537    }
538}
539
540impl<'a> ReadCborBorrowed<'a> for Cbor {
541    fn read_cbor_borrowed(cbor: &'a Cbor) -> Result<Cow<'a, Self>> {
542        Ok(Cow::Borrowed(cbor))
543    }
544}
545
546impl ReadCbor for CborOwned {
547    fn fmt(f: &mut impl std::fmt::Write) -> std::fmt::Result {
548        write!(f, "Cbor")
549    }
550
551    fn read_cbor_impl(cbor: &Cbor) -> Result<Self>
552    where
553        Self: Sized,
554    {
555        Ok(<Cbor>::read_cbor_borrowed(cbor)?.into_owned())
556    }
557}
558
559macro_rules! tuple {
560    ($($t:ident),+) => {
561        impl<$($t: WriteCbor),*> WriteCbor for ($($t),*) {
562            #[allow(unused_assignments, non_snake_case)]
563            fn write_cbor<W: Writer>(&self, w: W) -> W::Output {
564                w.encode_array(|mut w| {
565                    let ($($t),*) = self;
566                    $(w = $t.write_cbor(w);)*
567                })
568            }
569        }
570        impl<$($t: ReadCbor),*> ReadCbor for ($($t),*) {
571            #[allow(unused_assignments, non_snake_case)]
572            fn read_cbor_impl(cbor: &Cbor) -> Result<Self> {
573                let d = cbor.decode().to_array().ok_or_else(|| CodecError::type_error("tuple", &cbor.tagged_item()))?;
574                let len = $({const $t: usize = 1; $t}+)* 0;
575                if d.len() < len {
576                    return Err(CodecError::tuple_size(len, d.len()));
577                }
578                let mut idx = 0;
579                $(
580                    let $t = $t::read_cbor(d[idx].as_ref())?;
581                    idx += 1;
582                )*
583                Ok(($($t),*))
584            }
585
586            fn fmt(f: &mut impl ::std::fmt::Write) -> std::fmt::Result {
587                write!(f, "(")?;
588                $(
589                    $t::fmt(f)?;
590                    write!(f, ", ")?;
591                )*
592                write!(f, ")")?;
593                Ok(())
594            }
595        }
596    };
597}
598
599tuple!(T0, T1);
600tuple!(T0, T1, T2);
601tuple!(T0, T1, T2, T3);
602tuple!(T0, T1, T2, T3, T4);
603tuple!(T0, T1, T2, T3, T4, T5);
604tuple!(T0, T1, T2, T3, T4, T5, T6);
605tuple!(T0, T1, T2, T3, T4, T5, T6, T7);
606tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8);
607tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9);
608
609impl<T: ?Sized + WriteCbor> WriteCbor for &T {
610    fn write_cbor<W: Writer>(&self, w: W) -> W::Output {
611        (*self).write_cbor(w)
612    }
613}
614
615#[macro_export]
616macro_rules! cbor_via {
617    ($t:ty => $u:ty: |$x:pat| -> $xx:expr, |$y:pat| -> $yy:expr) => {
618        impl $crate::codec::WriteCbor for $t {
619            fn write_cbor<W: $crate::Writer>(&self, w: W) -> W::Output {
620                let $x: &$t = self;
621                let u = $xx;
622                $crate::codec::WriteCbor::write_cbor(&u, w)
623            }
624        }
625        impl $crate::codec::ReadCbor for $t {
626            fn read_cbor_impl(cbor: &$crate::Cbor) -> $crate::codec::Result<Self>
627            where
628                Self: Sized,
629            {
630                let $y = <$u>::read_cbor(cbor)?;
631                $yy
632            }
633
634            fn fmt(f: &mut impl ::std::fmt::Write) -> std::fmt::Result {
635                write!(f, stringify!($t))
636            }
637        }
638    };
639    ($t:ty => $u:ty: INTO, $($rest:tt)*) => {
640        cbor_via!($t => $u: |x| -> <$u>::from(x), $($rest)*);
641    };
642    ($t:ty => $u:ty: |$x:ident| -> $xx:expr, FROM) => {
643        cbor_via!($t => $u: |$x| -> $xx, |x| -> Ok(x.into()));
644    };
645    ($t:ty => $u:ty) => {
646        cbor_via!($t => $u: INTO, FROM);
647    };
648}
649
650cbor_via!(u64 => i128: |x| -> i128::from(*x), |x| -> x.try_into().map_err(CodecError::custom));
651cbor_via!(i64 => i128: |x| -> i128::from(*x), |x| -> x.try_into().map_err(CodecError::custom));
652cbor_via!(u32 => i128: |x| -> i128::from(*x), |x| -> x.try_into().map_err(CodecError::custom));
653cbor_via!(i32 => i128: |x| -> i128::from(*x), |x| -> x.try_into().map_err(CodecError::custom));
654cbor_via!(u16 => i128: |x| -> i128::from(*x), |x| -> x.try_into().map_err(CodecError::custom));
655cbor_via!(i16 => i128: |x| -> i128::from(*x), |x| -> x.try_into().map_err(CodecError::custom));
656cbor_via!(f32 => f64: |x| -> f64::from(*x), |x| -> Ok(x as f32));
657
658#[cfg(feature = "libipld14")]
659mod impl_libipld14 {
660    use super::*;
661    use libipld14::{
662        cbor::DagCborCodec,
663        prelude::{Codec, Encode},
664        store::StoreParams,
665        Block, Cid, Ipld,
666    };
667    use smallvec::SmallVec;
668
669    impl WriteCbor for Cid {
670        fn write_cbor<W: Writer>(&self, w: W) -> W::Output {
671            let mut bytes = SmallVec::<[u8; 128]>::new();
672            self.write_bytes(&mut bytes).expect("writing to SmallVec");
673            w.write_bytes_chunked([&[0][..], &*bytes], [42])
674        }
675    }
676
677    impl ReadCbor for Cid {
678        fn fmt(f: &mut impl std::fmt::Write) -> std::fmt::Result {
679            write!(f, "Cid")
680        }
681
682        fn read_cbor_impl(cbor: &Cbor) -> Result<Self>
683        where
684            Self: Sized,
685        {
686            let decoded = cbor.tagged_item();
687            if let (Some(42), ItemKind::Bytes(b)) = (decoded.tags().single(), decoded.kind()) {
688                let b = b.as_cow();
689                if b.is_empty() {
690                    Err(CodecError::str("Cid cannot be empty"))
691                } else if b[0] != 0 {
692                    Err(CodecError::str("Cid must use identity encoding"))
693                } else {
694                    Cid::read_bytes(&b[1..]).map_err(CodecError::custom)
695                }
696            } else {
697                Err(CodecError::type_error("Cid", &decoded))
698            }
699        }
700    }
701
702    impl<S: StoreParams> WriteCbor for Block<S> {
703        fn write_cbor<W: Writer>(&self, w: W) -> W::Output {
704            (self.cid(), AsByteString(self.data())).write_cbor(w)
705        }
706    }
707
708    impl<S: StoreParams> ReadCbor for Block<S> {
709        fn fmt(f: &mut impl std::fmt::Write) -> std::fmt::Result {
710            write!(f, "Block")
711        }
712
713        fn read_cbor_impl(cbor: &Cbor) -> Result<Self>
714        where
715            Self: Sized,
716        {
717            let (cid, data) = <(Cid, AsByteString<Vec<u8>>)>::read_cbor(cbor)?;
718            Self::new(cid, data.0).map_err(|err| CodecError::str(err.to_string()))
719        }
720    }
721
722    impl WriteCbor for Ipld {
723        fn write_cbor<W: Writer>(&self, mut w: W) -> W::Output {
724            w.bytes(|b| self.encode(DagCborCodec, b))
725                .expect("WriteCbor for Ipld");
726            w.into_output()
727        }
728    }
729
730    impl ReadCbor for Ipld {
731        fn fmt(f: &mut impl std::fmt::Write) -> std::fmt::Result {
732            write!(f, "Ipld")
733        }
734
735        fn read_cbor_impl(cbor: &Cbor) -> Result<Self>
736        where
737            Self: Sized,
738        {
739            DagCborCodec
740                .decode(cbor.as_slice())
741                .map_err(|err| CodecError::Custom(err.into()))
742        }
743    }
744}
745
746#[cfg(test)]
747mod tests {
748    use super::*;
749    use crate::CborBuilder;
750    use std::convert::TryFrom;
751
752    #[derive(Debug, PartialEq)]
753    struct X(u64);
754    impl From<u64> for X {
755        fn from(x: u64) -> Self {
756            X(x)
757        }
758    }
759    impl From<&X> for u64 {
760        fn from(x: &X) -> Self {
761            x.0
762        }
763    }
764    mod priv1 {
765        use super::X;
766        cbor_via!(X => u64);
767    }
768
769    #[derive(Debug)]
770    struct Z;
771    impl std::fmt::Display for Z {
772        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
773            write!(f, "Z")
774        }
775    }
776    impl Error for Z {}
777    #[derive(Debug, PartialEq)]
778    struct Y(u64);
779    impl TryFrom<u64> for Y {
780        type Error = Z;
781        fn try_from(y: u64) -> std::result::Result<Self, Z> {
782            Ok(Y(y))
783        }
784    }
785    mod priv2 {
786        use crate::codec::CodecError;
787        use std::convert::TryInto;
788
789        cbor_via!(super::Y => u64: |x| -> x.0, |x| -> x.try_into().map_err(CodecError::custom));
790    }
791
792    #[test]
793    fn via() {
794        assert_eq!(X::name(), "X");
795        let bytes = X(5).write_cbor(CborBuilder::default());
796        let x = X::read_cbor(&*bytes).unwrap();
797        assert_eq!(x, X(5));
798
799        assert_eq!(Y::name(), "super::Y");
800        let bytes = Y(5).write_cbor(CborBuilder::default());
801        let y = Y::read_cbor(&*bytes).unwrap();
802        assert_eq!(y, Y(5));
803    }
804
805    #[test]
806    fn tuple() {
807        assert_eq!(<(String, u64)>::name(), "(String, u64, )");
808        let bytes = ("hello".to_owned(), 42u64).write_cbor(CborBuilder::default());
809        let tuple = <(String, u64)>::read_cbor(&*bytes).unwrap();
810        assert_eq!(tuple, ("hello".to_owned(), 42u64));
811    }
812
813    #[test]
814    fn vec() {
815        assert_eq!(<Vec<String>>::name(), "Vec<String>");
816        let x = vec!["hello".to_owned(), "world".to_owned()];
817        let bytes = x.write_cbor(CborBuilder::default());
818        let vec = <Vec<String>>::read_cbor(&*bytes).unwrap();
819        assert_eq!(vec, x);
820    }
821
822    #[test]
823    fn option() {
824        assert_eq!(<Option<String>>::name(), "Option<String>");
825        let x = Some("hello".to_owned());
826        let bytes = x.write_cbor(CborBuilder::default());
827        let opt = <Option<String>>::read_cbor(&*bytes).unwrap();
828        assert_eq!(opt, x);
829
830        let x = None;
831        let bytes = x.write_cbor(CborBuilder::default());
832        let opt = <Option<String>>::read_cbor(&*bytes).unwrap();
833        assert_eq!(opt, x);
834    }
835
836    #[test]
837    fn int() {
838        assert_eq!(u64::name(), "u64");
839        let bytes = 42u64.write_cbor(CborBuilder::default());
840        let x = u64::read_cbor(&*bytes).unwrap();
841        assert_eq!(x, 42);
842    }
843}