Skip to main content

fp_library/classes/
ref_filterable.rs

1//! By-reference filtering and partitioning of structures.
2//!
3//! ### Examples
4//!
5//! ```
6//! use fp_library::{
7//! 	brands::*,
8//! 	functions::explicit::*,
9//! };
10//!
11//! let v = vec![1, 2, 3, 4, 5];
12//! let result =
13//! 	filter_map::<VecBrand, _, _, _, _>(|x: &i32| if *x > 3 { Some(*x) } else { None }, &v);
14//! assert_eq!(result, vec![4, 5]);
15//! ```
16
17#[fp_macros::document_module]
18mod inner {
19	use {
20		crate::{
21			classes::*,
22			kinds::*,
23		},
24		fp_macros::*,
25	};
26
27	/// By-reference filtering of structures.
28	///
29	/// Similar to [`Filterable`], but closures receive `&A` instead of `A`.
30	/// This enables filtering collections by reference without consuming elements,
31	/// or filtering memoized types that only provide `&A` access.
32	///
33	/// Default implementations derive:
34	/// * `ref_partition_map` from `ref_map` + `separate` (via `Compactable`).
35	/// * `ref_partition` from `ref_partition_map`.
36	/// * `ref_filter_map` from `ref_map` + `compact` (via `Compactable`).
37	/// * `ref_filter` from `ref_filter_map`.
38	#[kind(type Of<'a, A: 'a>: 'a;)]
39	pub trait RefFilterable: RefFunctor + Compactable {
40		/// Partitions a structure by reference using a function that returns `Result`.
41		#[document_signature]
42		///
43		#[document_type_parameters(
44			"The lifetime of the elements.",
45			"The type of the elements in the input structure.",
46			"The type of the error values.",
47			"The type of the success values."
48		)]
49		///
50		#[document_parameters(
51			"The function to apply to each element reference, returning a `Result`.",
52			"The structure to partition."
53		)]
54		///
55		#[document_returns("A pair of (errors, successes).")]
56		#[document_examples]
57		///
58		/// ```
59		/// use fp_library::{
60		/// 	brands::*,
61		/// 	functions::explicit::*,
62		/// };
63		///
64		/// let v = vec![1, 2, 3, 4, 5];
65		/// let (small, big) = partition_map::<VecBrand, _, _, _, _, _>(
66		/// 	|x: &i32| if *x > 3 { Ok(*x) } else { Err(*x) },
67		/// 	&v,
68		/// );
69		/// assert_eq!(big, vec![4, 5]);
70		/// assert_eq!(small, vec![1, 2, 3]);
71		/// ```
72		fn ref_partition_map<'a, A: 'a, E: 'a, O: 'a>(
73			func: impl Fn(&A) -> Result<O, E> + 'a,
74			fa: &Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
75		) -> (
76			Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E>),
77			Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, O>),
78		) {
79			Self::separate::<E, O>(Self::ref_map::<A, Result<O, E>>(func, fa))
80		}
81
82		/// Partitions a structure by reference using a predicate.
83		///
84		/// Returns `(not_satisfied, satisfied)`, matching Rust's `Iterator::partition`.
85		#[document_signature]
86		///
87		#[document_type_parameters(
88			"The lifetime of the elements.",
89			"The type of the elements in the structure."
90		)]
91		///
92		#[document_parameters("The predicate function.", "The structure to partition.")]
93		///
94		#[document_returns("A pair of (not satisfied, satisfied).")]
95		#[document_examples]
96		///
97		/// ```
98		/// use fp_library::{
99		/// 	brands::*,
100		/// 	functions::explicit::*,
101		/// };
102		///
103		/// let v = vec![1, 2, 3, 4, 5];
104		/// let (small, big) = partition::<VecBrand, _, _, _>(|x: &i32| *x > 3, &v);
105		/// assert_eq!(big, vec![4, 5]);
106		/// assert_eq!(small, vec![1, 2, 3]);
107		/// ```
108		fn ref_partition<'a, A: 'a + Clone>(
109			func: impl Fn(&A) -> bool + 'a,
110			fa: &Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
111		) -> (
112			Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
113			Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
114		) {
115			Self::ref_partition_map(
116				move |a: &A| {
117					if func(a) { Ok(a.clone()) } else { Err(a.clone()) }
118				},
119				fa,
120			)
121		}
122
123		/// Maps a function over a structure by reference and filters out `None` results.
124		#[document_signature]
125		///
126		#[document_type_parameters(
127			"The lifetime of the elements.",
128			"The type of the elements in the input structure.",
129			"The type of the elements in the output structure."
130		)]
131		///
132		#[document_parameters(
133			"The function to apply to each element reference, returning an `Option`.",
134			"The structure to filter and map."
135		)]
136		///
137		#[document_returns("The structure with `None` results removed.")]
138		#[document_examples]
139		///
140		/// ```
141		/// use fp_library::{
142		/// 	brands::*,
143		/// 	functions::explicit::*,
144		/// };
145		///
146		/// let v = vec![1, 2, 3, 4, 5];
147		/// let result =
148		/// 	filter_map::<VecBrand, _, _, _, _>(|x: &i32| if *x > 3 { Some(*x) } else { None }, &v);
149		/// assert_eq!(result, vec![4, 5]);
150		/// ```
151		fn ref_filter_map<'a, A: 'a, B: 'a>(
152			func: impl Fn(&A) -> Option<B> + 'a,
153			fa: &Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
154		) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
155			Self::compact::<B>(Self::ref_map::<A, Option<B>>(func, fa))
156		}
157
158		/// Filters a structure by reference using a predicate.
159		#[document_signature]
160		///
161		#[document_type_parameters(
162			"The lifetime of the elements.",
163			"The type of the elements in the structure."
164		)]
165		///
166		#[document_parameters("The predicate function.", "The structure to filter.")]
167		///
168		#[document_returns("The structure with elements not satisfying the predicate removed.")]
169		#[document_examples]
170		///
171		/// ```
172		/// use fp_library::{
173		/// 	brands::*,
174		/// 	functions::explicit::*,
175		/// };
176		///
177		/// let v = vec![1, 2, 3, 4, 5];
178		/// let result = filter::<VecBrand, _, _, _>(|x: &i32| *x > 3, &v);
179		/// assert_eq!(result, vec![4, 5]);
180		/// ```
181		fn ref_filter<'a, A: 'a + Clone>(
182			func: impl Fn(&A) -> bool + 'a,
183			fa: &Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
184		) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>) {
185			Self::ref_filter_map(move |a: &A| if func(a) { Some(a.clone()) } else { None }, fa)
186		}
187	}
188
189	/// Partitions by reference using a function returning `Result`.
190	///
191	/// Free function version that dispatches to [the type class' associated function][`RefFilterable::ref_partition_map`].
192	#[document_signature]
193	///
194	#[document_type_parameters(
195		"The lifetime of the elements.",
196		"The brand of the structure.",
197		"The type of the elements.",
198		"The error type.",
199		"The success type."
200	)]
201	///
202	#[document_parameters("The partitioning function.", "The structure to partition.")]
203	///
204	#[document_returns("A pair of (errors, successes).")]
205	#[document_examples]
206	///
207	/// ```
208	/// use fp_library::{
209	/// 	brands::*,
210	/// 	functions::explicit::*,
211	/// };
212	///
213	/// let v = vec![1, 2, 3, 4, 5];
214	/// let (small, big) = partition_map::<VecBrand, _, _, _, _, _>(
215	/// 	|x: &i32| if *x > 3 { Ok(*x) } else { Err(*x) },
216	/// 	&v,
217	/// );
218	/// assert_eq!(big, vec![4, 5]);
219	/// assert_eq!(small, vec![1, 2, 3]);
220	/// ```
221	pub fn ref_partition_map<'a, Brand: RefFilterable, A: 'a, E: 'a, O: 'a>(
222		func: impl Fn(&A) -> Result<O, E> + 'a,
223		fa: &Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
224	) -> (
225		Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E>),
226		Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, O>),
227	) {
228		Brand::ref_partition_map(func, fa)
229	}
230
231	/// Partitions by reference using a predicate.
232	///
233	/// Free function version that dispatches to [the type class' associated function][`RefFilterable::ref_partition`].
234	#[document_signature]
235	///
236	#[document_type_parameters(
237		"The lifetime of the elements.",
238		"The brand of the structure.",
239		"The type of the elements."
240	)]
241	///
242	#[document_parameters("The predicate.", "The structure to partition.")]
243	///
244	#[document_returns("A pair of (not satisfied, satisfied).")]
245	#[document_examples]
246	///
247	/// ```
248	/// use fp_library::{
249	/// 	brands::*,
250	/// 	functions::explicit::*,
251	/// };
252	///
253	/// let v = vec![1, 2, 3, 4, 5];
254	/// let (small, big) = partition::<VecBrand, _, _, _>(|x: &i32| *x > 3, &v);
255	/// assert_eq!(big, vec![4, 5]);
256	/// assert_eq!(small, vec![1, 2, 3]);
257	/// ```
258	pub fn ref_partition<'a, Brand: RefFilterable, A: 'a + Clone>(
259		func: impl Fn(&A) -> bool + 'a,
260		fa: &Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
261	) -> (
262		Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
263		Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
264	) {
265		Brand::ref_partition(func, fa)
266	}
267
268	/// Maps by reference and filters out `None` results.
269	///
270	/// Free function version that dispatches to [the type class' associated function][`RefFilterable::ref_filter_map`].
271	#[document_signature]
272	///
273	#[document_type_parameters(
274		"The lifetime of the elements.",
275		"The brand of the structure.",
276		"The type of the input elements.",
277		"The type of the output elements."
278	)]
279	///
280	#[document_parameters("The filter-map function.", "The structure to filter.")]
281	///
282	#[document_returns("The filtered structure.")]
283	#[document_examples]
284	///
285	/// ```
286	/// use fp_library::{
287	/// 	brands::*,
288	/// 	functions::explicit::*,
289	/// };
290	///
291	/// let v = vec![1, 2, 3, 4, 5];
292	/// let result =
293	/// 	filter_map::<VecBrand, _, _, _, _>(|x: &i32| if *x > 3 { Some(*x) } else { None }, &v);
294	/// assert_eq!(result, vec![4, 5]);
295	/// ```
296	pub fn ref_filter_map<'a, Brand: RefFilterable, A: 'a, B: 'a>(
297		func: impl Fn(&A) -> Option<B> + 'a,
298		fa: &Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
299	) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
300		Brand::ref_filter_map(func, fa)
301	}
302
303	/// Filters by reference using a predicate.
304	///
305	/// Free function version that dispatches to [the type class' associated function][`RefFilterable::ref_filter`].
306	#[document_signature]
307	///
308	#[document_type_parameters(
309		"The lifetime of the elements.",
310		"The brand of the structure.",
311		"The type of the elements."
312	)]
313	///
314	#[document_parameters("The predicate.", "The structure to filter.")]
315	///
316	#[document_returns("The filtered structure.")]
317	#[document_examples]
318	///
319	/// ```
320	/// use fp_library::{
321	/// 	brands::*,
322	/// 	functions::explicit::*,
323	/// };
324	///
325	/// let v = vec![1, 2, 3, 4, 5];
326	/// let result = filter::<VecBrand, _, _, _>(|x: &i32| *x > 3, &v);
327	/// assert_eq!(result, vec![4, 5]);
328	/// ```
329	pub fn ref_filter<'a, Brand: RefFilterable, A: 'a + Clone>(
330		func: impl Fn(&A) -> bool + 'a,
331		fa: &Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
332	) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>) {
333		Brand::ref_filter(func, fa)
334	}
335}
336
337pub use inner::*;