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