summaryrefslogtreecommitdiffstats
path: root/vendor/ciborium/src/value/integer.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/ciborium/src/value/integer.rs')
-rw-r--r--vendor/ciborium/src/value/integer.rs143
1 files changed, 143 insertions, 0 deletions
diff --git a/vendor/ciborium/src/value/integer.rs b/vendor/ciborium/src/value/integer.rs
new file mode 100644
index 000000000..ef6ea3df0
--- /dev/null
+++ b/vendor/ciborium/src/value/integer.rs
@@ -0,0 +1,143 @@
+// SPDX-License-Identifier: Apache-2.0
+use core::cmp::Ordering;
+
+macro_rules! implfrom {
+ ($( $(#[$($attr:meta)+])? $t:ident)+) => {
+ $(
+ $(#[$($attr)+])?
+ impl From<$t> for Integer {
+ #[inline]
+ fn from(value: $t) -> Self {
+ Self(value as _)
+ }
+ }
+
+ impl TryFrom<Integer> for $t {
+ type Error = core::num::TryFromIntError;
+
+ #[inline]
+ fn try_from(value: Integer) -> Result<Self, Self::Error> {
+ $t::try_from(value.0)
+ }
+ }
+ )+
+ };
+}
+
+/// An abstract integer value
+///
+/// This opaque type represents an integer value which can be encoded in CBOR
+/// without resulting to big integer encoding. Larger values may be encoded
+/// using the big integer encoding as described in the CBOR RFC. See the
+/// implementations for 128-bit integer conversions on `Value` for more
+/// details.
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
+pub struct Integer(i128);
+
+impl Integer {
+ /// Returns the canonical length this integer will have when serialized to bytes.
+ /// This is called `canonical` as it is only used for canonically comparing two
+ /// values. It shouldn't be used in any other context.
+ fn canonical_len(&self) -> usize {
+ let x = self.0;
+
+ if let Ok(x) = u8::try_from(x) {
+ if x < 24 {
+ 1
+ } else {
+ 2
+ }
+ } else if let Ok(x) = i8::try_from(x) {
+ if x >= -24i8 {
+ 1
+ } else {
+ 2
+ }
+ } else if u16::try_from(x).is_ok() || i16::try_from(x).is_ok() {
+ 3
+ } else if u32::try_from(x).is_ok() || i32::try_from(x).is_ok() {
+ 5
+ } else if u64::try_from(x).is_ok() || i64::try_from(x).is_ok() {
+ 9
+ } else {
+ // Ciborium serializes u128/i128 as BigPos if they don't fit in 64 bits.
+ // In this special case we have to calculate the length.
+ // The Tag itself will always be 1 byte.
+ x.to_be_bytes().len() + 1
+ }
+ }
+
+ /// Compare two integers as if we were to serialize them, but more efficiently.
+ pub fn canonical_cmp(&self, other: &Self) -> Ordering {
+ match self.canonical_len().cmp(&other.canonical_len()) {
+ Ordering::Equal => {
+ // Negative numbers are higher in byte-order than positive numbers.
+ match (self.0.is_negative(), other.0.is_negative()) {
+ (false, true) => Ordering::Less,
+ (true, false) => Ordering::Greater,
+ (true, true) => {
+ // For negative numbers the byte order puts numbers closer to 0 which
+ // are lexically higher, lower. So -1 < -2 when sorting by be_bytes().
+ match self.0.cmp(&other.0) {
+ Ordering::Less => Ordering::Greater,
+ Ordering::Equal => Ordering::Equal,
+ Ordering::Greater => Ordering::Less,
+ }
+ }
+ (_, _) => self.0.cmp(&other.0),
+ }
+ }
+ x => x,
+ }
+ }
+}
+
+implfrom! {
+ u8 u16 u32 u64
+ i8 i16 i32 i64
+
+ #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
+ usize
+
+ #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
+ isize
+}
+
+impl TryFrom<i128> for Integer {
+ type Error = core::num::TryFromIntError;
+
+ #[inline]
+ fn try_from(value: i128) -> Result<Self, Self::Error> {
+ u64::try_from(match value.is_negative() {
+ false => value,
+ true => value ^ !0,
+ })?;
+
+ Ok(Integer(value))
+ }
+}
+
+impl TryFrom<u128> for Integer {
+ type Error = core::num::TryFromIntError;
+
+ #[inline]
+ fn try_from(value: u128) -> Result<Self, Self::Error> {
+ Ok(Self(u64::try_from(value)?.into()))
+ }
+}
+
+impl From<Integer> for i128 {
+ #[inline]
+ fn from(value: Integer) -> Self {
+ value.0
+ }
+}
+
+impl TryFrom<Integer> for u128 {
+ type Error = core::num::TryFromIntError;
+
+ #[inline]
+ fn try_from(value: Integer) -> Result<Self, Self::Error> {
+ u128::try_from(value.0)
+ }
+}