Skip to main content

topsoil_core/traits/
members.rs

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