summaryrefslogtreecommitdiff
path: root/vendor/num-conv/src/lib.rs
diff options
context:
space:
mode:
authormo khan <mo@mokhan.ca>2025-07-02 18:36:06 -0600
committermo khan <mo@mokhan.ca>2025-07-02 18:36:06 -0600
commit8cdfa445d6629ffef4cb84967ff7017654045bc2 (patch)
tree22f0b0907c024c78d26a731e2e1f5219407d8102 /vendor/num-conv/src/lib.rs
parent4351c74c7c5f97156bc94d3a8549b9940ac80e3f (diff)
chore: add vendor directory
Diffstat (limited to 'vendor/num-conv/src/lib.rs')
-rw-r--r--vendor/num-conv/src/lib.rs329
1 files changed, 329 insertions, 0 deletions
diff --git a/vendor/num-conv/src/lib.rs b/vendor/num-conv/src/lib.rs
new file mode 100644
index 00000000..cbf3ff21
--- /dev/null
+++ b/vendor/num-conv/src/lib.rs
@@ -0,0 +1,329 @@
+//! `num_conv` is a crate to convert between integer types without using `as` casts. This provides
+//! better certainty when refactoring, makes the exact behavior of code more explicit, and allows
+//! using turbofish syntax.
+
+#![no_std]
+
+/// Anonymously import all extension traits.
+///
+/// This allows you to use the methods without worrying about polluting the namespace or importing
+/// them individually.
+///
+/// ```rust
+/// use num_conv::prelude::*;
+/// ```
+pub mod prelude {
+ pub use crate::{CastSigned as _, CastUnsigned as _, Extend as _, Truncate as _};
+}
+
+mod sealed {
+ pub trait Integer {}
+
+ macro_rules! impl_integer {
+ ($($t:ty)*) => {$(
+ impl Integer for $t {}
+ )*};
+ }
+
+ impl_integer! {
+ u8 u16 u32 u64 u128 usize
+ i8 i16 i32 i64 i128 isize
+ }
+
+ pub trait ExtendTargetSealed<T> {
+ fn extend(self) -> T;
+ }
+
+ pub trait TruncateTargetSealed<T> {
+ fn truncate(self) -> T;
+ }
+}
+
+/// Cast to a signed integer of the same size.
+///
+/// This trait is implemented for all integers. Unsigned to signed casts are equivalent to
+/// `0.wrapping_add_signed(value)`, while signed to signed casts are an identity conversion.
+///
+/// ```rust
+/// # use num_conv::CastSigned;
+/// assert_eq!(u8::MAX.cast_signed(), -1_i8);
+/// assert_eq!(u16::MAX.cast_signed(), -1_i16);
+/// assert_eq!(u32::MAX.cast_signed(), -1_i32);
+/// assert_eq!(u64::MAX.cast_signed(), -1_i64);
+/// assert_eq!(u128::MAX.cast_signed(), -1_i128);
+/// assert_eq!(usize::MAX.cast_signed(), -1_isize);
+/// ```
+///
+/// ```rust
+/// # use num_conv::CastSigned;
+/// assert_eq!(0_i8.cast_signed(), 0_i8);
+/// assert_eq!(0_i16.cast_signed(), 0_i16);
+/// assert_eq!(0_i32.cast_signed(), 0_i32);
+/// assert_eq!(0_i64.cast_signed(), 0_i64);
+/// assert_eq!(0_i128.cast_signed(), 0_i128);
+/// assert_eq!(0_isize.cast_signed(), 0_isize);
+/// ```
+pub trait CastSigned: sealed::Integer {
+ /// The signed integer type with the same size as `Self`.
+ type Signed;
+
+ /// Cast an integer to the signed integer of the same size.
+ fn cast_signed(self) -> Self::Signed;
+}
+
+/// Cast to an unsigned integer of the same size.
+///
+/// This trait is implemented for all integers. Signed to unsigned casts are equivalent to
+/// `0.wrapping_add_unsigned(value)`, while unsigned to unsigned casts are an identity conversion.
+///
+/// ```rust
+/// # use num_conv::CastUnsigned;
+/// assert_eq!((-1_i8).cast_unsigned(), u8::MAX);
+/// assert_eq!((-1_i16).cast_unsigned(), u16::MAX);
+/// assert_eq!((-1_i32).cast_unsigned(), u32::MAX);
+/// assert_eq!((-1_i64).cast_unsigned(), u64::MAX);
+/// assert_eq!((-1_i128).cast_unsigned(), u128::MAX);
+/// assert_eq!((-1_isize).cast_unsigned(), usize::MAX);
+/// ```
+///
+/// ```rust
+/// # use num_conv::CastUnsigned;
+/// assert_eq!(0_u8.cast_unsigned(), 0_u8);
+/// assert_eq!(0_u16.cast_unsigned(), 0_u16);
+/// assert_eq!(0_u32.cast_unsigned(), 0_u32);
+/// assert_eq!(0_u64.cast_unsigned(), 0_u64);
+/// assert_eq!(0_u128.cast_unsigned(), 0_u128);
+/// assert_eq!(0_usize.cast_unsigned(), 0_usize);
+/// ```
+pub trait CastUnsigned: sealed::Integer {
+ /// The unsigned integer type with the same size as `Self`.
+ type Unsigned;
+
+ /// Cast an integer to the unsigned integer of the same size.
+ fn cast_unsigned(self) -> Self::Unsigned;
+}
+
+/// A type that can be used with turbofish syntax in [`Extend::extend`].
+///
+/// It is unlikely that you will want to use this trait directly. You are probably looking for the
+/// [`Extend`] trait.
+pub trait ExtendTarget<T>: sealed::ExtendTargetSealed<T> {}
+
+/// A type that can be used with turbofish syntax in [`Truncate::truncate`].
+///
+/// It is unlikely that you will want to use this trait directly. You are probably looking for the
+/// [`Truncate`] trait.
+pub trait TruncateTarget<T>: sealed::TruncateTargetSealed<T> {}
+
+/// Extend to an integer of the same size or larger, preserving its value.
+///
+/// ```rust
+/// # use num_conv::Extend;
+/// assert_eq!(0_u8.extend::<u16>(), 0_u16);
+/// assert_eq!(0_u16.extend::<u32>(), 0_u32);
+/// assert_eq!(0_u32.extend::<u64>(), 0_u64);
+/// assert_eq!(0_u64.extend::<u128>(), 0_u128);
+/// ```
+///
+/// ```rust
+/// # use num_conv::Extend;
+/// assert_eq!((-1_i8).extend::<i16>(), -1_i16);
+/// assert_eq!((-1_i16).extend::<i32>(), -1_i32);
+/// assert_eq!((-1_i32).extend::<i64>(), -1_i64);
+/// assert_eq!((-1_i64).extend::<i128>(), -1_i128);
+/// ```
+pub trait Extend: sealed::Integer {
+ /// Extend an integer to an integer of the same size or larger, preserving its value.
+ fn extend<T>(self) -> T
+ where
+ Self: ExtendTarget<T>;
+}
+
+impl<T: sealed::Integer> Extend for T {
+ fn extend<U>(self) -> U
+ where
+ T: ExtendTarget<U>,
+ {
+ sealed::ExtendTargetSealed::extend(self)
+ }
+}
+
+/// Truncate to an integer of the same size or smaller, preserving the least significant bits.
+///
+/// ```rust
+/// # use num_conv::Truncate;
+/// assert_eq!(u16::MAX.truncate::<u8>(), u8::MAX);
+/// assert_eq!(u32::MAX.truncate::<u16>(), u16::MAX);
+/// assert_eq!(u64::MAX.truncate::<u32>(), u32::MAX);
+/// assert_eq!(u128::MAX.truncate::<u64>(), u64::MAX);
+/// ```
+///
+/// ```rust
+/// # use num_conv::Truncate;
+/// assert_eq!((-1_i16).truncate::<i8>(), -1_i8);
+/// assert_eq!((-1_i32).truncate::<i16>(), -1_i16);
+/// assert_eq!((-1_i64).truncate::<i32>(), -1_i32);
+/// assert_eq!((-1_i128).truncate::<i64>(), -1_i64);
+/// ```
+pub trait Truncate: sealed::Integer {
+ /// Truncate an integer to an integer of the same size or smaller, preserving the least
+ /// significant bits.
+ fn truncate<T>(self) -> T
+ where
+ Self: TruncateTarget<T>;
+}
+
+impl<T: sealed::Integer> Truncate for T {
+ fn truncate<U>(self) -> U
+ where
+ T: TruncateTarget<U>,
+ {
+ sealed::TruncateTargetSealed::truncate(self)
+ }
+}
+
+macro_rules! impl_cast_signed {
+ ($($($from:ty),+ => $to:ty;)*) => {$($(
+ const _: () = assert!(
+ core::mem::size_of::<$from>() == core::mem::size_of::<$to>(),
+ concat!(
+ "cannot cast ",
+ stringify!($from),
+ " to ",
+ stringify!($to),
+ " because they are different sizes"
+ )
+ );
+
+ impl CastSigned for $from {
+ type Signed = $to;
+ fn cast_signed(self) -> Self::Signed {
+ self as _
+ }
+ }
+ )+)*};
+}
+
+macro_rules! impl_cast_unsigned {
+ ($($($from:ty),+ => $to:ty;)*) => {$($(
+ const _: () = assert!(
+ core::mem::size_of::<$from>() == core::mem::size_of::<$to>(),
+ concat!(
+ "cannot cast ",
+ stringify!($from),
+ " to ",
+ stringify!($to),
+ " because they are different sizes"
+ )
+ );
+
+ impl CastUnsigned for $from {
+ type Unsigned = $to;
+ fn cast_unsigned(self) -> Self::Unsigned {
+ self as _
+ }
+ }
+ )+)*};
+}
+
+macro_rules! impl_extend {
+ ($($from:ty => $($to:ty),+;)*) => {$($(
+ const _: () = assert!(
+ core::mem::size_of::<$from>() <= core::mem::size_of::<$to>(),
+ concat!(
+ "cannot extend ",
+ stringify!($from),
+ " to ",
+ stringify!($to),
+ " because ",
+ stringify!($from),
+ " is larger than ",
+ stringify!($to)
+ )
+ );
+
+ impl sealed::ExtendTargetSealed<$to> for $from {
+ fn extend(self) -> $to {
+ self as _
+ }
+ }
+
+ impl ExtendTarget<$to> for $from {}
+ )+)*};
+}
+
+macro_rules! impl_truncate {
+ ($($($from:ty),+ => $to:ty;)*) => {$($(
+ const _: () = assert!(
+ core::mem::size_of::<$from>() >= core::mem::size_of::<$to>(),
+ concat!(
+ "cannot truncate ",
+ stringify!($from),
+ " to ",
+ stringify!($to),
+ " because ",
+ stringify!($from),
+ " is smaller than ",
+ stringify!($to)
+ )
+ );
+
+ impl sealed::TruncateTargetSealed<$to> for $from {
+ fn truncate(self) -> $to {
+ self as _
+ }
+ }
+
+ impl TruncateTarget<$to> for $from {}
+ )+)*};
+}
+
+impl_cast_signed! {
+ u8, i8 => i8;
+ u16, i16 => i16;
+ u32, i32 => i32;
+ u64, i64 => i64;
+ u128, i128 => i128;
+ usize, isize => isize;
+}
+
+impl_cast_unsigned! {
+ u8, i8 => u8;
+ u16, i16 => u16;
+ u32, i32 => u32;
+ u64, i64 => u64;
+ u128, i128 => u128;
+ usize, isize => usize;
+}
+
+impl_extend! {
+ u8 => u8, u16, u32, u64, u128, usize;
+ u16 => u16, u32, u64, u128, usize;
+ u32 => u32, u64, u128;
+ u64 => u64, u128;
+ u128 => u128;
+ usize => usize;
+
+ i8 => i8, i16, i32, i64, i128, isize;
+ i16 => i16, i32, i64, i128, isize;
+ i32 => i32, i64, i128;
+ i64 => i64, i128;
+ i128 => i128;
+ isize => isize;
+}
+
+impl_truncate! {
+ u8, u16, u32, u64, u128, usize => u8;
+ u16, u32, u64, u128, usize => u16;
+ u32, u64, u128 => u32;
+ u64, u128 => u64;
+ u128 => u128;
+ usize => usize;
+
+ i8, i16, i32, i64, i128, isize => i8;
+ i16, i32, i64, i128, isize => i16;
+ i32, i64, i128 => i32;
+ i64, i128 => i64;
+ i128 => i128;
+ isize => isize;
+}