dcbor 0.25.2

Deterministic CBOR ("dCBOR") for Rust.
Documentation
import_stdlib!();

use super::{
    CBORCase,
    varint::{EncodeVarInt, MajorType},
};
use crate::{CBOR, Error, Result};

macro_rules! impl_cbor {
    ($type:ty) => {
        impl From64 for $type {
            fn cbor_data(&self) -> Vec<u8> {
                #[allow(unused_comparisons)]
                if *self < 0 {
                    let n = (-1 - (*self as i128)) as u64;
                    n.encode_varint(MajorType::Negative)
                } else {
                    let n = *self as u64;
                    n.encode_varint(MajorType::Unsigned)
                }
            }
        }

        impl From<$type> for CBOR {
            fn from(value: $type) -> Self {
                #[allow(unused_comparisons)]
                if value < 0 {
                    CBORCase::Negative((-1 - (value as i128)) as u64).into()
                } else {
                    CBORCase::Unsigned(value as u64).into()
                }
            }
        }

        impl TryFrom<CBOR> for $type {
            type Error = Error;

            fn try_from(cbor: CBOR) -> Result<Self> {
                match cbor.into_case() {
                    CBORCase::Unsigned(n) => {
                        Self::from_u64(n, <$type>::MAX as u64, |x| x as $type)
                    }
                    CBORCase::Negative(n) => {
                        let a = Self::from_u64(n, <$type>::MAX as u64, |x| {
                            x as $type
                        })? as i128;
                        Ok((-1 - a) as $type)
                    }
                    _ => return Err(Error::WrongType),
                }
            }
        }
    };
}

impl_cbor!(u8);
impl_cbor!(u16);
impl_cbor!(u32);
impl_cbor!(u64);
impl_cbor!(usize);
impl_cbor!(i8);
impl_cbor!(i16);
impl_cbor!(i32);
impl_cbor!(i64);

pub trait From64 {
    fn cbor_data(&self) -> Vec<u8>;

    fn from_u64<F>(n: u64, max: u64, f: F) -> Result<Self>
    where
        F: Fn(u64) -> Self,
        Self: Sized,
    {
        if n > max {
            return Err(Error::OutOfRange);
        }
        Ok(f(n))
    }

    #[allow(dead_code)]
    fn from_i64<F>(n: i64, min: i64, max: i64, f: F) -> Result<Self>
    where
        F: Fn(i64) -> Self,
        Self: Sized,
    {
        if n > max || n > min {
            return Err(Error::OutOfRange);
        }
        Ok(f(n))
    }
}