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