frame_support/traits/
filter.rs1pub use super::members::Contains;
21use core::marker::PhantomData;
22
23pub trait FilterStack<T>: Contains<T> {
25 type Stack;
27
28 fn push(constraint: impl Fn(&T) -> bool + 'static);
30
31 fn pop();
33
34 fn take() -> Self::Stack;
36
37 fn restore(taken: Self::Stack);
39}
40
41pub struct FilterStackGuard<F: FilterStack<T>, T>(PhantomData<(F, T)>);
43
44pub struct ClearFilterGuard<F: FilterStack<T>, T>(Option<F::Stack>, PhantomData<T>);
47
48impl<F: FilterStack<T>, T> FilterStackGuard<F, T> {
49 pub fn new(constraint: impl Fn(&T) -> bool + 'static) -> Self {
52 F::push(constraint);
53 Self(PhantomData)
54 }
55}
56
57impl<F: FilterStack<T>, T> Drop for FilterStackGuard<F, T> {
58 fn drop(&mut self) {
59 F::pop();
60 }
61}
62
63impl<F: FilterStack<T>, T> ClearFilterGuard<F, T> {
64 pub fn new() -> Self {
67 Self(Some(F::take()), PhantomData)
68 }
69}
70
71impl<F: FilterStack<T>, T> Drop for ClearFilterGuard<F, T> {
72 fn drop(&mut self) {
73 if let Some(taken) = self.0.take() {
74 F::restore(taken);
75 }
76 }
77}
78
79pub trait InstanceFilter<T>: Sized + Send + Sync {
81 fn filter(&self, _: &T) -> bool;
83
84 fn is_superset(&self, _o: &Self) -> bool {
86 false
87 }
88}
89
90impl<T> InstanceFilter<T> for () {
91 fn filter(&self, _: &T) -> bool {
92 true
93 }
94 fn is_superset(&self, _o: &Self) -> bool {
95 true
96 }
97}
98
99#[macro_export]
100macro_rules! impl_filter_stack {
101 ($target:ty, $base:ty, $call:ty, $module:ident) => {
102 #[cfg(feature = "std")]
103 mod $module {
104 #[allow(unused_imports)]
105 use super::*;
106 use std::{boxed::Box, cell::RefCell, mem::{swap, take}, vec::Vec};
107 use $crate::traits::filter::{Contains, FilterStack};
108
109 thread_local! {
110 static FILTER: RefCell<Vec<Box<dyn Fn(&$call) -> bool + 'static>>> = RefCell::new(Vec::new());
111 }
112
113 impl Contains<$call> for $target {
114 fn contains(call: &$call) -> bool {
115 <$base>::contains(call) &&
116 FILTER.with(|filter| filter.borrow().iter().all(|f| f(call)))
117 }
118 }
119
120 impl FilterStack<$call> for $target {
121 type Stack = Vec<Box<dyn Fn(&$call) -> bool + 'static>>;
122 fn push(f: impl Fn(&$call) -> bool + 'static) {
123 FILTER.with(|filter| filter.borrow_mut().push(Box::new(f)));
124 }
125 fn pop() {
126 FILTER.with(|filter| filter.borrow_mut().pop());
127 }
128 fn take() -> Self::Stack {
129 FILTER.with(|filter| take(filter.borrow_mut().as_mut()))
130 }
131 fn restore(mut s: Self::Stack) {
132 FILTER.with(|filter| swap(filter.borrow_mut().as_mut(), &mut s));
133 }
134 }
135 }
136
137 #[cfg(not(feature = "std"))]
138 mod $module {
139 #[allow(unused_imports)]
140 use super::*;
141 use $crate::traits::{swap, take, RefCell, Vec, Box, Contains, FilterStack};
142
143 struct ThisFilter(RefCell<Vec<Box<dyn Fn(&$call) -> bool + 'static>>>);
144 unsafe impl Send for ThisFilter {}
146 unsafe impl Sync for ThisFilter {}
147
148 static FILTER: ThisFilter = ThisFilter(RefCell::new(Vec::new()));
149
150 impl Contains<$call> for $target {
151 fn contains(call: &$call) -> bool {
152 <$base>::contains(call) && FILTER.0.borrow().iter().all(|f| f(call))
153 }
154 }
155
156 impl FilterStack<$call> for $target {
157 type Stack = Vec<Box<dyn Fn(&$call) -> bool + 'static>>;
158 fn push(f: impl Fn(&$call) -> bool + 'static) {
159 FILTER.0.borrow_mut().push(Box::new(f));
160 }
161 fn pop() {
162 FILTER.0.borrow_mut().pop();
163 }
164 fn take() -> Self::Stack {
165 take(FILTER.0.borrow_mut().as_mut())
166 }
167 fn restore(mut s: Self::Stack) {
168 swap(FILTER.0.borrow_mut().as_mut(), &mut s);
169 }
170 }
171 }
172 }
173}
174
175#[cfg(test)]
176pub mod test_impl_filter_stack {
177 use super::*;
178
179 pub struct IsCallable;
180 pub struct BaseFilter;
181 impl Contains<u32> for BaseFilter {
182 fn contains(x: &u32) -> bool {
183 x % 2 == 0
184 }
185 }
186 impl_filter_stack!(
187 crate::traits::filter::test_impl_filter_stack::IsCallable,
188 crate::traits::filter::test_impl_filter_stack::BaseFilter,
189 u32,
190 is_callable
191 );
192
193 #[test]
194 fn impl_filter_stack_should_work() {
195 assert!(IsCallable::contains(&36));
196 assert!(IsCallable::contains(&40));
197 assert!(IsCallable::contains(&42));
198 assert!(!IsCallable::contains(&43));
199
200 IsCallable::push(|x| *x < 42);
201 assert!(IsCallable::contains(&36));
202 assert!(IsCallable::contains(&40));
203 assert!(!IsCallable::contains(&42));
204
205 IsCallable::push(|x| *x % 3 == 0);
206 assert!(IsCallable::contains(&36));
207 assert!(!IsCallable::contains(&40));
208
209 IsCallable::pop();
210 assert!(IsCallable::contains(&36));
211 assert!(IsCallable::contains(&40));
212 assert!(!IsCallable::contains(&42));
213
214 let saved = IsCallable::take();
215 assert!(IsCallable::contains(&36));
216 assert!(IsCallable::contains(&40));
217 assert!(IsCallable::contains(&42));
218 assert!(!IsCallable::contains(&43));
219
220 IsCallable::restore(saved);
221 assert!(IsCallable::contains(&36));
222 assert!(IsCallable::contains(&40));
223 assert!(!IsCallable::contains(&42));
224
225 IsCallable::pop();
226 assert!(IsCallable::contains(&36));
227 assert!(IsCallable::contains(&40));
228 assert!(IsCallable::contains(&42));
229 assert!(!IsCallable::contains(&43));
230 }
231
232 #[test]
233 fn guards_should_work() {
234 assert!(IsCallable::contains(&36));
235 assert!(IsCallable::contains(&40));
236 assert!(IsCallable::contains(&42));
237 assert!(!IsCallable::contains(&43));
238 {
239 let _guard_1 = FilterStackGuard::<IsCallable, u32>::new(|x| *x < 42);
240 assert!(IsCallable::contains(&36));
241 assert!(IsCallable::contains(&40));
242 assert!(!IsCallable::contains(&42));
243 {
244 let _guard_2 = FilterStackGuard::<IsCallable, u32>::new(|x| *x % 3 == 0);
245 assert!(IsCallable::contains(&36));
246 assert!(!IsCallable::contains(&40));
247 }
248 assert!(IsCallable::contains(&36));
249 assert!(IsCallable::contains(&40));
250 assert!(!IsCallable::contains(&42));
251 {
252 let _guard_2 = ClearFilterGuard::<IsCallable, u32>::new();
253 assert!(IsCallable::contains(&36));
254 assert!(IsCallable::contains(&40));
255 assert!(IsCallable::contains(&42));
256 assert!(!IsCallable::contains(&43));
257 }
258 assert!(IsCallable::contains(&36));
259 assert!(IsCallable::contains(&40));
260 assert!(!IsCallable::contains(&42));
261 }
262 assert!(IsCallable::contains(&36));
263 assert!(IsCallable::contains(&40));
264 assert!(IsCallable::contains(&42));
265 assert!(!IsCallable::contains(&43));
266 }
267}