ciborium/value/
integer.rs1use core::cmp::Ordering;
3
4macro_rules! implfrom {
5    ($( $(#[$($attr:meta)+])? $t:ident)+) => {
6        $(
7            $(#[$($attr)+])?
8            impl From<$t> for Integer {
9                #[inline]
10                fn from(value: $t) -> Self {
11                    Self(value as _)
12                }
13            }
14
15            impl TryFrom<Integer> for $t {
16                type Error = core::num::TryFromIntError;
17
18                #[inline]
19                fn try_from(value: Integer) -> Result<Self, Self::Error> {
20                    $t::try_from(value.0)
21                }
22            }
23        )+
24    };
25}
26
27#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
35pub struct Integer(i128);
36
37impl Integer {
38    fn canonical_len(&self) -> usize {
42        let x = self.0;
43
44        if let Ok(x) = u8::try_from(x) {
45            if x < 24 {
46                1
47            } else {
48                2
49            }
50        } else if let Ok(x) = i8::try_from(x) {
51            if x >= -24i8 {
52                1
53            } else {
54                2
55            }
56        } else if u16::try_from(x).is_ok() || i16::try_from(x).is_ok() {
57            3
58        } else if u32::try_from(x).is_ok() || i32::try_from(x).is_ok() {
59            5
60        } else if u64::try_from(x).is_ok() || i64::try_from(x).is_ok() {
61            9
62        } else {
63            x.to_be_bytes().len() + 1
67        }
68    }
69
70    pub fn canonical_cmp(&self, other: &Self) -> Ordering {
72        match self.canonical_len().cmp(&other.canonical_len()) {
73            Ordering::Equal => {
74                match (self.0.is_negative(), other.0.is_negative()) {
76                    (false, true) => Ordering::Less,
77                    (true, false) => Ordering::Greater,
78                    (true, true) => {
79                        match self.0.cmp(&other.0) {
82                            Ordering::Less => Ordering::Greater,
83                            Ordering::Equal => Ordering::Equal,
84                            Ordering::Greater => Ordering::Less,
85                        }
86                    }
87                    (_, _) => self.0.cmp(&other.0),
88                }
89            }
90            x => x,
91        }
92    }
93}
94
95implfrom! {
96    u8 u16 u32 u64
97    i8 i16 i32 i64
98
99    #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
100    usize
101
102    #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
103    isize
104}
105
106impl TryFrom<i128> for Integer {
107    type Error = core::num::TryFromIntError;
108
109    #[inline]
110    fn try_from(value: i128) -> Result<Self, Self::Error> {
111        u64::try_from(match value.is_negative() {
112            false => value,
113            true => value ^ !0,
114        })?;
115
116        Ok(Integer(value))
117    }
118}
119
120impl TryFrom<u128> for Integer {
121    type Error = core::num::TryFromIntError;
122
123    #[inline]
124    fn try_from(value: u128) -> Result<Self, Self::Error> {
125        Ok(Self(u64::try_from(value)?.into()))
126    }
127}
128
129impl From<Integer> for i128 {
130    #[inline]
131    fn from(value: Integer) -> Self {
132        value.0
133    }
134}
135
136impl TryFrom<Integer> for u128 {
137    type Error = core::num::TryFromIntError;
138
139    #[inline]
140    fn try_from(value: Integer) -> Result<Self, Self::Error> {
141        u128::try_from(value.0)
142    }
143}