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