bounded_collections/
const_int.rs

1// Copyright (C) Parity Technologies (UK) Ltd.
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9use crate::{Get, TypedGet};
10use core::marker::PhantomData;
11
12// Numbers which have constant upper and lower bounds.
13trait ConstBounded<T> {
14	const MIN: T;
15	const MAX: T;
16}
17
18macro_rules! impl_const_bounded {
19	($bound:ty, $t:ty) => {
20		impl ConstBounded<$bound> for $t {
21			const MIN: $bound = <$t>::MIN as $bound;
22			const MAX: $bound = <$t>::MAX as $bound;
23		}
24	};
25}
26
27impl_const_bounded!(u128, u8);
28impl_const_bounded!(u128, u16);
29impl_const_bounded!(u128, u32);
30impl_const_bounded!(u128, u64);
31impl_const_bounded!(u128, u128);
32impl_const_bounded!(u128, usize);
33
34impl_const_bounded!(i128, i8);
35impl_const_bounded!(i128, i16);
36impl_const_bounded!(i128, i32);
37impl_const_bounded!(i128, i64);
38impl_const_bounded!(i128, i128);
39
40// Check whether a unsigned integer is within the bounds of a type.
41struct CheckOverflowU128<T: ConstBounded<u128>, const N: u128>(PhantomData<T>);
42
43impl<T: ConstBounded<u128>, const N: u128> CheckOverflowU128<T, N> {
44	const ASSERTION: () = assert!(N >= T::MIN && N <= T::MAX);
45}
46
47// Check whether an integer is within the bounds of a type.
48struct CheckOverflowI128<T: ConstBounded<i128>, const N: i128>(PhantomData<T>);
49
50impl<T: ConstBounded<i128>, const N: i128> CheckOverflowI128<T, N> {
51	const ASSERTION: () = assert!(N >= T::MIN && N <= T::MAX);
52}
53
54/// Const getter for unsigned integers.
55///
56/// # Compile-time checks
57///
58/// ```compile_fail
59/// # use bounded_collections::{ConstUint, Get};
60/// let _ = <ConstUint<256> as Get<u8>>::get();
61/// ```
62#[derive(Default, Clone)]
63pub struct ConstUint<const N: u128>;
64
65impl<const N: u128> core::fmt::Debug for ConstUint<N> {
66	fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
67		fmt.write_str(&alloc::format!("ConstUint<{}>", N))
68	}
69}
70
71impl<const N: u128> TypedGet for ConstUint<N> {
72	type Type = u128;
73	fn get() -> u128 {
74		N
75	}
76}
77
78/// Const getter for signed integers.
79#[derive(Default, Clone)]
80pub struct ConstInt<const N: i128>;
81
82impl<const N: i128> core::fmt::Debug for ConstInt<N> {
83	fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
84		fmt.write_str(&alloc::format!("ConstInt<{}>", N))
85	}
86}
87
88impl<const N: i128> TypedGet for ConstInt<N> {
89	type Type = i128;
90	fn get() -> i128 {
91		N
92	}
93}
94
95macro_rules! impl_const_int {
96	($t:ident, $check:ident, $bound:ty, $target:ty) => {
97		impl<const N: $bound> Get<$target> for $t<N> {
98			fn get() -> $target {
99				let _ = <$check<$target, N>>::ASSERTION;
100				N as $target
101			}
102		}
103		impl<const N: $bound> Get<Option<$target>> for $t<N> {
104			fn get() -> Option<$target> {
105				let _ = <$check<$target, N>>::ASSERTION;
106				Some(N as $target)
107			}
108		}
109	};
110}
111
112impl_const_int!(ConstUint, CheckOverflowU128, u128, u8);
113impl_const_int!(ConstUint, CheckOverflowU128, u128, u16);
114impl_const_int!(ConstUint, CheckOverflowU128, u128, u32);
115impl_const_int!(ConstUint, CheckOverflowU128, u128, u64);
116impl_const_int!(ConstUint, CheckOverflowU128, u128, u128);
117impl_const_int!(ConstUint, CheckOverflowU128, u128, usize);
118
119impl_const_int!(ConstInt, CheckOverflowI128, i128, i8);
120impl_const_int!(ConstInt, CheckOverflowI128, i128, i16);
121impl_const_int!(ConstInt, CheckOverflowI128, i128, i32);
122impl_const_int!(ConstInt, CheckOverflowI128, i128, i64);
123impl_const_int!(ConstInt, CheckOverflowI128, i128, i128);
124
125#[cfg(test)]
126mod tests {
127	use super::*;
128
129	#[test]
130	fn const_uint_works() {
131		assert_eq!(<ConstUint<42> as Get<u8>>::get(), 42);
132		assert_eq!(<ConstUint<42> as Get<Option<u8>>>::get(), Some(42));
133		assert_eq!(<ConstUint<42> as Get<u16>>::get(), 42);
134		assert_eq!(<ConstUint<42> as Get<u32>>::get(), 42);
135		assert_eq!(<ConstUint<42> as Get<u64>>::get(), 42);
136		assert_eq!(<ConstUint<42> as Get<u128>>::get(), 42);
137		assert_eq!(<ConstUint<42> as Get<usize>>::get(), 42);
138		assert_eq!(<ConstUint<42> as TypedGet>::get(), 42);
139		// compile-time error
140		// assert_eq!(<ConstUint<256> as Get<u8>>::get() as u128, 256);
141	}
142
143	#[test]
144	fn const_int_works() {
145		assert_eq!(<ConstInt<-42> as Get<i8>>::get(), -42);
146		assert_eq!(<ConstInt<-42> as Get<Option<i8>>>::get(), Some(-42));
147		assert_eq!(<ConstInt<-42> as Get<i16>>::get(), -42);
148		assert_eq!(<ConstInt<-42> as Get<i32>>::get(), -42);
149		assert_eq!(<ConstInt<-42> as Get<i64>>::get(), -42);
150		assert_eq!(<ConstInt<-42> as Get<i128>>::get(), -42);
151		assert_eq!(<ConstInt<-42> as TypedGet>::get(), -42);
152	}
153}