Skip to main content

fp_library/classes/
compactable.rs

1//! Data structures that can be compacted by filtering out [`None`] or separated by splitting [`Result`] values.
2//!
3//! ### Examples
4//!
5//! ```
6//! use fp_library::{brands::*, functions::*};
7//!
8//! let x = Some(Some(5));
9//! let y = compact::<OptionBrand, _>(x);
10//! assert_eq!(y, Some(5));
11//! ```
12
13use crate::{Apply, brands::OptionBrand, kinds::*, types::Pair};
14use fp_macros::doc_params;
15use fp_macros::doc_type_params;
16use fp_macros::hm_signature;
17
18/// A type class for data structures that can be compacted and separated.
19///
20/// `Compactable` allows for:
21/// *   `compact`: Filtering out [`None`] values and unwrapping [`Some`] values from a structure of [`Option`]s.
22/// *   `separate`: Splitting a structure of [`Result`]s into a pair of structures, one containing the [`Err`] values and the other containing the [`Ok`] values.
23pub trait Compactable: Kind_cdc7cd43dac7585f {
24	/// Compacts a data structure of [`Option`]s, discarding [`None`] values and keeping [`Some`] values.
25	///
26	/// ### Type Signature
27	///
28	#[hm_signature(Compactable)]
29	///
30	/// ### Type Parameters
31	///
32	#[doc_type_params(
33		"The lifetime of the elements.",
34		"The type of the elements in the [`Option`]."
35	)]
36	///
37	/// ### Parameters
38	///
39	#[doc_params("The data structure containing [`Option`] values.")]
40	///
41	/// ### Returns
42	///
43	/// A new data structure containing only the values from the [`Some`] variants.
44	///
45	/// ### Examples
46	///
47	/// ```
48	/// use fp_library::{brands::*, functions::*};
49	///
50	/// let x = Some(Some(5));
51	/// let y = compact::<OptionBrand, _>(x);
52	/// assert_eq!(y, Some(5));
53	///
54	/// let z = Some(None::<i32>);
55	/// let w = compact::<OptionBrand, _>(z);
56	/// assert_eq!(w, None);
57	/// ```
58	fn compact<'a, A: 'a>(
59		fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<
60			'a,
61			Apply!(<OptionBrand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
62		>)
63	) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>);
64
65	/// Separates a data structure of [`Result`]s into two data structures: one containing the [`Ok`] values and one containing the [`Err`] values.
66	///
67	/// ### Type Signature
68	///
69	#[hm_signature(Compactable)]
70	///
71	/// ### Type Parameters
72	///
73	#[doc_type_params(
74		"The lifetime of the elements.",
75		"The type of the success values.",
76		"The type of the error values."
77	)]
78	///
79	/// ### Parameters
80	///
81	#[doc_params("The data structure containing [`Result`] values.")]
82	///
83	/// ### Returns
84	///
85	/// A pair of data structures: the first containing the [`Ok`] values, and the second containing the [`Err`] values.
86	///
87	/// ### Examples
88	///
89	/// ```
90	/// use fp_library::{brands::*, functions::*, types::*};
91	///
92	/// let x: Option<Result<i32, &str>> = Some(Ok(5));
93	/// let Pair(oks, errs) = separate::<OptionBrand, _, _>(x);
94	/// assert_eq!(oks, Some(5));
95	/// assert_eq!(errs, None);
96	///
97	/// let y: Option<Result<i32, &str>> = Some(Err("error"));
98	/// let Pair(oks2, errs2) = separate::<OptionBrand, _, _>(y);
99	/// assert_eq!(oks2, None);
100	/// assert_eq!(errs2, Some("error"));
101	/// ```
102	fn separate<'a, O: 'a, E: 'a>(
103		fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Result<O, E>>)
104	) -> Pair<
105		Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, O>),
106		Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E>),
107	>;
108}
109
110/// Compacts a data structure of [`Option`]s, discarding [`None`] values and keeping [`Some`] values.
111///
112/// Free function version that dispatches to [the type class' associated function][`Compactable::compact`].
113///
114/// ### Type Signature
115///
116#[hm_signature(Compactable)]
117///
118/// ### Type Parameters
119///
120#[doc_type_params(
121	"The lifetime of the elements.",
122	"The brand of the compactable structure.",
123	"The type of the elements in the [`Option`]."
124)]
125///
126/// ### Parameters
127///
128#[doc_params("The data structure containing [`Option`] values.")]
129///
130/// ### Returns
131///
132/// A new data structure containing only the values from the [`Some`] variants.
133///
134/// ### Examples
135///
136/// ```
137/// use fp_library::{brands::*, functions::*};
138///
139/// let x = Some(Some(5));
140/// let y = compact::<OptionBrand, _>(x);
141/// assert_eq!(y, Some(5));
142/// ```
143pub fn compact<'a, Brand: Compactable, A: 'a>(
144	fa: Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<
145		'a,
146		Apply!(<OptionBrand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
147	>)
148) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>) {
149	Brand::compact(fa)
150}
151
152/// Separates a data structure of [`Result`]s into two data structures: one containing the [`Ok`] values and one containing the [`Err`] values.
153///
154/// Free function version that dispatches to [the type class' associated function][`Compactable::separate`].
155///
156/// ### Type Signature
157///
158#[hm_signature(Compactable)]
159///
160/// ### Type Parameters
161///
162#[doc_type_params(
163	"The lifetime of the elements.",
164	"The brand of the compactable structure.",
165	"The type of the success values.",
166	"The type of the error values."
167)]
168///
169/// ### Parameters
170///
171#[doc_params("The data structure containing [`Result`] values.")]
172///
173/// ### Returns
174///
175/// A pair of data structures: the first containing the [`Ok`] values, and the second containing the [`Err`] values.
176///
177/// ### Examples
178///
179/// ```
180/// use fp_library::{brands::*, functions::*, types::*};
181///
182/// let x: Option<Result<i32, &str>> = Some(Ok(5));
183/// let Pair(oks, errs) = separate::<OptionBrand, _, _>(x);
184/// assert_eq!(oks, Some(5));
185/// assert_eq!(errs, None);
186/// ```
187pub fn separate<'a, Brand: Compactable, O: 'a, E: 'a>(
188	fa: Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Result<O, E>>)
189) -> Pair<
190	Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, O>),
191	Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E>),
192> {
193	Brand::separate::<O, E>(fa)
194}