bounded_collections_next/
lib.rs

1// Copyright 2023 Parity Technologies
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
9//! Collection types that have an upper limit on how many elements that they can contain, and
10//! supporting traits that aid in defining the limit.
11
12#![cfg_attr(not(feature = "std"), no_std)]
13
14pub extern crate alloc;
15
16pub mod bounded_btree_map;
17pub mod bounded_btree_set;
18pub mod bounded_vec;
19pub mod const_int;
20pub mod weak_bounded_vec;
21
22mod test;
23
24pub use bounded_btree_map::BoundedBTreeMap;
25pub use bounded_btree_set::BoundedBTreeSet;
26pub use bounded_vec::{BoundedSlice, BoundedVec};
27pub use const_int::{ConstInt, ConstUint};
28pub use weak_bounded_vec::WeakBoundedVec;
29
30/// A trait for querying a single value from a type defined in the trait.
31///
32/// It is not required that the value is constant.
33pub trait TypedGet {
34	/// The type which is returned.
35	type Type;
36	/// Return the current value.
37	fn get() -> Self::Type;
38}
39
40/// A trait for querying a single value from a type.
41///
42/// It is not required that the value is constant.
43pub trait Get<T> {
44	/// Return the current value.
45	fn get() -> T;
46}
47
48impl<T: Default> Get<T> for () {
49	fn get() -> T {
50		T::default()
51	}
52}
53
54/// Converts [`Get<I>`] to [`Get<R>`] using [`Into`].
55///
56/// Acts as a type-safe bridge between `Get` implementations where `I: Into<R>`.
57///
58/// - `Inner`: The [`Get<I>`] implementation
59/// - `I`: Source type to convert from
60///
61/// # Example
62/// ```
63/// use bounded_collections_next::Get;
64/// use bounded_collections_next::GetInto;
65///
66/// struct MyGetter;
67/// impl Get<u16> for MyGetter { fn get() -> u16 { 42 } }
68/// let foo: u32 = GetInto::<MyGetter, u16>::get();
69/// assert_eq!(foo, 42u32); // <--- infered as u32
70/// ```
71pub struct GetInto<Inner, I>(core::marker::PhantomData<(Inner, I)>);
72
73impl<Inner, I, R> Get<R> for GetInto<Inner, I>
74where
75	Inner: Get<I>,
76	I: Into<R>,
77{
78	/// Returns the converted value by:
79	/// 1. Getting the inner value of type `I`
80	/// 2. Converting it to type `R` using [`Into`]
81	fn get() -> R {
82		Inner::get().into()
83	}
84}
85
86/// Implement Get by returning Default for any type that implements Default.
87pub struct GetDefault;
88impl<T: Default> Get<T> for GetDefault {
89	fn get() -> T {
90		T::default()
91	}
92}
93
94macro_rules! impl_const_get {
95	($name:ident, $t:ty) => {
96		/// Const getter for a basic type.
97		#[derive(Default, Clone)]
98		pub struct $name<const T: $t>;
99
100		#[cfg(feature = "std")]
101		impl<const T: $t> core::fmt::Debug for $name<T> {
102			fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
103				fmt.write_str(&format!("{}<{}>", stringify!($name), T))
104			}
105		}
106		#[cfg(not(feature = "std"))]
107		impl<const T: $t> core::fmt::Debug for $name<T> {
108			fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
109				fmt.write_str("<wasm:stripped>")
110			}
111		}
112		impl<const T: $t> Get<$t> for $name<T> {
113			fn get() -> $t {
114				T
115			}
116		}
117		impl<const T: $t> Get<Option<$t>> for $name<T> {
118			fn get() -> Option<$t> {
119				Some(T)
120			}
121		}
122		impl<const T: $t> TypedGet for $name<T> {
123			type Type = $t;
124			fn get() -> $t {
125				T
126			}
127		}
128	};
129}
130
131impl_const_get!(ConstBool, bool);
132impl_const_get!(ConstU8, u8);
133impl_const_get!(ConstU16, u16);
134impl_const_get!(ConstU32, u32);
135impl_const_get!(ConstU64, u64);
136impl_const_get!(ConstU128, u128);
137impl_const_get!(ConstI8, i8);
138impl_const_get!(ConstI16, i16);
139impl_const_get!(ConstI32, i32);
140impl_const_get!(ConstI64, i64);
141impl_const_get!(ConstI128, i128);
142
143/// Try and collect into a collection `C`.
144pub trait TryCollect<C> {
145	/// The error type that gets returned when a collection can't be made from `self`.
146	type Error;
147	/// Consume self and try to collect the results into `C`.
148	///
149	/// This is useful in preventing the undesirable `.collect().try_into()` call chain on
150	/// collections that need to be converted into a bounded type (e.g. `BoundedVec`).
151	fn try_collect(self) -> Result<C, Self::Error>;
152}
153
154/// Create new implementations of the [`Get`](crate::Get) trait.
155///
156/// The so-called parameter type can be created in four different ways:
157///
158/// - Using `const` to create a parameter type that provides a `const` getter. It is required that
159///   the `value` is const.
160///
161/// - Declare the parameter type without `const` to have more freedom when creating the value.
162///
163/// NOTE: A more substantial version of this macro is available in `frame_support` crate which
164/// allows mutable and persistant variants.
165///
166/// # Examples
167///
168/// ```
169/// # use bounded_collections_next::Get;
170/// # use bounded_collections_next::parameter_types;
171/// // This function cannot be used in a const context.
172/// fn non_const_expression() -> u64 { 99 }
173///
174/// const FIXED_VALUE: u64 = 10;
175/// parameter_types! {
176///    pub const Argument: u64 = 42 + FIXED_VALUE;
177///    /// Visibility of the type is optional
178///    OtherArgument: u64 = non_const_expression();
179/// }
180///
181/// trait Config {
182///    type Parameter: Get<u64>;
183///    type OtherParameter: Get<u64>;
184/// }
185///
186/// struct Runtime;
187/// impl Config for Runtime {
188///    type Parameter = Argument;
189///    type OtherParameter = OtherArgument;
190/// }
191/// ```
192///
193/// # Invalid example:
194///
195/// ```compile_fail
196/// # use bounded_collections::Get;
197/// # use bounded_collections::parameter_types;
198/// // This function cannot be used in a const context.
199/// fn non_const_expression() -> u64 { 99 }
200///
201/// parameter_types! {
202///    pub const Argument: u64 = non_const_expression();
203/// }
204/// ```
205#[macro_export]
206macro_rules! parameter_types {
207	(
208		$( #[ $attr:meta ] )*
209		$vis:vis const $name:ident: $type:ty = $value:expr;
210		$( $rest:tt )*
211	) => (
212		$( #[ $attr ] )*
213		$vis struct $name;
214		$crate::parameter_types!(@IMPL_CONST $name , $type , $value);
215		$crate::parameter_types!( $( $rest )* );
216	);
217	(
218		$( #[ $attr:meta ] )*
219		$vis:vis $name:ident: $type:ty = $value:expr;
220		$( $rest:tt )*
221	) => (
222		$( #[ $attr ] )*
223		$vis struct $name;
224		$crate::parameter_types!(@IMPL $name, $type, $value);
225		$crate::parameter_types!( $( $rest )* );
226	);
227	() => ();
228	(@IMPL_CONST $name:ident, $type:ty, $value:expr) => {
229		impl $name {
230			/// Returns the value of this parameter type.
231			pub const fn get() -> $type {
232				$value
233			}
234		}
235
236		impl<I: From<$type>> $crate::Get<I> for $name {
237			fn get() -> I {
238				I::from(Self::get())
239			}
240		}
241
242		impl $crate::TypedGet for $name {
243			type Type = $type;
244			fn get() -> $type {
245				Self::get()
246			}
247		}
248	};
249	(@IMPL $name:ident, $type:ty, $value:expr) => {
250		impl $name {
251			/// Returns the value of this parameter type.
252			pub fn get() -> $type {
253				$value
254			}
255		}
256
257		impl<I: From<$type>> $crate::Get<I> for $name {
258			fn get() -> I {
259				I::from(Self::get())
260			}
261		}
262
263		impl $crate::TypedGet for $name {
264			type Type = $type;
265			fn get() -> $type {
266				Self::get()
267			}
268		}
269	};
270}
271
272/// Build a bounded vec from the given literals.
273///
274/// The type of the outcome must be known.
275///
276/// Will not handle any errors and just panic if the given literals cannot fit in the corresponding
277/// bounded vec type. Thus, this is only suitable for testing and non-consensus code.
278#[macro_export]
279#[cfg(feature = "std")]
280macro_rules! bounded_vec {
281	($ ($values:expr),* $(,)?) => {
282		{
283			$crate::alloc::vec![$($values),*].try_into().unwrap()
284		}
285	};
286	( $value:expr ; $repetition:expr ) => {
287		{
288			$crate::alloc::vec![$value ; $repetition].try_into().unwrap()
289		}
290	}
291}
292
293/// Build a bounded btree-map from the given literals.
294///
295/// The type of the outcome must be known.
296///
297/// Will not handle any errors and just panic if the given literals cannot fit in the corresponding
298/// bounded vec type. Thus, this is only suitable for testing and non-consensus code.
299#[macro_export]
300#[cfg(feature = "std")]
301macro_rules! bounded_btree_map {
302	($ ( $key:expr => $value:expr ),* $(,)?) => {
303		{
304			$crate::TryCollect::<$crate::BoundedBTreeMap<_, _, _>>::try_collect(
305				$crate::alloc::vec![$(($key, $value)),*].into_iter()
306			).unwrap()
307		}
308	};
309}