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}