From 31ae2341bab13604013419a7c3627058e453f162 Mon Sep 17 00:00:00 2001 From: Jeeyong Um Date: Mon, 4 Nov 2024 21:55:34 +0900 Subject: [PATCH] bounded-collections: Add Const(Int|Uint) for generic const getter support (#878) * bounded-collections: Add Const(Int|Uint) for generic const getter support * bounded-collections: Update changelog * bounded-collections: Clean up helper types for ConstUint * bounded-collections: Fix broken compile-time check * bounded-collections: Add compile_fail doc test for overflown ConstUint * bounded-collections: Address review comments --------- Co-authored-by: ordian --- bounded-collections/CHANGELOG.md | 3 + bounded-collections/src/const_int.rs | 153 +++++++++++++++++++++++++++ bounded-collections/src/lib.rs | 2 + 3 files changed, 158 insertions(+) create mode 100644 bounded-collections/src/const_int.rs diff --git a/bounded-collections/CHANGELOG.md b/bounded-collections/CHANGELOG.md index f6e01625..59fc603c 100644 --- a/bounded-collections/CHANGELOG.md +++ b/bounded-collections/CHANGELOG.md @@ -4,6 +4,9 @@ The format is based on [Keep a Changelog]. [Keep a Changelog]: http://keepachangelog.com/en/1.0.0/ +## [Unreleased] +- Added `ConstInt` and `ConstUint` types. [#878](https://github.com/paritytech/parity-common/pull/878) + ## [0.2.1] - 2024-10-08 - Added `serde` support for `BoundedBTreeMap`. [#870](https://github.com/paritytech/parity-common/pull/870) diff --git a/bounded-collections/src/const_int.rs b/bounded-collections/src/const_int.rs new file mode 100644 index 00000000..df1f4a16 --- /dev/null +++ b/bounded-collections/src/const_int.rs @@ -0,0 +1,153 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use crate::{Get, TypedGet}; +use core::marker::PhantomData; + +// Numbers which have constant upper and lower bounds. +trait ConstBounded { + 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); + +// Check whether a unsigned integer is within the bounds of a type. +struct CheckOverflowU128, const N: u128>(PhantomData); + +impl, const N: u128> CheckOverflowU128 { + const ASSERTION: () = assert!(N >= T::MIN && N <= T::MAX); +} + +// Check whether an integer is within the bounds of a type. +struct CheckOverflowI128, const N: i128>(PhantomData); + +impl, const N: i128> CheckOverflowI128 { + const ASSERTION: () = assert!(N >= T::MIN && N <= T::MAX); +} + +/// Const getter for unsigned integers. +/// +/// # Compile-time checks +/// +/// ```compile_fail +/// # use bounded_collections::{ConstUint, Get}; +/// let _ = as Get>::get(); +/// ``` +#[derive(Default, Clone)] +pub struct ConstUint; + +impl core::fmt::Debug for ConstUint { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + fmt.write_str(&alloc::format!("ConstUint<{}>", N)) + } +} + +impl TypedGet for ConstUint { + type Type = u128; + fn get() -> u128 { + N + } +} + +/// Const getter for signed integers. +#[derive(Default, Clone)] +pub struct ConstInt; + +impl core::fmt::Debug for ConstInt { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + fmt.write_str(&alloc::format!("ConstInt<{}>", N)) + } +} + +impl TypedGet for ConstInt { + type Type = i128; + fn get() -> i128 { + N + } +} + +macro_rules! impl_const_int { + ($t:ident, $check:ident, $bound:ty, $target:ty) => { + impl Get<$target> for $t { + fn get() -> $target { + let _ = <$check<$target, N>>::ASSERTION; + N as $target + } + } + impl Get> for $t { + 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!( as Get>::get(), 42); + assert_eq!( as Get>>::get(), Some(42)); + assert_eq!( as Get>::get(), 42); + assert_eq!( as Get>::get(), 42); + assert_eq!( as Get>::get(), 42); + assert_eq!( as Get>::get(), 42); + assert_eq!( as Get>::get(), 42); + assert_eq!( as TypedGet>::get(), 42); + // compile-time error + // assert_eq!( as Get>::get() as u128, 256); + } + + #[test] + fn const_int_works() { + assert_eq!( as Get>::get(), -42); + assert_eq!( as Get>>::get(), Some(-42)); + assert_eq!( as Get>::get(), -42); + assert_eq!( as Get>::get(), -42); + assert_eq!( as Get>::get(), -42); + assert_eq!( as Get>::get(), -42); + assert_eq!( as TypedGet>::get(), -42); + } +} diff --git a/bounded-collections/src/lib.rs b/bounded-collections/src/lib.rs index ee706da5..c7d5d1f7 100644 --- a/bounded-collections/src/lib.rs +++ b/bounded-collections/src/lib.rs @@ -16,6 +16,7 @@ pub extern crate alloc; pub mod bounded_btree_map; pub mod bounded_btree_set; pub mod bounded_vec; +pub mod const_int; pub mod weak_bounded_vec; mod test; @@ -23,6 +24,7 @@ mod test; pub use bounded_btree_map::BoundedBTreeMap; pub use bounded_btree_set::BoundedBTreeSet; pub use bounded_vec::{BoundedSlice, BoundedVec}; +pub use const_int::{ConstInt, ConstUint}; pub use weak_bounded_vec::WeakBoundedVec; /// A trait for querying a single value from a type defined in the trait.