Skip to main content

fp_library/classes/
ref_compactable.rs

1//! By-reference compacting and separating of structures.
2//!
3//! Similar to [`Compactable`](crate::classes::Compactable), but operates on borrowed containers. Elements are cloned
4//! out of the borrowed structure, so the element types must implement [`Clone`].
5//!
6//! ### Examples
7//!
8//! ```
9//! use fp_library::{
10//! 	brands::*,
11//! 	functions::explicit::*,
12//! };
13//!
14//! let v = vec![Some(1), None, Some(3)];
15//! let result = compact::<VecBrand, _, _, _>(&v);
16//! assert_eq!(result, vec![1, 3]);
17//! ```
18
19#[fp_macros::document_module]
20mod inner {
21	use {
22		crate::kinds::*,
23		fp_macros::*,
24	};
25
26	/// A type class for data structures that can be compacted and separated by reference.
27	///
28	/// Like [`Compactable`](crate::classes::Compactable), but takes the container by reference
29	/// (`&F<Option<A>>`) instead of by value. Because elements must be extracted from a
30	/// borrowed container, the element types require [`Clone`].
31	///
32	/// ### Laws
33	///
34	/// The same laws as [`Compactable`](crate::classes::Compactable) apply;
35	/// `ref_compact` and `ref_separate` must agree with their by-value counterparts
36	/// when applied to cloned inputs.
37	#[document_examples]
38	///
39	/// ```
40	/// use fp_library::{
41	/// 	brands::*,
42	/// 	functions::explicit::*,
43	/// };
44	///
45	/// let v = vec![Some(1), None, Some(3)];
46	/// let result = compact::<VecBrand, _, _, _>(&v);
47	/// assert_eq!(result, vec![1, 3]);
48	///
49	/// let v2: Vec<Result<i32, &str>> = vec![Ok(1), Err("bad"), Ok(3)];
50	/// let (errs, oks) = separate::<VecBrand, _, _, _, _>(&v2);
51	/// assert_eq!(oks, vec![1, 3]);
52	/// assert_eq!(errs, vec!["bad"]);
53	/// ```
54	#[kind(type Of<'a, A: 'a>: 'a;)]
55	pub trait RefCompactable {
56		/// Compacts a borrowed data structure of [`Option`]s, discarding [`None`] values and cloning [`Some`] values.
57		#[document_signature]
58		///
59		#[document_type_parameters(
60			"The lifetime of the elements.",
61			"The type of the elements in the [`Option`]. Must be [`Clone`] because elements are extracted from a borrowed container."
62		)]
63		///
64		#[document_parameters("A reference to the data structure containing [`Option`] values.")]
65		///
66		#[document_returns(
67			"A new data structure containing only the cloned values from the [`Some`] variants."
68		)]
69		#[document_examples]
70		///
71		/// ```
72		/// use fp_library::{
73		/// 	brands::*,
74		/// 	functions::explicit::*,
75		/// };
76		///
77		/// let v = vec![Some(1), None, Some(3)];
78		/// let result = compact::<VecBrand, _, _, _>(&v);
79		/// assert_eq!(result, vec![1, 3]);
80		///
81		/// let v2 = vec![None::<i32>, None, None];
82		/// let result2 = compact::<VecBrand, _, _, _>(&v2);
83		/// assert_eq!(result2, Vec::<i32>::new());
84		/// ```
85		fn ref_compact<'a, A: 'a + Clone>(
86			fa: &Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Option<A>>)
87		) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>);
88
89		/// Separates a borrowed data structure of [`Result`]s into two data structures: one containing the cloned [`Err`] values and one containing the cloned [`Ok`] values.
90		#[document_signature]
91		///
92		#[document_type_parameters(
93			"The lifetime of the elements.",
94			"The type of the error values. Must be [`Clone`] because elements are extracted from a borrowed container.",
95			"The type of the success values. Must be [`Clone`] because elements are extracted from a borrowed container."
96		)]
97		///
98		#[document_parameters("A reference to the data structure containing [`Result`] values.")]
99		///
100		#[document_returns(
101			"A pair of data structures: the first containing the cloned [`Err`] values, and the second containing the cloned [`Ok`] values."
102		)]
103		#[document_examples]
104		///
105		/// ```
106		/// use fp_library::{
107		/// 	brands::*,
108		/// 	functions::explicit::*,
109		/// };
110		///
111		/// let v: Vec<Result<i32, &str>> = vec![Ok(1), Err("bad"), Ok(3)];
112		/// let (errs, oks) = separate::<VecBrand, _, _, _, _>(&v);
113		/// assert_eq!(oks, vec![1, 3]);
114		/// assert_eq!(errs, vec!["bad"]);
115		/// ```
116		fn ref_separate<'a, E: 'a + Clone, O: 'a + Clone>(
117			fa: &Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Result<O, E>>)
118		) -> (
119			Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E>),
120			Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, O>),
121		);
122	}
123
124	/// Compacts a borrowed data structure of [`Option`]s, discarding [`None`] values and cloning [`Some`] values.
125	///
126	/// Free function version that dispatches to [the type class' associated function][`RefCompactable::ref_compact`].
127	#[document_signature]
128	///
129	#[document_type_parameters(
130		"The lifetime of the elements.",
131		"The brand of the compactable structure.",
132		"The type of the elements in the [`Option`]. Must be [`Clone`] because elements are extracted from a borrowed container."
133	)]
134	///
135	#[document_parameters("A reference to the data structure containing [`Option`] values.")]
136	///
137	#[document_returns(
138		"A new data structure containing only the cloned values from the [`Some`] variants."
139	)]
140	#[document_examples]
141	///
142	/// ```
143	/// use fp_library::{
144	/// 	brands::*,
145	/// 	functions::explicit::*,
146	/// };
147	///
148	/// let v = vec![Some(1), None, Some(3)];
149	/// let result = compact::<VecBrand, _, _, _>(&v);
150	/// assert_eq!(result, vec![1, 3]);
151	/// ```
152	pub fn ref_compact<'a, Brand: RefCompactable, A: 'a + Clone>(
153		fa: &Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Option<A>>)
154	) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>) {
155		Brand::ref_compact(fa)
156	}
157
158	/// Separates a borrowed data structure of [`Result`]s into two data structures: one containing the cloned [`Err`] values and one containing the cloned [`Ok`] values.
159	///
160	/// Free function version that dispatches to [the type class' associated function][`RefCompactable::ref_separate`].
161	#[document_signature]
162	///
163	#[document_type_parameters(
164		"The lifetime of the elements.",
165		"The brand of the compactable structure.",
166		"The type of the error values. Must be [`Clone`] because elements are extracted from a borrowed container.",
167		"The type of the success values. Must be [`Clone`] because elements are extracted from a borrowed container."
168	)]
169	///
170	#[document_parameters("A reference to the data structure containing [`Result`] values.")]
171	///
172	#[document_returns(
173		"A pair of data structures: the first containing the cloned [`Err`] values, and the second containing the cloned [`Ok`] values."
174	)]
175	#[document_examples]
176	///
177	/// ```
178	/// use fp_library::{
179	/// 	brands::*,
180	/// 	functions::explicit::*,
181	/// };
182	///
183	/// let v: Vec<Result<i32, &str>> = vec![Ok(1), Err("bad"), Ok(3)];
184	/// let (errs, oks) = separate::<VecBrand, _, _, _, _>(&v);
185	/// assert_eq!(oks, vec![1, 3]);
186	/// assert_eq!(errs, vec!["bad"]);
187	/// ```
188	pub fn ref_separate<'a, Brand: RefCompactable, E: 'a + Clone, O: 'a + Clone>(
189		fa: &Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Result<O, E>>)
190	) -> (
191		Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E>),
192		Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, O>),
193	) {
194		Brand::ref_separate::<E, O>(fa)
195	}
196}
197
198pub use inner::*;