Skip to main content

fp_library/dispatch/
apply_second.rs

1//! Dispatch for [`ApplySecond::apply_second`](crate::classes::ApplySecond::apply_second) and
2//! [`RefApplySecond::ref_apply_second`](crate::classes::RefApplySecond::ref_apply_second).
3//!
4//! Provides the [`ApplySecondDispatch`] trait and a unified
5//! [`explicit::apply_second`] free function that routes to the appropriate trait
6//! method based on whether the containers are owned or borrowed.
7//!
8//! ### Examples
9//!
10//! ```
11//! use fp_library::{
12//! 	brands::*,
13//! 	functions::explicit::*,
14//! };
15//!
16//! // Owned: dispatches to ApplySecond::apply_second
17//! let y = apply_second::<OptionBrand, _, _, _, _>(Some(5), Some(10));
18//! assert_eq!(y, Some(10));
19//!
20//! // By-ref: dispatches to RefApplySecond::ref_apply_second
21//! let a = Some(5);
22//! let b = Some(10);
23//! let y = apply_second::<OptionBrand, _, _, _, _>(&a, &b);
24//! assert_eq!(y, Some(10));
25//! ```
26
27#[fp_macros::document_module]
28pub(crate) mod inner {
29	use {
30		crate::{
31			classes::{
32				ApplySecond,
33				RefApplySecond,
34			},
35			dispatch::{
36				Ref,
37				Val,
38			},
39			kinds::*,
40		},
41		fp_macros::*,
42	};
43
44	/// Trait that routes an apply_second operation to the appropriate type class method.
45	///
46	/// The `Marker` type parameter is an implementation detail resolved by
47	/// the compiler from the container type; callers never specify it directly.
48	/// Owned containers resolve to [`Val`], borrowed containers resolve to [`Ref`].
49	#[document_type_parameters(
50		"The lifetime of the values.",
51		"The brand of the applicative.",
52		"The type of the value(s) inside the first container.",
53		"The type of the value(s) inside the second container.",
54		"Dispatch marker type, inferred automatically. Either [`Val`](crate::dispatch::Val) or [`Ref`](crate::dispatch::Ref)."
55	)]
56	#[document_parameters("The first container implementing this dispatch.")]
57	pub trait ApplySecondDispatch<'a, Brand: Kind_cdc7cd43dac7585f, A: 'a, B: 'a, Marker> {
58		/// The type of the second container argument.
59		type FB;
60
61		/// Perform the dispatched apply_second operation.
62		#[document_signature]
63		///
64		#[document_parameters("The second container (its result is kept).")]
65		///
66		#[document_returns("A container preserving the values from the second input.")]
67		#[document_examples]
68		///
69		/// ```
70		/// use fp_library::{
71		/// 	brands::*,
72		/// 	functions::explicit::*,
73		/// };
74		///
75		/// let result = apply_second::<OptionBrand, _, _, _, _>(Some(5), Some(10));
76		/// assert_eq!(result, Some(10));
77		/// ```
78		fn dispatch(
79			self,
80			fb: Self::FB,
81		) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>);
82	}
83
84	// -- Val: owned containers -> ApplySecond::apply_second --
85
86	/// Routes owned containers to [`ApplySecond::apply_second`].
87	#[document_type_parameters(
88		"The lifetime of the values.",
89		"The brand of the applicative.",
90		"The type of the value(s) inside the first container.",
91		"The type of the value(s) inside the second container."
92	)]
93	#[document_parameters("The owned first container.")]
94	impl<'a, Brand, A, B> ApplySecondDispatch<'a, Brand, A, B, Val> for Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>)
95	where
96		Brand: ApplySecond,
97		A: 'a + Clone,
98		B: 'a + Clone,
99	{
100		type FB = Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>);
101
102		#[document_signature]
103		///
104		#[document_parameters("The second container (its result is kept).")]
105		///
106		#[document_returns("A container preserving the values from the second input.")]
107		#[document_examples]
108		///
109		/// ```
110		/// use fp_library::{
111		/// 	brands::*,
112		/// 	functions::explicit::*,
113		/// };
114		///
115		/// let result = apply_second::<OptionBrand, _, _, _, _>(Some(5), Some(10));
116		/// assert_eq!(result, Some(10));
117		/// ```
118		fn dispatch(
119			self,
120			fb: Self::FB,
121		) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
122			Brand::apply_second::<A, B>(self, fb)
123		}
124	}
125
126	// -- Ref: borrowed containers -> RefApplySecond::ref_apply_second --
127
128	/// Routes borrowed containers to [`RefApplySecond::ref_apply_second`].
129	#[document_type_parameters(
130		"The lifetime of the values.",
131		"The borrow lifetime.",
132		"The brand of the applicative.",
133		"The type of the value(s) inside the first container.",
134		"The type of the value(s) inside the second container."
135	)]
136	#[document_parameters("The borrowed first container.")]
137	impl<'a, 'b, Brand, A, B> ApplySecondDispatch<'a, Brand, A, B, Ref> for &'b Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>)
138	where
139		'a: 'b,
140		Brand: RefApplySecond,
141		A: 'a,
142		B: 'a + Clone,
143	{
144		type FB = &'b Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>);
145
146		#[document_signature]
147		///
148		#[document_parameters("The second borrowed container (its result is kept).")]
149		///
150		#[document_returns("A container preserving the values from the second input.")]
151		#[document_examples]
152		///
153		/// ```
154		/// use fp_library::{
155		/// 	brands::*,
156		/// 	functions::explicit::*,
157		/// };
158		///
159		/// let a = Some(5);
160		/// let b = Some(10);
161		/// let result = apply_second::<OptionBrand, _, _, _, _>(&a, &b);
162		/// assert_eq!(result, Some(10));
163		/// ```
164		fn dispatch(
165			self,
166			fb: Self::FB,
167		) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
168			Brand::ref_apply_second(self, fb)
169		}
170	}
171
172	// -- Inference wrapper --
173
174	/// Sequences two applicative actions, keeping the result of the second,
175	/// inferring the brand from the container type.
176	///
177	/// The `Brand` type parameter is inferred from the concrete type of `fa`
178	/// via [`InferableBrand`](crate::kinds::InferableBrand_cdc7cd43dac7585f). Both owned and borrowed containers are supported.
179	///
180	/// For types with multiple brands, use
181	/// [`explicit::apply_second`](crate::functions::explicit::apply_second) with a turbofish.
182	#[document_signature]
183	///
184	#[document_type_parameters(
185		"The lifetime of the values.",
186		"The first container type (owned or borrowed). Brand is inferred from this.",
187		"The type of the value(s) inside the first container.",
188		"The type of the value(s) inside the second container.",
189		"Dispatch marker type, inferred automatically."
190	)]
191	///
192	#[document_parameters(
193		"The first container (its values are discarded).",
194		"The second container (its values are preserved)."
195	)]
196	///
197	#[document_returns("A container preserving the values from the second input.")]
198	#[document_examples]
199	///
200	/// ```
201	/// use fp_library::functions::*;
202	///
203	/// assert_eq!(apply_second(Some(5), Some(10)), Some(10));
204	///
205	/// let a = Some(5);
206	/// let b = Some(10);
207	/// assert_eq!(apply_second(&a, &b), Some(10));
208	/// ```
209	pub fn apply_second<'a, FA, A: 'a, B: 'a, Marker>(
210		fa: FA,
211		fb: <FA as ApplySecondDispatch<
212			'a,
213			<FA as InferableBrand_cdc7cd43dac7585f>::Brand,
214			A,
215			B,
216			Marker,
217		>>::FB,
218	) -> <<FA as InferableBrand_cdc7cd43dac7585f>::Brand as Kind_cdc7cd43dac7585f>::Of<'a, B>
219	where
220		FA: InferableBrand_cdc7cd43dac7585f
221			+ ApplySecondDispatch<'a, <FA as InferableBrand_cdc7cd43dac7585f>::Brand, A, B, Marker>, {
222		fa.dispatch(fb)
223	}
224
225	// -- Explicit dispatch free function --
226
227	/// Explicit dispatch functions requiring a Brand turbofish.
228	///
229	/// For most use cases, prefer the inference-enabled wrappers from
230	/// [`functions`](crate::functions).
231	pub mod explicit {
232		use super::*;
233
234		/// Sequences two applicative actions, keeping the result of the second.
235		///
236		/// Dispatches to either [`ApplySecond::apply_second`] or
237		/// [`RefApplySecond::ref_apply_second`] based on whether the containers
238		/// are owned or borrowed.
239		///
240		/// The `Marker` type parameter is inferred automatically by the
241		/// compiler from the container arguments. Callers write
242		/// `apply_second::<Brand, _, _>(...)` and never need to specify
243		/// `Marker` explicitly.
244		///
245		/// The dispatch is resolved at compile time with no runtime cost.
246		#[document_signature]
247		///
248		#[document_type_parameters(
249			"The lifetime of the values.",
250			"The brand of the applicative.",
251			"The type of the value(s) inside the first container.",
252			"The type of the value(s) inside the second container.",
253			"The first container type (owned or borrowed), inferred from the argument.",
254			"Dispatch marker type, inferred automatically."
255		)]
256		///
257		#[document_parameters(
258			"The first container (its values are discarded).",
259			"The second container (its values are preserved)."
260		)]
261		///
262		#[document_returns("A container preserving the values from the second input.")]
263		///
264		#[document_examples]
265		///
266		/// ```
267		/// use fp_library::{
268		/// 	brands::*,
269		/// 	functions::explicit::*,
270		/// };
271		///
272		/// // Owned: dispatches to ApplySecond::apply_second
273		/// let y = apply_second::<OptionBrand, _, _, _, _>(Some(5), Some(10));
274		/// assert_eq!(y, Some(10));
275		///
276		/// // By-ref: dispatches to RefApplySecond::ref_apply_second
277		/// let a = Some(5);
278		/// let b = Some(10);
279		/// let y = apply_second::<OptionBrand, _, _, _, _>(&a, &b);
280		/// assert_eq!(y, Some(10));
281		/// ```
282		pub fn apply_second<'a, Brand: Kind_cdc7cd43dac7585f, A: 'a, B: 'a, FA, Marker>(
283			fa: FA,
284			fb: <FA as ApplySecondDispatch<'a, Brand, A, B, Marker>>::FB,
285		) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>)
286		where
287			FA: ApplySecondDispatch<'a, Brand, A, B, Marker>, {
288			fa.dispatch(fb)
289		}
290	}
291}
292
293pub use inner::*;