Skip to main content

fp_library/dispatch/
compactable.rs

1//! Dispatch for compactable operations:
2//! [`Compactable`](crate::classes::Compactable) and
3//! [`RefCompactable`](crate::classes::RefCompactable).
4//!
5//! Provides the following dispatch traits and unified free functions:
6//!
7//! - [`CompactDispatch`] + [`explicit::compact`]
8//! - [`SeparateDispatch`] + [`explicit::separate`]
9//!
10//! Each routes to the appropriate trait method based on whether the container
11//! is owned or borrowed.
12//!
13//! ### Examples
14//!
15//! ```
16//! use fp_library::{
17//! 	brands::*,
18//! 	functions::explicit::*,
19//! };
20//!
21//! // compact
22//! let y = compact::<VecBrand, _, _, _>(vec![Some(1), None, Some(3)]);
23//! assert_eq!(y, vec![1, 3]);
24//!
25//! // separate
26//! let (errs, oks) = separate::<VecBrand, _, _, _, _>(vec![Ok(1), Err(2), Ok(3)]);
27//! assert_eq!(oks, vec![1, 3]);
28//! assert_eq!(errs, vec![2]);
29//! ```
30
31#[fp_macros::document_module]
32pub(crate) mod inner {
33	use {
34		crate::{
35			brands::OptionBrand,
36			classes::{
37				Compactable,
38				RefCompactable,
39			},
40			dispatch::{
41				Ref,
42				Val,
43			},
44			kinds::*,
45		},
46		fp_macros::*,
47	};
48
49	// -- CompactDispatch --
50
51	/// Trait that routes a compact operation to the appropriate type class method.
52	///
53	/// The `Marker` type parameter is an implementation detail resolved by
54	/// the compiler from the container type; callers never specify it directly.
55	/// Owned containers resolve to [`Val`], borrowed containers resolve to [`Ref`].
56	#[document_type_parameters(
57		"The lifetime of the values.",
58		"The brand of the compactable.",
59		"The type of the value(s) inside the `Option` wrappers.",
60		"Dispatch marker type, inferred automatically. Either [`Val`](crate::dispatch::Val) or [`Ref`](crate::dispatch::Ref)."
61	)]
62	#[document_parameters("The container implementing this dispatch.")]
63	pub trait CompactDispatch<'a, Brand: Kind_cdc7cd43dac7585f, A: 'a, Marker> {
64		/// Perform the dispatched compact operation.
65		#[document_signature]
66		///
67		#[document_returns(
68			"A new container with `None` values removed and `Some` values unwrapped."
69		)]
70		#[document_examples]
71		///
72		/// ```
73		/// use fp_library::{
74		/// 	brands::*,
75		/// 	functions::explicit::*,
76		/// };
77		///
78		/// let result = compact::<VecBrand, _, _, _>(vec![Some(1), None, Some(3)]);
79		/// assert_eq!(result, vec![1, 3]);
80		/// ```
81		fn dispatch(self) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>);
82	}
83
84	/// Routes owned containers to [`Compactable::compact`].
85	#[document_type_parameters(
86		"The lifetime of the values.",
87		"The brand of the compactable.",
88		"The type of the value(s) inside the `Option` wrappers."
89	)]
90	#[document_parameters("The owned container of `Option` values.")]
91	impl<'a, Brand, A> CompactDispatch<'a, Brand, A, Val> for Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Apply!(<OptionBrand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>)>)
92	where
93		Brand: Compactable,
94		A: 'a,
95	{
96		#[document_signature]
97		///
98		#[document_returns(
99			"A new container with `None` values removed and `Some` values unwrapped."
100		)]
101		#[document_examples]
102		///
103		/// ```
104		/// use fp_library::{
105		/// 	brands::*,
106		/// 	functions::explicit::*,
107		/// };
108		///
109		/// let result = compact::<VecBrand, _, _, _>(vec![Some(1), None, Some(3)]);
110		/// assert_eq!(result, vec![1, 3]);
111		/// ```
112		fn dispatch(self) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>) {
113			Brand::compact(self)
114		}
115	}
116
117	/// Routes borrowed containers to [`RefCompactable::ref_compact`].
118	#[document_type_parameters(
119		"The lifetime of the values.",
120		"The brand of the compactable.",
121		"The type of the value(s) inside the `Option` wrappers."
122	)]
123	#[document_parameters("The borrowed container of `Option` values.")]
124	impl<'a, Brand, A> CompactDispatch<'a, Brand, A, Ref> for &Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Apply!(<OptionBrand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>)>)
125	where
126		Brand: RefCompactable,
127		A: 'a + Clone,
128	{
129		#[document_signature]
130		///
131		#[document_returns(
132			"A new container with `None` values removed and `Some` values unwrapped."
133		)]
134		#[document_examples]
135		///
136		/// ```
137		/// use fp_library::{
138		/// 	brands::*,
139		/// 	functions::explicit::*,
140		/// };
141		///
142		/// let v = vec![Some(1), None, Some(3)];
143		/// let result = compact::<VecBrand, _, _, _>(&v);
144		/// assert_eq!(result, vec![1, 3]);
145		/// ```
146		fn dispatch(self) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>) {
147			Brand::ref_compact(self)
148		}
149	}
150
151	// -- SeparateDispatch --
152
153	/// Trait that routes a separate operation to the appropriate type class method.
154	///
155	/// The `Marker` type parameter is an implementation detail resolved by
156	/// the compiler from the container type; callers never specify it directly.
157	/// Owned containers resolve to [`Val`], borrowed containers resolve to [`Ref`].
158	#[document_type_parameters(
159		"The lifetime of the values.",
160		"The brand of the compactable.",
161		"The error type inside the `Result` wrappers.",
162		"The success type inside the `Result` wrappers.",
163		"Dispatch marker type, inferred automatically. Either [`Val`](crate::dispatch::Val) or [`Ref`](crate::dispatch::Ref)."
164	)]
165	#[document_parameters("The container implementing this dispatch.")]
166	pub trait SeparateDispatch<'a, Brand: Kind_cdc7cd43dac7585f, E: 'a, O: 'a, Marker> {
167		/// Perform the dispatched separate operation.
168		#[document_signature]
169		///
170		#[document_returns("A tuple of two containers: `Err` values and `Ok` values.")]
171		#[document_examples]
172		///
173		/// ```
174		/// use fp_library::{
175		/// 	brands::*,
176		/// 	functions::explicit::*,
177		/// };
178		///
179		/// let (errs, oks) = separate::<VecBrand, _, _, _, _>(vec![Ok(1), Err(2), Ok(3)]);
180		/// assert_eq!(oks, vec![1, 3]);
181		/// assert_eq!(errs, vec![2]);
182		/// ```
183		fn dispatch(
184			self
185		) -> (
186			Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E>),
187			Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, O>),
188		);
189	}
190
191	/// Routes owned containers to [`Compactable::separate`].
192	#[document_type_parameters(
193		"The lifetime of the values.",
194		"The brand of the compactable.",
195		"The error type inside the `Result` wrappers.",
196		"The success type inside the `Result` wrappers."
197	)]
198	#[document_parameters("The owned container of `Result` values.")]
199	impl<'a, Brand, E, O> SeparateDispatch<'a, Brand, E, O, Val> for Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Result<O, E>>)
200	where
201		Brand: Compactable,
202		E: 'a,
203		O: 'a,
204	{
205		#[document_signature]
206		///
207		#[document_returns("A tuple of two containers: `Err` values and `Ok` values.")]
208		#[document_examples]
209		///
210		/// ```
211		/// use fp_library::{
212		/// 	brands::*,
213		/// 	functions::explicit::*,
214		/// };
215		///
216		/// let (errs, oks) = separate::<VecBrand, _, _, _, _>(vec![Ok(1), Err(2), Ok(3)]);
217		/// assert_eq!(oks, vec![1, 3]);
218		/// assert_eq!(errs, vec![2]);
219		/// ```
220		fn dispatch(
221			self
222		) -> (
223			Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E>),
224			Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, O>),
225		) {
226			Brand::separate(self)
227		}
228	}
229
230	/// Routes borrowed containers to [`RefCompactable::ref_separate`].
231	#[document_type_parameters(
232		"The lifetime of the values.",
233		"The brand of the compactable.",
234		"The error type inside the `Result` wrappers.",
235		"The success type inside the `Result` wrappers."
236	)]
237	#[document_parameters("The borrowed container of `Result` values.")]
238	impl<'a, Brand, E, O> SeparateDispatch<'a, Brand, E, O, Ref> for &Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Result<O, E>>)
239	where
240		Brand: RefCompactable,
241		E: 'a + Clone,
242		O: 'a + Clone,
243	{
244		#[document_signature]
245		///
246		#[document_returns("A tuple of two containers: `Err` values and `Ok` values.")]
247		#[document_examples]
248		///
249		/// ```
250		/// use fp_library::{
251		/// 	brands::*,
252		/// 	functions::explicit::*,
253		/// };
254		///
255		/// let v: Vec<Result<i32, i32>> = vec![Ok(1), Err(2), Ok(3)];
256		/// let (errs, oks) = separate::<VecBrand, _, _, _, _>(&v);
257		/// assert_eq!(oks, vec![1, 3]);
258		/// assert_eq!(errs, vec![2]);
259		/// ```
260		fn dispatch(
261			self
262		) -> (
263			Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E>),
264			Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, O>),
265		) {
266			Brand::ref_separate(self)
267		}
268	}
269
270	// -- Inference wrappers --
271
272	/// Removes `None` values from a container of `Option`s, inferring the brand
273	/// from the container type.
274	///
275	/// The `Brand` type parameter is inferred from the concrete type of `fa`
276	/// via [`InferableBrand`](crate::kinds::InferableBrand_cdc7cd43dac7585f). Both owned and borrowed containers are supported.
277	///
278	/// For types with multiple brands, use
279	/// [`explicit::compact`](crate::functions::explicit::compact) with a turbofish.
280	#[document_signature]
281	///
282	#[document_type_parameters(
283		"The lifetime of the values.",
284		"The container type (owned or borrowed). Brand is inferred from this.",
285		"The type of the value(s) inside the `Option` wrappers.",
286		"Dispatch marker type, inferred automatically."
287	)]
288	///
289	#[document_parameters("The container of `Option` values (owned or borrowed).")]
290	///
291	#[document_returns("A new container with `None` values removed and `Some` values unwrapped.")]
292	#[document_examples]
293	///
294	/// ```
295	/// use fp_library::functions::*;
296	///
297	/// assert_eq!(compact(vec![Some(1), None, Some(3)]), vec![1, 3]);
298	///
299	/// let v = vec![Some(1), None, Some(3)];
300	/// assert_eq!(compact(&v), vec![1, 3]);
301	/// ```
302	pub fn compact<'a, FA, A: 'a, Marker>(
303		fa: FA
304	) -> <<FA as InferableBrand_cdc7cd43dac7585f>::Brand as Kind_cdc7cd43dac7585f>::Of<'a, A>
305	where
306		FA: InferableBrand_cdc7cd43dac7585f
307			+ CompactDispatch<'a, <FA as InferableBrand_cdc7cd43dac7585f>::Brand, A, Marker>, {
308		fa.dispatch()
309	}
310
311	/// Separates a container of `Result` values into two containers, inferring
312	/// the brand from the container type.
313	///
314	/// The `Brand` type parameter is inferred from the concrete type of `fa`
315	/// via [`InferableBrand`](crate::kinds::InferableBrand_cdc7cd43dac7585f). Both owned and borrowed containers are supported.
316	///
317	/// For types with multiple brands, use
318	/// [`explicit::separate`](crate::functions::explicit::separate) with a turbofish.
319	#[document_signature]
320	///
321	#[document_type_parameters(
322		"The lifetime of the values.",
323		"The container type (owned or borrowed). Brand is inferred from this.",
324		"The error type inside the `Result` wrappers.",
325		"The success type inside the `Result` wrappers.",
326		"Dispatch marker type, inferred automatically."
327	)]
328	///
329	#[document_parameters("The container of `Result` values (owned or borrowed).")]
330	///
331	#[document_returns("A tuple of two containers: `Err` values and `Ok` values.")]
332	#[document_examples]
333	///
334	/// ```
335	/// use fp_library::functions::*;
336	///
337	/// let (errs, oks) = separate(vec![Ok(1), Err(2), Ok(3)]);
338	/// assert_eq!(oks, vec![1, 3]);
339	/// assert_eq!(errs, vec![2]);
340	/// ```
341	pub fn separate<'a, FA, E: 'a, O: 'a, Marker>(
342		fa: FA
343	) -> (
344		<<FA as InferableBrand_cdc7cd43dac7585f>::Brand as Kind_cdc7cd43dac7585f>::Of<'a, E>,
345		<<FA as InferableBrand_cdc7cd43dac7585f>::Brand as Kind_cdc7cd43dac7585f>::Of<'a, O>,
346	)
347	where
348		FA: InferableBrand_cdc7cd43dac7585f
349			+ SeparateDispatch<'a, <FA as InferableBrand_cdc7cd43dac7585f>::Brand, E, O, Marker>, {
350		fa.dispatch()
351	}
352
353	// -- Explicit dispatch free functions --
354
355	/// Explicit dispatch functions requiring a Brand turbofish.
356	///
357	/// For most use cases, prefer the inference-enabled wrappers from
358	/// [`functions`](crate::functions).
359	pub mod explicit {
360		use super::*;
361
362		/// Removes `None` values from a container of `Option`s, unwrapping the `Some` values.
363		///
364		/// Dispatches to either [`Compactable::compact`] or [`RefCompactable::ref_compact`]
365		/// based on whether the container is owned or borrowed.
366		///
367		/// The dispatch is resolved at compile time with no runtime cost.
368		#[document_signature]
369		///
370		#[document_type_parameters(
371			"The lifetime of the values.",
372			"The brand of the compactable.",
373			"The type of the value(s) inside the `Option` wrappers.",
374			"The container type (owned or borrowed), inferred from the argument.",
375			"Dispatch marker type, inferred automatically."
376		)]
377		///
378		#[document_parameters("The container of `Option` values (owned or borrowed).")]
379		///
380		#[document_returns(
381			"A new container with `None` values removed and `Some` values unwrapped."
382		)]
383		///
384		#[document_examples]
385		///
386		/// ```
387		/// use fp_library::{
388		/// 	brands::*,
389		/// 	functions::explicit::*,
390		/// };
391		///
392		/// // Owned
393		/// let y = compact::<VecBrand, _, _, _>(vec![Some(1), None, Some(3)]);
394		/// assert_eq!(y, vec![1, 3]);
395		///
396		/// // By-ref
397		/// let v = vec![Some(1), None, Some(3)];
398		/// let y = compact::<VecBrand, _, _, _>(&v);
399		/// assert_eq!(y, vec![1, 3]);
400		/// ```
401		#[allow_named_generics]
402		pub fn compact<'a, Brand: Kind_cdc7cd43dac7585f, A: 'a, FA, Marker>(
403			fa: FA
404		) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>)
405		where
406			FA: CompactDispatch<'a, Brand, A, Marker>, {
407			fa.dispatch()
408		}
409
410		/// Separates a container of `Result` values into two containers.
411		///
412		/// Dispatches to either [`Compactable::separate`] or [`RefCompactable::ref_separate`]
413		/// based on whether the container is owned or borrowed.
414		///
415		/// The dispatch is resolved at compile time with no runtime cost.
416		#[document_signature]
417		///
418		#[document_type_parameters(
419			"The lifetime of the values.",
420			"The brand of the compactable.",
421			"The error type inside the `Result` wrappers.",
422			"The success type inside the `Result` wrappers.",
423			"The container type (owned or borrowed), inferred from the argument.",
424			"Dispatch marker type, inferred automatically."
425		)]
426		///
427		#[document_parameters("The container of `Result` values (owned or borrowed).")]
428		///
429		#[document_returns("A tuple of two containers: `Err` values and `Ok` values.")]
430		///
431		#[document_examples]
432		///
433		/// ```
434		/// use fp_library::{
435		/// 	brands::*,
436		/// 	functions::explicit::*,
437		/// };
438		///
439		/// // Owned
440		/// let (errs, oks) = separate::<VecBrand, _, _, _, _>(vec![Ok(1), Err(2), Ok(3)]);
441		/// assert_eq!(oks, vec![1, 3]);
442		/// assert_eq!(errs, vec![2]);
443		///
444		/// // By-ref
445		/// let v: Vec<Result<i32, i32>> = vec![Ok(1), Err(2), Ok(3)];
446		/// let (errs, oks) = separate::<VecBrand, _, _, _, _>(&v);
447		/// assert_eq!(oks, vec![1, 3]);
448		/// assert_eq!(errs, vec![2]);
449		/// ```
450		#[allow_named_generics]
451		pub fn separate<'a, Brand: Kind_cdc7cd43dac7585f, E: 'a, O: 'a, FA, Marker>(
452			fa: FA
453		) -> (
454			Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E>),
455			Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, O>),
456		)
457		where
458			FA: SeparateDispatch<'a, Brand, E, O, Marker>, {
459			fa.dispatch()
460		}
461	}
462}
463
464pub use inner::*;