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