referrerpolicy=no-referrer-when-downgrade

frame_support/traits/
members.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! Traits for dealing with the idea of membership.
19
20use alloc::vec::Vec;
21use core::marker::PhantomData;
22use impl_trait_for_tuples::impl_for_tuples;
23use sp_arithmetic::traits::AtLeast16BitUnsigned;
24use sp_runtime::DispatchResult;
25
26/// A trait for querying whether a type can be said to "contain" a value.
27pub trait Contains<T> {
28	/// Return `true` if this "contains" the given value `t`.
29	fn contains(t: &T) -> bool;
30}
31
32#[cfg_attr(all(not(feature = "tuples-96"), not(feature = "tuples-128")), impl_for_tuples(64))]
33#[cfg_attr(all(feature = "tuples-96", not(feature = "tuples-128")), impl_for_tuples(96))]
34#[cfg_attr(feature = "tuples-128", impl_for_tuples(128))]
35impl<T> Contains<T> for Tuple {
36	fn contains(t: &T) -> bool {
37		for_tuples!( #(
38			if Tuple::contains(t) { return true }
39		)* );
40		false
41	}
42}
43
44/// A trait for querying whether a type can be said to "contain" a pair-value.
45pub trait ContainsPair<A, B> {
46	/// Return `true` if this "contains" the pair-value `(a, b)`.
47	fn contains(a: &A, b: &B) -> bool;
48}
49
50#[cfg_attr(all(not(feature = "tuples-96"), not(feature = "tuples-128")), impl_for_tuples(64))]
51#[cfg_attr(all(feature = "tuples-96", not(feature = "tuples-128")), impl_for_tuples(96))]
52#[cfg_attr(feature = "tuples-128", impl_for_tuples(128))]
53impl<A, B> ContainsPair<A, B> for Tuple {
54	fn contains(a: &A, b: &B) -> bool {
55		for_tuples!( #(
56			if Tuple::contains(a, b) { return true }
57		)* );
58		false
59	}
60}
61
62/// Converter `struct` to use a `ContainsPair` implementation for a `Contains` bound.
63pub struct FromContainsPair<CP>(PhantomData<CP>);
64impl<A, B, CP: ContainsPair<A, B>> Contains<(A, B)> for FromContainsPair<CP> {
65	fn contains((ref a, ref b): &(A, B)) -> bool {
66		CP::contains(a, b)
67	}
68}
69
70/// A [`ContainsPair`] implementation that has a `Contains` implementation for each member of the
71/// pair.
72pub struct FromContains<CA, CB>(PhantomData<(CA, CB)>);
73impl<A, B, CA: Contains<A>, CB: Contains<B>> ContainsPair<A, B> for FromContains<CA, CB> {
74	fn contains(a: &A, b: &B) -> bool {
75		CA::contains(a) && CB::contains(b)
76	}
77}
78
79/// A [`Contains`] implementation that contains every value.
80pub enum Everything {}
81impl<T> Contains<T> for Everything {
82	fn contains(_: &T) -> bool {
83		true
84	}
85}
86impl<A, B> ContainsPair<A, B> for Everything {
87	fn contains(_: &A, _: &B) -> bool {
88		true
89	}
90}
91
92/// A [`Contains`] implementation that contains no value.
93pub enum Nothing {}
94impl<T> Contains<T> for Nothing {
95	fn contains(_: &T) -> bool {
96		false
97	}
98}
99impl<A, B> ContainsPair<A, B> for Nothing {
100	fn contains(_: &A, _: &B) -> bool {
101		false
102	}
103}
104
105/// A [`Contains`] implementation that contains everything except the values in `Exclude`.
106pub struct EverythingBut<Exclude>(PhantomData<Exclude>);
107impl<T, Exclude: Contains<T>> Contains<T> for EverythingBut<Exclude> {
108	fn contains(t: &T) -> bool {
109		!Exclude::contains(t)
110	}
111}
112impl<A, B, Exclude: ContainsPair<A, B>> ContainsPair<A, B> for EverythingBut<Exclude> {
113	fn contains(a: &A, b: &B) -> bool {
114		!Exclude::contains(a, b)
115	}
116}
117
118/// A [`Contains`] implementation that contains all members of `These` excepting any members in
119/// `Except`.
120pub struct TheseExcept<These, Except>(PhantomData<(These, Except)>);
121impl<T, These: Contains<T>, Except: Contains<T>> Contains<T> for TheseExcept<These, Except> {
122	fn contains(t: &T) -> bool {
123		These::contains(t) && !Except::contains(t)
124	}
125}
126impl<A, B, These: ContainsPair<A, B>, Except: ContainsPair<A, B>> ContainsPair<A, B>
127	for TheseExcept<These, Except>
128{
129	fn contains(a: &A, b: &B) -> bool {
130		These::contains(a, b) && !Except::contains(a, b)
131	}
132}
133
134/// A [`Contains`] implementation which contains all members of `These` which are also members of
135/// `Those`.
136pub struct InsideBoth<These, Those>(PhantomData<(These, Those)>);
137impl<T, These: Contains<T>, Those: Contains<T>> Contains<T> for InsideBoth<These, Those> {
138	fn contains(t: &T) -> bool {
139		These::contains(t) && Those::contains(t)
140	}
141}
142impl<A, B, These: ContainsPair<A, B>, Those: ContainsPair<A, B>> ContainsPair<A, B>
143	for InsideBoth<These, Those>
144{
145	fn contains(a: &A, b: &B) -> bool {
146		These::contains(a, b) && Those::contains(a, b)
147	}
148}
149
150/// An implementation of [`Contains`] which contains only equal members to `T`.
151pub struct Equals<T>(PhantomData<T>);
152impl<X: PartialEq, T: super::Get<X>> Contains<X> for Equals<T> {
153	fn contains(t: &X) -> bool {
154		t == &T::get()
155	}
156}
157
158/// Create a type which implements the `Contains` trait for a particular type with syntax similar
159/// to `matches!`.
160#[macro_export]
161macro_rules! match_types {
162	(
163		pub type $n:ident: impl Contains<$t:ty> = {
164			$phead:pat_param $( | $ptail:pat )*
165		};
166		$( $rest:tt )*
167	) => {
168		pub struct $n;
169		impl $crate::traits::Contains<$t> for $n {
170			fn contains(l: &$t) -> bool {
171				matches!(l, $phead $( | $ptail )* )
172			}
173		}
174		$crate::match_types!( $( $rest )* );
175	};
176	(
177		pub type $n:ident: impl ContainsPair<$a:ty, $b:ty> = {
178			$phead:pat_param $( | $ptail:pat )*
179		};
180		$( $rest:tt )*
181	) => {
182		pub struct $n;
183		impl $crate::traits::ContainsPair<$a, $b> for $n {
184			fn contains(a: &$a, b: &$b) -> bool {
185				matches!((a, b), $phead $( | $ptail )* )
186			}
187		}
188		$crate::match_types!( $( $rest )* );
189	};
190	() => {}
191}
192
193#[cfg(test)]
194mod tests {
195	use super::*;
196
197	match_types! {
198		pub type OneOrTenToTwenty: impl Contains<u8> = { 1 | 10..=20 };
199	}
200
201	#[test]
202	fn match_types_works() {
203		for i in 0..=255 {
204			assert_eq!(OneOrTenToTwenty::contains(&i), i == 1 || i >= 10 && i <= 20);
205		}
206	}
207}
208
209/// A trait for a set which can enumerate its members in order.
210pub trait SortedMembers<T: Ord> {
211	/// Get a vector of all members in the set, ordered.
212	fn sorted_members() -> Vec<T>;
213
214	/// Return `true` if this "contains" the given value `t`.
215	fn contains(t: &T) -> bool {
216		Self::sorted_members().binary_search(t).is_ok()
217	}
218
219	/// Get the number of items in the set.
220	fn count() -> usize {
221		Self::sorted_members().len()
222	}
223
224	/// Add an item that would satisfy `contains`. It does not make sure any other
225	/// state is correctly maintained or generated.
226	///
227	/// **Should be used for benchmarking only!!!**
228	#[cfg(feature = "runtime-benchmarks")]
229	fn add(_t: &T) {
230		unimplemented!()
231	}
232}
233
234/// Adapter struct for turning an `OrderedMembership` impl into a `Contains` impl.
235pub struct AsContains<OM>(PhantomData<(OM,)>);
236impl<T: Ord + Eq, OM: SortedMembers<T>> Contains<T> for AsContains<OM> {
237	fn contains(t: &T) -> bool {
238		OM::contains(t)
239	}
240}
241
242/// Trivial utility for implementing `Contains`/`OrderedMembership` with a `Vec`.
243pub struct IsInVec<T>(PhantomData<T>);
244impl<X: Eq, T: super::Get<Vec<X>>> Contains<X> for IsInVec<T> {
245	fn contains(t: &X) -> bool {
246		T::get().contains(t)
247	}
248}
249impl<X: Ord + PartialOrd, T: super::Get<Vec<X>>> SortedMembers<X> for IsInVec<T> {
250	fn sorted_members() -> Vec<X> {
251		let mut r = T::get();
252		r.sort();
253		r
254	}
255}
256
257/// A trait for querying bound for the length of an implementation of `Contains`
258pub trait ContainsLengthBound {
259	/// Minimum number of elements contained
260	fn min_len() -> usize;
261	/// Maximum number of elements contained
262	fn max_len() -> usize;
263}
264
265/// Ranked membership data structure.
266pub trait RankedMembers {
267	type AccountId;
268	type Rank: AtLeast16BitUnsigned;
269
270	/// The lowest rank possible in this membership organisation.
271	fn min_rank() -> Self::Rank;
272
273	/// Return the rank of the given ID, or `None` if they are not a member.
274	fn rank_of(who: &Self::AccountId) -> Option<Self::Rank>;
275
276	/// Add a member to the group at the `min_rank()`.
277	fn induct(who: &Self::AccountId) -> DispatchResult;
278
279	/// Promote a member to the next higher rank.
280	fn promote(who: &Self::AccountId) -> DispatchResult;
281
282	/// Demote a member to the next lower rank; demoting beyond the `min_rank` removes the
283	/// member entirely.
284	fn demote(who: &Self::AccountId) -> DispatchResult;
285}
286
287/// Handler that can deal with the swap of two members.
288#[impl_trait_for_tuples::impl_for_tuples(16)]
289pub trait RankedMembersSwapHandler<AccountId, Rank> {
290	/// Member `old` was swapped with `new` at `rank`.
291	fn swapped(who: &AccountId, new_who: &AccountId, rank: Rank);
292}
293
294/// Trait for type that can handle the initialization of account IDs at genesis.
295pub trait InitializeMembers<AccountId> {
296	/// Initialize the members to the given `members`.
297	fn initialize_members(members: &[AccountId]);
298}
299
300impl<T> InitializeMembers<T> for () {
301	fn initialize_members(_: &[T]) {}
302}
303
304/// Trait for type that can handle incremental changes to a set of account IDs.
305pub trait ChangeMembers<AccountId: Clone + Ord> {
306	/// A number of members `incoming` just joined the set and replaced some `outgoing` ones. The
307	/// new set is given by `new`, and need not be sorted.
308	///
309	/// This resets any previous value of prime.
310	fn change_members(incoming: &[AccountId], outgoing: &[AccountId], mut new: Vec<AccountId>) {
311		new.sort();
312		Self::change_members_sorted(incoming, outgoing, &new[..]);
313	}
314
315	/// A number of members `_incoming` just joined the set and replaced some `_outgoing` ones. The
316	/// new set is thus given by `sorted_new` and **must be sorted**.
317	///
318	/// NOTE: This is the only function that needs to be implemented in `ChangeMembers`.
319	///
320	/// This resets any previous value of prime.
321	fn change_members_sorted(
322		incoming: &[AccountId],
323		outgoing: &[AccountId],
324		sorted_new: &[AccountId],
325	);
326
327	/// Set the new members; they **must already be sorted**. This will compute the diff and use it
328	/// to call `change_members_sorted`.
329	///
330	/// This resets any previous value of prime.
331	fn set_members_sorted(new_members: &[AccountId], old_members: &[AccountId]) {
332		let (incoming, outgoing) = Self::compute_members_diff_sorted(new_members, old_members);
333		Self::change_members_sorted(&incoming[..], &outgoing[..], new_members);
334	}
335
336	/// Compute diff between new and old members; they **must already be sorted**.
337	///
338	/// Returns incoming and outgoing members.
339	fn compute_members_diff_sorted(
340		new_members: &[AccountId],
341		old_members: &[AccountId],
342	) -> (Vec<AccountId>, Vec<AccountId>) {
343		let mut old_iter = old_members.iter();
344		let mut new_iter = new_members.iter();
345		let mut incoming = Vec::new();
346		let mut outgoing = Vec::new();
347		let mut old_i = old_iter.next();
348		let mut new_i = new_iter.next();
349		loop {
350			match (old_i, new_i) {
351				(None, None) => break,
352				(Some(old), Some(new)) if old == new => {
353					old_i = old_iter.next();
354					new_i = new_iter.next();
355				},
356				(Some(old), Some(new)) if old < new => {
357					outgoing.push(old.clone());
358					old_i = old_iter.next();
359				},
360				(Some(old), None) => {
361					outgoing.push(old.clone());
362					old_i = old_iter.next();
363				},
364				(_, Some(new)) => {
365					incoming.push(new.clone());
366					new_i = new_iter.next();
367				},
368			}
369		}
370		(incoming, outgoing)
371	}
372
373	/// Set the prime member.
374	fn set_prime(_prime: Option<AccountId>) {}
375
376	/// Get the current prime.
377	fn get_prime() -> Option<AccountId> {
378		None
379	}
380}
381
382impl<T: Clone + Ord> ChangeMembers<T> for () {
383	fn change_members(_: &[T], _: &[T], _: Vec<T>) {}
384	fn change_members_sorted(_: &[T], _: &[T], _: &[T]) {}
385	fn set_members_sorted(_: &[T], _: &[T]) {}
386	fn set_prime(_: Option<T>) {}
387}