Skip to main content

fp_library/types/optics/
stall.rs

1//! The `Stall` profunctor, used for affine traversals.
2//!
3//! `Stall<A, B, S, T>` wraps a preview function `S -> Result<A, T>` and a setter function `S -> B -> T`.
4
5#[fp_macros::document_module]
6mod inner {
7	use {
8		crate::{
9			Apply,
10			brands::optics::*,
11			classes::{
12				profunctor::{
13					Choice,
14					Profunctor,
15					Strong,
16				},
17				*,
18			},
19			impl_kind,
20			kinds::*,
21		},
22		fp_macros::*,
23	};
24
25	/// The `Stall` profunctor.
26	#[document_type_parameters(
27		"The lifetime of the functions.",
28		"The cloneable function brand.",
29		"The type of the value produced by the preview function.",
30		"The type of the value consumed by the setter.",
31		"The source type of the structure.",
32		"The target type of the structure."
33	)]
34	pub struct Stall<'a, FunctionBrand: LiftFn, A: 'a, B: 'a, S: 'a, T: 'a> {
35		/// Preview function: tries to extract the focus.
36		pub get: <FunctionBrand as CloneFn>::Of<'a, S, Result<A, T>>,
37		/// Setter function.
38		pub set: <FunctionBrand as CloneFn>::Of<'a, (S, B), T>,
39	}
40
41	#[document_type_parameters(
42		"The lifetime of the functions.",
43		"The cloneable function brand.",
44		"The type of the value produced by the preview function.",
45		"The type of the value consumed by the setter.",
46		"The source type of the structure.",
47		"The target type of the structure."
48	)]
49	impl<'a, FunctionBrand: LiftFn, A: 'a, B: 'a, S: 'a, T: 'a> Stall<'a, FunctionBrand, A, B, S, T> {
50		/// Creates a new `Stall` instance.
51		#[document_signature]
52		///
53		#[document_parameters("The preview function.", "The setter function.")]
54		///
55		#[document_returns("A new instance of the type.")]
56		///
57		#[document_examples]
58		///
59		/// ```
60		/// use fp_library::{
61		/// 	brands::RcFnBrand,
62		/// 	classes::clone_fn::new as lift_fn_new,
63		/// 	types::optics::Stall,
64		/// };
65		///
66		/// let stall = Stall::<RcFnBrand, i32, i32, (i32, i32), (i32, i32)>::new(
67		/// 	lift_fn_new::<RcFnBrand, _, _>(|s: (i32, i32)| Ok(s.0)),
68		/// 	lift_fn_new::<RcFnBrand, _, _>(|(s, b): ((i32, i32), i32)| (b, s.1)),
69		/// );
70		/// assert_eq!((stall.get)((10, 20)), Ok(10));
71		/// assert_eq!((stall.set)(((10, 20), 30)), (30, 20));
72		/// ```
73		pub fn new(
74			get: <FunctionBrand as CloneFn>::Of<'a, S, Result<A, T>>,
75			set: <FunctionBrand as CloneFn>::Of<'a, (S, B), T>,
76		) -> Self {
77			Stall {
78				get,
79				set,
80			}
81		}
82	}
83
84	impl_kind! {
85		impl<FunctionBrand: LiftFn + 'static, A: 'static, B: 'static> for StallBrand<FunctionBrand, A, B> {
86			#[document_default]
87			type Of<'a, S: 'a, T: 'a>: 'a = Stall<'a, FunctionBrand, A, B, S, T>;
88		}
89	}
90
91	#[document_type_parameters(
92		"The cloneable function brand.",
93		"The type of the value produced by the preview function.",
94		"The type of the value consumed by the setter."
95	)]
96	impl<FunctionBrand: LiftFn + 'static, A: 'static, B: 'static> Profunctor
97		for StallBrand<FunctionBrand, A, B>
98	{
99		/// Maps functions over the input and output of the `Stall` profunctor.
100		#[document_signature]
101		#[document_type_parameters(
102			"The lifetime of the functions.",
103			"The source type of the new structure.",
104			"The target type of the new structure.",
105			"The source type of the original structure.",
106			"The target type of the original structure."
107		)]
108		///
109		#[document_parameters(
110			"The function to apply to the input.",
111			"The function to apply to the output.",
112			"The stall instance to transform."
113		)]
114		#[document_returns("A transformed `Stall` instance.")]
115		///
116		#[document_examples]
117		///
118		/// ```
119		/// use fp_library::{
120		/// 	brands::{
121		/// 		optics::*,
122		/// 		*,
123		/// 	},
124		/// 	classes::{
125		/// 		clone_fn::new as lift_fn_new,
126		/// 		optics::*,
127		/// 		profunctor::*,
128		/// 	},
129		/// 	types::optics::*,
130		/// };
131		///
132		/// // Stall is usually used internally by AffineTraversal optics
133		/// let stall = Stall::<RcFnBrand, i32, i32, (i32, i32), (i32, i32)>::new(
134		/// 	lift_fn_new::<RcFnBrand, _, _>(|s: (i32, i32)| Ok(s.0)),
135		/// 	lift_fn_new::<RcFnBrand, _, _>(|(s, b): ((i32, i32), i32)| (b, s.1)),
136		/// );
137		/// let transformed = <StallBrand<RcFnBrand, i32, i32> as Profunctor>::dimap(
138		/// 	|s: (i32, i32)| s,
139		/// 	|t: (i32, i32)| t,
140		/// 	stall,
141		/// );
142		/// assert_eq!((transformed.get)((10, 20)), Ok(10));
143		/// ```
144		fn dimap<'a, S: 'a, T: 'a, U: 'a, V: 'a>(
145			st: impl Fn(S) -> T + 'a,
146			uv: impl Fn(U) -> V + 'a,
147			puv: Apply!(<Self as Kind!( type Of<'a, T: 'a, U: 'a>: 'a; )>::Of<'a, T, U>),
148		) -> Apply!(<Self as Kind!( type Of<'a, T: 'a, U: 'a>: 'a; )>::Of<'a, S, V>) {
149			let get = puv.get;
150			let set = puv.set;
151			let st = <FunctionBrand as LiftFn>::new(st);
152			let uv = <FunctionBrand as LiftFn>::new(uv);
153			let st_2 = st.clone();
154			let uv_2 = uv.clone();
155			Stall::new(
156				<FunctionBrand as LiftFn>::new(move |s: S| (*get)((*st)(s)).map_err(|u| (*uv)(u))),
157				<FunctionBrand as LiftFn>::new(move |(s, b): (S, B)| {
158					(*uv_2)((*set)(((*st_2)(s), b)))
159				}),
160			)
161		}
162	}
163
164	#[document_type_parameters(
165		"The cloneable function brand.",
166		"The type of the value produced by the preview function.",
167		"The type of the value consumed by the setter."
168	)]
169	impl<FunctionBrand: LiftFn + 'static, A: 'static, B: 'static> Strong
170		for StallBrand<FunctionBrand, A, B>
171	{
172		/// Lifts the `Stall` profunctor to operate on the first component of a tuple.
173		#[document_signature]
174		#[document_type_parameters(
175			"The lifetime of the functions.",
176			"The source type of the structure.",
177			"The target type of the structure.",
178			"The type of the other component."
179		)]
180		///
181		#[document_parameters("The stall instance to transform.")]
182		#[document_returns("A transformed `Stall` instance that operates on tuples.")]
183		///
184		#[document_examples]
185		///
186		/// ```
187		/// use fp_library::{
188		/// 	brands::{
189		/// 		optics::*,
190		/// 		*,
191		/// 	},
192		/// 	classes::{
193		/// 		clone_fn::new as lift_fn_new,
194		/// 		optics::*,
195		/// 		profunctor::*,
196		/// 	},
197		/// 	types::optics::*,
198		/// };
199		///
200		/// let stall = Stall::<RcFnBrand, i32, i32, i32, i32>::new(
201		/// 	lift_fn_new::<RcFnBrand, _, _>(|s: i32| Ok(s)),
202		/// 	lift_fn_new::<RcFnBrand, _, _>(|(_s, b): (i32, i32)| b),
203		/// );
204		/// let lifted = <StallBrand<RcFnBrand, i32, i32> as Strong>::first::<i32, i32, String>(stall);
205		/// assert_eq!((lifted.get)((10, "hi".to_string())), Ok(10));
206		/// ```
207		fn first<'a, S: 'a, T: 'a, C: 'a>(
208			pab: Apply!(<Self as Kind!( type Of<'a, T: 'a, U: 'a>: 'a; )>::Of<'a, S, T>)
209		) -> Apply!(<Self as Kind!( type Of<'a, T: 'a, U: 'a>: 'a; )>::Of<'a, (S, C), (T, C)>) {
210			let get = pab.get;
211			let set = pab.set;
212			Stall::new(
213				<FunctionBrand as LiftFn>::new(move |(s, c): (S, C)| (*get)(s).map_err(|t| (t, c))),
214				<FunctionBrand as LiftFn>::new(move |((s, c), b): ((S, C), B)| ((*set)((s, b)), c)),
215			)
216		}
217	}
218
219	#[document_type_parameters(
220		"The cloneable function brand.",
221		"The type of the value produced by the preview function.",
222		"The type of the value consumed by the setter."
223	)]
224	impl<FunctionBrand: LiftFn + 'static, A: 'static, B: 'static> Choice
225		for StallBrand<FunctionBrand, A, B>
226	{
227		/// Lifts the `Stall` profunctor to operate on the left component of a `Result`.
228		#[document_signature]
229		#[document_type_parameters(
230			"The lifetime of the functions.",
231			"The source type of the structure.",
232			"The target type of the structure.",
233			"The type of the other component."
234		)]
235		///
236		#[document_parameters("The stall instance to transform.")]
237		#[document_returns(
238			"A transformed `Stall` instance that operates on the left component of a `Result`."
239		)]
240		///
241		#[document_examples]
242		///
243		/// ```
244		/// use fp_library::{
245		/// 	brands::{
246		/// 		optics::*,
247		/// 		*,
248		/// 	},
249		/// 	classes::{
250		/// 		clone_fn::new as lift_fn_new,
251		/// 		optics::*,
252		/// 		profunctor::*,
253		/// 	},
254		/// 	types::optics::*,
255		/// };
256		///
257		/// let stall = Stall::<RcFnBrand, i32, i32, i32, i32>::new(
258		/// 	lift_fn_new::<RcFnBrand, _, _>(|s: i32| Ok(s)),
259		/// 	lift_fn_new::<RcFnBrand, _, _>(|(_s, b): (i32, i32)| b),
260		/// );
261		/// let lifted = <StallBrand<RcFnBrand, i32, i32> as Choice>::left::<i32, i32, String>(stall);
262		/// assert!((lifted.get)(Err(10)).is_ok());
263		/// ```
264		fn left<'a, S: 'a, T: 'a, C: 'a>(
265			pab: Apply!(<Self as Kind!( type Of<'a, T: 'a, U: 'a>: 'a; )>::Of<'a, S, T>)
266		) -> Apply!(<Self as Kind!( type Of<'a, T: 'a, U: 'a>: 'a; )>::Of<'a, Result<C, S>, Result<C, T>>)
267		{
268			let get = pab.get;
269			let set = pab.set;
270			Stall::new(
271				<FunctionBrand as LiftFn>::new(move |r: Result<C, S>| match r {
272					Err(s) => (*get)(s).map_err(Err),
273					Ok(c) => Err(Ok(c)),
274				}),
275				<FunctionBrand as LiftFn>::new(move |(r, b): (Result<C, S>, B)| match r {
276					Err(s) => Err((*set)((s, b))),
277					Ok(c) => Ok(c),
278				}),
279			)
280		}
281
282		/// Lifts the `Stall` profunctor to operate on the right component of a `Result`.
283		#[document_signature]
284		#[document_type_parameters(
285			"The lifetime of the functions.",
286			"The source type of the structure.",
287			"The target type of the structure.",
288			"The type of the other component."
289		)]
290		///
291		#[document_parameters("The stall instance to transform.")]
292		#[document_returns(
293			"A transformed `Stall` instance that operates on the right component of a `Result`."
294		)]
295		///
296		#[document_examples]
297		///
298		/// ```
299		/// use fp_library::{
300		/// 	brands::{
301		/// 		optics::*,
302		/// 		*,
303		/// 	},
304		/// 	classes::{
305		/// 		clone_fn::new as lift_fn_new,
306		/// 		optics::*,
307		/// 		profunctor::*,
308		/// 	},
309		/// 	types::optics::*,
310		/// };
311		///
312		/// let stall = Stall::<RcFnBrand, i32, i32, i32, i32>::new(
313		/// 	lift_fn_new::<RcFnBrand, _, _>(|s| Ok(s)),
314		/// 	lift_fn_new::<RcFnBrand, _, _>(|(_, b)| b),
315		/// );
316		/// let lifted = <StallBrand<RcFnBrand, i32, i32> as Choice>::right::<i32, i32, i32>(stall);
317		/// assert_eq!((lifted.get)(Ok(42)), Ok(42));
318		/// ```
319		fn right<'a, S: 'a, T: 'a, C: 'a>(
320			pab: Apply!(<Self as Kind!( type Of<'a, T: 'a, U: 'a>: 'a; )>::Of<'a, S, T>)
321		) -> Apply!(<Self as Kind!( type Of<'a, T: 'a, U: 'a>: 'a; )>::Of<'a, Result<S, C>, Result<T, C>>)
322		{
323			let get = pab.get;
324			let set = pab.set;
325			Stall::new(
326				<FunctionBrand as LiftFn>::new(move |r: Result<S, C>| match r {
327					Ok(s) => (*get)(s).map_err(Ok),
328					Err(c) => Err(Err(c)),
329				}),
330				<FunctionBrand as LiftFn>::new(move |(r, b): (Result<S, C>, B)| match r {
331					Ok(s) => Ok((*set)((s, b))),
332					Err(c) => Err(c),
333				}),
334			)
335		}
336	}
337}
338pub use inner::*;