Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bounded-collections: Add Const(Int|Uint) for generic const getter support #878

Merged
merged 7 commits into from
Nov 4, 2024
Merged
3 changes: 3 additions & 0 deletions bounded-collections/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
160 changes: 160 additions & 0 deletions bounded-collections/src/const_int.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
// Copyright (C) Parity Technologies (UK) Ltd.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use crate::{Get, TypedGet};

// Numbers which have constant upper and lower bounds.
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);

// Check whether a number is within the bounds of a type.
struct CheckOverflow<T>(core::marker::PhantomData<T>);

impl CheckOverflow<u128> {
const fn check<T: ConstBounded<u128>, const N: u128>() {
assert!(N <= T::MAX && N >= T::MIN)
}
}

impl CheckOverflow<i128> {
const fn check<T: ConstBounded<i128>, const N: i128>() {
assert!(N <= T::MAX && N >= T::MIN)
}
}

/// Const getter for unsigned integers.
#[derive(Default, Clone)]
pub struct ConstUint<const N: u128>;

#[cfg(feature = "std")]
impl<const N: u128> std::fmt::Debug for ConstUint<N> {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
fmt.write_str(&format!("{}<{}>", stringify!(ConstUint), N))
conr2d marked this conversation as resolved.
Show resolved Hide resolved
}
}
#[cfg(not(feature = "std"))]
impl<const N: u128> core::fmt::Debug for ConstUint<N> {
fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
fmt.write_str("<wasm:stripped>")
}
}
conr2d marked this conversation as resolved.
Show resolved Hide resolved

impl<const N: u128> TypedGet for ConstUint<N> {
type Type = u128;
fn get() -> u128 {
N
}
}

/// Const getter for signed integers.
#[derive(Default, Clone)]
pub struct ConstInt<const N: i128>;

#[cfg(feature = "std")]
impl<const N: i128> std::fmt::Debug for ConstInt<N> {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
conr2d marked this conversation as resolved.
Show resolved Hide resolved
fmt.write_str(&format!("{}<{}>", stringify!(ConstInt), N))
conr2d marked this conversation as resolved.
Show resolved Hide resolved
}
}
#[cfg(not(feature = "std"))]
impl<const N: i128> core::fmt::Debug for ConstInt<N> {
fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
fmt.write_str("<wasm:stripped>")
}
}
conr2d marked this conversation as resolved.
Show resolved Hide resolved

impl<const N: i128> TypedGet for ConstInt<N> {
type Type = i128;
fn get() -> i128 {
N
}
}

macro_rules! impl_const_int {
($t:ident, $bound:ty, $target:ty) => {
impl<const N: $bound> Get<$target> for $t<N> {
fn get() -> $target {
let _ = <CheckOverflow<$bound>>::check::<$target, N>();
N as $target
}
}
impl<const N: $bound> Get<Option<$target>> for $t<N> {
fn get() -> Option<$target> {
let _ = <CheckOverflow<$bound>>::check::<$target, N>();
conr2d marked this conversation as resolved.
Show resolved Hide resolved
Some(N as $target)
}
}
};
}

impl_const_int!(ConstUint, u128, u8);
impl_const_int!(ConstUint, u128, u16);
impl_const_int!(ConstUint, u128, u32);
impl_const_int!(ConstUint, u128, u64);
impl_const_int!(ConstUint, u128, u128);
impl_const_int!(ConstUint, u128, usize);

impl_const_int!(ConstInt, i128, i8);
impl_const_int!(ConstInt, i128, i16);
impl_const_int!(ConstInt, i128, i32);
impl_const_int!(ConstInt, i128, i64);
impl_const_int!(ConstInt, 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);
// compile-time error
// assert_eq!(<ConstUint<256> as Get<u8>>::get() as u128, 256);
}

#[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);
}
}
2 changes: 2 additions & 0 deletions bounded-collections/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@ 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;

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.
Expand Down
Loading