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::*};
14use fp_macros::document_parameters;
15use fp_macros::document_signature;
16use fp_macros::document_type_parameters;
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 #[document_signature]
29 ///
30 /// ### Type Parameters
31 ///
32 #[document_type_parameters(
33 "The lifetime of the elements.",
34 "The type of the elements in the [`Option`]."
35 )]
36 ///
37 /// ### Parameters
38 ///
39 #[document_parameters("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 [`Err`] values and one containing the [`Ok`] values.
66 ///
67 /// ### Type Signature
68 ///
69 #[document_signature]
70 ///
71 /// ### Type Parameters
72 ///
73 #[document_type_parameters(
74 "The lifetime of the elements.",
75 "The type of the error values.",
76 "The type of the success values."
77 )]
78 ///
79 /// ### Parameters
80 ///
81 #[document_parameters("The data structure containing [`Result`] values.")]
82 ///
83 /// ### Returns
84 ///
85 /// A pair of data structures: the first containing the [`Err`] values, and the second containing the [`Ok`] values.
86 ///
87 /// ### Examples
88 ///
89 /// ```
90 /// use fp_library::{brands::*, functions::*};
91 ///
92 /// let x: Option<Result<i32, &str>> = Some(Ok(5));
93 /// let (errs, oks) = 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 (errs2, oks2) = separate::<OptionBrand, _, _>(y);
99 /// assert_eq!(oks2, None);
100 /// assert_eq!(errs2, Some("error"));
101 /// ```
102 fn separate<'a, E: 'a, O: 'a>(
103 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Result<O, E>>)
104 ) -> (
105 Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E>),
106 Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, O>),
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#[document_signature]
117///
118/// ### Type Parameters
119///
120#[document_type_parameters(
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#[document_parameters("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 [`Err`] values and one containing the [`Ok`] values.
153///
154/// Free function version that dispatches to [the type class' associated function][`Compactable::separate`].
155///
156/// ### Type Signature
157///
158#[document_signature]
159///
160/// ### Type Parameters
161///
162#[document_type_parameters(
163 "The lifetime of the elements.",
164 "The brand of the compactable structure.",
165 "The type of the error values.",
166 "The type of the success values."
167)]
168///
169/// ### Parameters
170///
171#[document_parameters("The data structure containing [`Result`] values.")]
172///
173/// ### Returns
174///
175/// A pair of data structures: the first containing the [`Err`] values, and the second containing the [`Ok`] values.
176///
177/// ### Examples
178///
179/// ```
180/// use fp_library::{brands::*, functions::*};
181///
182/// let x: Option<Result<i32, &str>> = Some(Ok(5));
183/// let (errs, oks) = separate::<OptionBrand, _, _>(x);
184/// assert_eq!(oks, Some(5));
185/// assert_eq!(errs, None);
186/// ```
187pub fn separate<'a, Brand: Compactable, E: 'a, O: 'a>(
188 fa: Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Result<O, E>>)
189) -> (
190 Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E>),
191 Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, O>),
192) {
193 Brand::separate::<E, O>(fa)
194}