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