icrc_cbor/
nat.rs

1use candid::Nat;
2use minicbor::data::Tag;
3use minicbor::decode::{Decoder, Error};
4use minicbor::encode::{Encoder, Write};
5use num_bigint::BigUint;
6use num_traits::ToPrimitive;
7
8pub fn decode<Ctx>(d: &mut Decoder<'_>, _ctx: &mut Ctx) -> Result<Nat, Error> {
9    let pos = d.position();
10    match d.u64() {
11        Ok(n) => return Ok(Nat::from(n)),
12        Err(e) if e.is_type_mismatch() => {
13            d.set_position(pos);
14        }
15        Err(e) => return Err(e),
16    }
17    let tag: Tag = d.tag()?;
18    if tag != Tag::PosBignum {
19        return Err(Error::message(
20            "failed to parse Nat: expected the PosBignum tag",
21        ));
22    }
23    let be_bytes = d.bytes()?;
24    Ok(Nat(BigUint::from_bytes_be(be_bytes)))
25}
26
27pub fn encode<Ctx, W: Write>(
28    v: &Nat,
29    e: &mut Encoder<W>,
30    _ctx: &mut Ctx,
31) -> Result<(), minicbor::encode::Error<W::Error>> {
32    if let Some(n) = v.0.to_u32() {
33        return e.u32(n)?.ok();
34    }
35    match v.0.to_u64() {
36        Some(n) => e.u64(n)?.ok(),
37        None => e.tag(Tag::PosBignum)?.bytes(&v.0.to_bytes_be())?.ok(),
38    }
39}
40
41pub mod option {
42    use super::*;
43    use minicbor::{Decode, Encode};
44
45    #[derive(Decode, Encode)]
46    #[cbor(transparent)]
47    struct CborNat(#[cbor(n(0), with = "crate::nat")] pub Nat);
48
49    pub fn decode<Ctx>(d: &mut Decoder<'_>, ctx: &mut Ctx) -> Result<Option<Nat>, Error> {
50        Ok(Option::<CborNat>::decode(d, ctx)?.map(|n| n.0))
51    }
52
53    pub fn encode<Ctx, W: Write>(
54        v: &Option<Nat>,
55        e: &mut Encoder<W>,
56        ctx: &mut Ctx,
57    ) -> Result<(), minicbor::encode::Error<W::Error>> {
58        v.clone().map(CborNat).encode(e, ctx)
59    }
60}