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}