bounded_collections/
const_int.rsuse crate::{Get, TypedGet};
use core::marker::PhantomData;
trait ConstBounded<T> {
const MIN: T;
const MAX: T;
}
macro_rules! impl_const_bounded {
($bound:ty, $t:ty) => {
impl ConstBounded<$bound> for $t {
const MIN: $bound = <$t>::MIN as $bound;
const MAX: $bound = <$t>::MAX as $bound;
}
};
}
impl_const_bounded!(u128, u8);
impl_const_bounded!(u128, u16);
impl_const_bounded!(u128, u32);
impl_const_bounded!(u128, u64);
impl_const_bounded!(u128, u128);
impl_const_bounded!(u128, usize);
impl_const_bounded!(i128, i8);
impl_const_bounded!(i128, i16);
impl_const_bounded!(i128, i32);
impl_const_bounded!(i128, i64);
impl_const_bounded!(i128, i128);
struct CheckOverflowU128<T: ConstBounded<u128>, const N: u128>(PhantomData<T>);
impl<T: ConstBounded<u128>, const N: u128> CheckOverflowU128<T, N> {
const ASSERTION: () = assert!(N >= T::MIN && N <= T::MAX);
}
struct CheckOverflowI128<T: ConstBounded<i128>, const N: i128>(PhantomData<T>);
impl<T: ConstBounded<i128>, const N: i128> CheckOverflowI128<T, N> {
const ASSERTION: () = assert!(N >= T::MIN && N <= T::MAX);
}
#[derive(Default, Clone)]
pub struct ConstUint<const N: u128>;
impl<const N: u128> core::fmt::Debug for ConstUint<N> {
fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
fmt.write_str(&alloc::format!("ConstUint<{}>", N))
}
}
impl<const N: u128> TypedGet for ConstUint<N> {
type Type = u128;
fn get() -> u128 {
N
}
}
#[derive(Default, Clone)]
pub struct ConstInt<const N: i128>;
impl<const N: i128> core::fmt::Debug for ConstInt<N> {
fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
fmt.write_str(&alloc::format!("ConstInt<{}>", N))
}
}
impl<const N: i128> TypedGet for ConstInt<N> {
type Type = i128;
fn get() -> i128 {
N
}
}
macro_rules! impl_const_int {
($t:ident, $check:ident, $bound:ty, $target:ty) => {
impl<const N: $bound> Get<$target> for $t<N> {
fn get() -> $target {
let _ = <$check<$target, N>>::ASSERTION;
N as $target
}
}
impl<const N: $bound> Get<Option<$target>> for $t<N> {
fn get() -> Option<$target> {
let _ = <$check<$target, N>>::ASSERTION;
Some(N as $target)
}
}
};
}
impl_const_int!(ConstUint, CheckOverflowU128, u128, u8);
impl_const_int!(ConstUint, CheckOverflowU128, u128, u16);
impl_const_int!(ConstUint, CheckOverflowU128, u128, u32);
impl_const_int!(ConstUint, CheckOverflowU128, u128, u64);
impl_const_int!(ConstUint, CheckOverflowU128, u128, u128);
impl_const_int!(ConstUint, CheckOverflowU128, u128, usize);
impl_const_int!(ConstInt, CheckOverflowI128, i128, i8);
impl_const_int!(ConstInt, CheckOverflowI128, i128, i16);
impl_const_int!(ConstInt, CheckOverflowI128, i128, i32);
impl_const_int!(ConstInt, CheckOverflowI128, i128, i64);
impl_const_int!(ConstInt, CheckOverflowI128, i128, i128);
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn const_uint_works() {
assert_eq!(<ConstUint<42> as Get<u8>>::get(), 42);
assert_eq!(<ConstUint<42> as Get<Option<u8>>>::get(), Some(42));
assert_eq!(<ConstUint<42> as Get<u16>>::get(), 42);
assert_eq!(<ConstUint<42> as Get<u32>>::get(), 42);
assert_eq!(<ConstUint<42> as Get<u64>>::get(), 42);
assert_eq!(<ConstUint<42> as Get<u128>>::get(), 42);
assert_eq!(<ConstUint<42> as Get<usize>>::get(), 42);
assert_eq!(<ConstUint<42> as TypedGet>::get(), 42);
}
#[test]
fn const_int_works() {
assert_eq!(<ConstInt<-42> as Get<i8>>::get(), -42);
assert_eq!(<ConstInt<-42> as Get<Option<i8>>>::get(), Some(-42));
assert_eq!(<ConstInt<-42> as Get<i16>>::get(), -42);
assert_eq!(<ConstInt<-42> as Get<i32>>::get(), -42);
assert_eq!(<ConstInt<-42> as Get<i64>>::get(), -42);
assert_eq!(<ConstInt<-42> as Get<i128>>::get(), -42);
assert_eq!(<ConstInt<-42> as TypedGet>::get(), -42);
}
}