Skip to main content

fp_library/types/optics/
getter.rs

1//! Getter optics for read-only access.
2//!
3//! A getter represents a way to view a value in a structure.
4
5#[fp_macros::document_module]
6mod inner {
7	use {
8		crate::{
9			Apply,
10			brands::{
11				FnBrand,
12				optics::*,
13			},
14			classes::{
15				monoid::Monoid,
16				optics::*,
17				*,
18			},
19			kinds::*,
20			types::optics::Forget,
21		},
22		fp_macros::*,
23		std::marker::PhantomData,
24	};
25
26	/// A polymorphic getter.
27	///
28	/// Matches PureScript's `Getter s t a b`.
29	#[document_type_parameters(
30		"The lifetime of the values.",
31		"The reference-counted pointer type.",
32		"The source type of the structure.",
33		"The target type of the structure.",
34		"The source type of the focus.",
35		"The target type of the focus."
36	)]
37	pub struct Getter<'a, PointerBrand, S, T, A, B>
38	where
39		PointerBrand: UnsizedCoercible,
40		S: 'a,
41		T: 'a,
42		A: 'a,
43		B: 'a, {
44		/// Function to view the focus of the getter in a structure.
45		pub view_fn: Apply!(<FnBrand<PointerBrand> as Kind!( type Of<'b, U: 'b, V: 'b>: 'b; )>::Of<'a, S, A>),
46		pub(crate) _phantom: PhantomData<&'a (T, B)>,
47	}
48
49	#[document_type_parameters(
50		"The lifetime of the values.",
51		"The reference-counted pointer type.",
52		"The source type of the structure.",
53		"The target type of the structure.",
54		"The source type of the focus.",
55		"The target type of the focus."
56	)]
57	#[document_parameters("The getter instance.")]
58	impl<'a, PointerBrand, S, T, A, B> Clone for Getter<'a, PointerBrand, S, T, A, B>
59	where
60		PointerBrand: UnsizedCoercible,
61		S: 'a,
62		T: 'a,
63		A: 'a,
64		B: 'a,
65	{
66		#[document_signature]
67		#[document_returns("A new `Getter` instance that is a copy of the original.")]
68		#[document_examples]
69		///
70		/// ```
71		/// use fp_library::{
72		/// 	brands::RcBrand,
73		/// 	types::optics::Getter,
74		/// };
75		///
76		/// let g: Getter<RcBrand, (i32, String), (i32, String), i32, i32> = Getter::new(|(x, _)| x);
77		/// let cloned = g.clone();
78		/// assert_eq!(cloned.view((42, "hi".to_string())), 42);
79		/// ```
80		fn clone(&self) -> Self {
81			Getter {
82				view_fn: self.view_fn.clone(),
83				_phantom: PhantomData,
84			}
85		}
86	}
87
88	#[document_type_parameters(
89		"The lifetime of the values.",
90		"The reference-counted pointer type.",
91		"The source type of the structure.",
92		"The target type of the structure.",
93		"The source type of the focus.",
94		"The target type of the focus."
95	)]
96	#[document_parameters("The getter instance.")]
97	impl<'a, PointerBrand, S, T, A, B> Getter<'a, PointerBrand, S, T, A, B>
98	where
99		PointerBrand: UnsizedCoercible,
100		S: 'a,
101		T: 'a,
102		A: 'a,
103		B: 'a,
104	{
105		/// Create a new getter from a view function.
106		#[document_signature]
107		///
108		#[document_parameters("The view function.")]
109		///
110		#[document_returns("A new instance of the type.")]
111		///
112		#[document_examples]
113		///
114		/// ```
115		/// use fp_library::{
116		/// 	brands::RcBrand,
117		/// 	types::optics::Getter,
118		/// };
119		///
120		/// let g: Getter<RcBrand, (i32, String), (i32, String), i32, i32> = Getter::new(|(x, _)| x);
121		/// assert_eq!(g.view((42, "hi".to_string())), 42);
122		/// ```
123		pub fn new(view: impl 'a + Fn(S) -> A) -> Self {
124			Getter {
125				view_fn: <FnBrand<PointerBrand> as LiftFn>::new(view),
126				_phantom: PhantomData,
127			}
128		}
129
130		/// View the focus of the getter in a structure.
131		#[document_signature]
132		///
133		#[document_parameters("The structure to view.")]
134		///
135		#[document_returns("The focus value.")]
136		///
137		#[document_examples]
138		///
139		/// ```
140		/// use fp_library::{
141		/// 	brands::RcBrand,
142		/// 	types::optics::Getter,
143		/// };
144		///
145		/// let g: Getter<RcBrand, (i32, String), (i32, String), i32, i32> = Getter::new(|(x, _)| x);
146		/// assert_eq!(g.view((42, "hi".to_string())), 42);
147		/// ```
148		pub fn view(
149			&self,
150			s: S,
151		) -> A {
152			(self.view_fn)(s)
153		}
154	}
155
156	#[document_type_parameters(
157		"The lifetime of the values.",
158		"The reference-counted pointer type for the getter.",
159		"The source type of the structure.",
160		"The target type of the structure.",
161		"The source type of the focus.",
162		"The target type of the focus.",
163		"The return type of the forget profunctor.",
164		"The reference-counted pointer type for the forget brand."
165	)]
166	#[document_parameters("The getter instance.")]
167	impl<'a, PointerBrand, S, T, A, B, R, Q> Optic<'a, ForgetBrand<Q, R>, S, T, A, B>
168		for Getter<'a, PointerBrand, S, T, A, B>
169	where
170		PointerBrand: UnsizedCoercible,
171		Q: UnsizedCoercible + 'static,
172		S: 'a,
173		T: 'a,
174		A: 'a,
175		B: 'a,
176		R: 'a + 'static,
177	{
178		#[document_signature]
179		#[document_parameters("The profunctor value to transform.")]
180		#[document_returns("The transformed profunctor value.")]
181		#[document_examples]
182		///
183		/// ```
184		/// use fp_library::{
185		/// 	brands::{
186		/// 		optics::*,
187		/// 		*,
188		/// 	},
189		/// 	classes::optics::*,
190		/// 	functions::*,
191		/// 	types::optics::*,
192		/// };
193		///
194		/// let g: Getter<RcBrand, (i32, String), (i32, String), i32, i32> = Getter::new(|(x, _)| x);
195		/// let f = Forget::<RcBrand, i32, i32, i32>::new(|x| x);
196		/// let folded = Optic::<ForgetBrand<RcBrand, i32>, _, _, _, _>::evaluate(&g, f);
197		/// assert_eq!(folded.run((42, "hi".to_string())), 42);
198		/// ```
199		fn evaluate(
200			&self,
201			pab: Apply!(<ForgetBrand<Q, R> as Kind!( type Of<'b, U: 'b, V: 'b>: 'b; )>::Of<'a, A, B>),
202		) -> Apply!(<ForgetBrand<Q, R> as Kind!( type Of<'b, U: 'b, V: 'b>: 'b; )>::Of<'a, S, T>)
203		{
204			let view_fn = self.view_fn.clone();
205			Forget::new(move |s: S| pab.run(view_fn(s)))
206		}
207	}
208
209	/// A concrete getter type where types do not change.
210	///
211	/// Matches PureScript's `Getter' s a`.
212	#[document_type_parameters(
213		"The lifetime of the values.",
214		"The reference-counted pointer type.",
215		"The type of the structure.",
216		"The type of the focus."
217	)]
218	pub struct GetterPrime<'a, PointerBrand, S, A>
219	where
220		PointerBrand: UnsizedCoercible,
221		S: 'a,
222		A: 'a, {
223		/// Function to view the focus of the getter in a structure.
224		pub view_fn: Apply!(<FnBrand<PointerBrand> as Kind!( type Of<'b, U: 'b, V: 'b>: 'b; )>::Of<'a, S, A>),
225		pub(crate) _phantom: PhantomData<PointerBrand>,
226	}
227
228	#[document_type_parameters(
229		"The lifetime of the values.",
230		"The reference-counted pointer type.",
231		"The type of the structure.",
232		"The type of the focus."
233	)]
234	#[document_parameters("The getter instance.")]
235	impl<'a, PointerBrand, S, A> Clone for GetterPrime<'a, PointerBrand, S, A>
236	where
237		PointerBrand: UnsizedCoercible,
238		S: 'a,
239		A: 'a,
240	{
241		#[document_signature]
242		#[document_returns("A new `GetterPrime` instance that is a copy of the original.")]
243		#[document_examples]
244		///
245		/// ```
246		/// use fp_library::{
247		/// 	brands::RcBrand,
248		/// 	types::optics::GetterPrime,
249		/// };
250		///
251		/// let g: GetterPrime<RcBrand, (i32, String), i32> = GetterPrime::new(|(x, _)| x);
252		/// let cloned = g.clone();
253		/// assert_eq!(cloned.view((42, "hi".to_string())), 42);
254		/// ```
255		fn clone(&self) -> Self {
256			GetterPrime {
257				view_fn: self.view_fn.clone(),
258				_phantom: PhantomData,
259			}
260		}
261	}
262
263	#[document_type_parameters(
264		"The lifetime of the values.",
265		"The reference-counted pointer type.",
266		"The type of the structure.",
267		"The type of the focus."
268	)]
269	#[document_parameters("The getter instance.")]
270	impl<'a, PointerBrand, S, A> GetterPrime<'a, PointerBrand, S, A>
271	where
272		PointerBrand: UnsizedCoercible,
273		S: 'a,
274		A: 'a,
275	{
276		/// Create a new monomorphic getter from a view function.
277		#[document_signature]
278		///
279		#[document_parameters("The view function.")]
280		///
281		#[document_returns("A new instance of the type.")]
282		///
283		#[document_examples]
284		///
285		/// ```
286		/// use fp_library::{
287		/// 	brands::RcBrand,
288		/// 	types::optics::GetterPrime,
289		/// };
290		///
291		/// let g: GetterPrime<RcBrand, (i32, String), i32> = GetterPrime::new(|(x, _)| x);
292		/// assert_eq!(g.view((42, "hi".to_string())), 42);
293		/// ```
294		pub fn new(view: impl 'a + Fn(S) -> A) -> Self {
295			GetterPrime {
296				view_fn: <FnBrand<PointerBrand> as LiftFn>::new(view),
297				_phantom: PhantomData,
298			}
299		}
300
301		/// View the focus of the getter in a structure.
302		#[document_signature]
303		///
304		#[document_parameters("The structure to view.")]
305		///
306		#[document_returns("The focus value.")]
307		///
308		#[document_examples]
309		///
310		/// ```
311		/// use fp_library::{
312		/// 	brands::RcBrand,
313		/// 	types::optics::GetterPrime,
314		/// };
315		///
316		/// let g: GetterPrime<RcBrand, (i32, String), i32> = GetterPrime::new(|(x, _)| x);
317		/// assert_eq!(g.view((42, "hi".to_string())), 42);
318		/// ```
319		pub fn view(
320			&self,
321			s: S,
322		) -> A {
323			(self.view_fn)(s)
324		}
325	}
326
327	#[document_type_parameters(
328		"The lifetime of the values.",
329		"The reference-counted pointer type for the getter.",
330		"The type of the structure.",
331		"The type of the focus.",
332		"The return type of the forget profunctor.",
333		"The reference-counted pointer type for the forget brand."
334	)]
335	#[document_parameters("The getter instance.")]
336	impl<'a, PointerBrand, S, A, R, Q> Optic<'a, ForgetBrand<Q, R>, S, S, A, A>
337		for GetterPrime<'a, PointerBrand, S, A>
338	where
339		PointerBrand: UnsizedCoercible,
340		Q: UnsizedCoercible + 'static,
341		S: 'a,
342		A: 'a,
343		R: 'a + 'static,
344	{
345		#[document_signature]
346		#[document_parameters("The profunctor value to transform.")]
347		#[document_returns("The transformed profunctor value.")]
348		#[document_examples]
349		///
350		/// ```
351		/// use fp_library::{
352		/// 	brands::{
353		/// 		optics::*,
354		/// 		*,
355		/// 	},
356		/// 	classes::optics::*,
357		/// 	functions::*,
358		/// 	types::optics::*,
359		/// };
360		///
361		/// let g: GetterPrime<RcBrand, (i32, String), i32> = GetterPrime::new(|(x, _)| x);
362		/// let f = Forget::<RcBrand, i32, i32, i32>::new(|x| x);
363		/// let folded = Optic::<ForgetBrand<RcBrand, i32>, _, _, _, _>::evaluate(&g, f);
364		/// assert_eq!(folded.run((42, "hi".to_string())), 42);
365		/// ```
366		fn evaluate(
367			&self,
368			pab: Apply!(<ForgetBrand<Q, R> as Kind!( type Of<'b, U: 'b, V: 'b>: 'b; )>::Of<'a, A, A>),
369		) -> Apply!(<ForgetBrand<Q, R> as Kind!( type Of<'b, U: 'b, V: 'b>: 'b; )>::Of<'a, S, S>)
370		{
371			let view_fn = self.view_fn.clone();
372			Forget::new(move |s: S| pab.run(view_fn(s)))
373		}
374	}
375
376	#[document_type_parameters(
377		"The lifetime of the values.",
378		"The reference-counted pointer type.",
379		"The type of the structure.",
380		"The type of the focus."
381	)]
382	#[document_parameters("The getter instance.")]
383	impl<'a, PointerBrand, S: 'a, A: 'a> GetterOptic<'a, S, A> for GetterPrime<'a, PointerBrand, S, A>
384	where
385		PointerBrand: UnsizedCoercible,
386	{
387		#[document_signature]
388		#[document_type_parameters(
389			"The return type of the forget profunctor.",
390			"The reference-counted pointer type."
391		)]
392		#[document_parameters("The profunctor value to transform.")]
393		#[document_returns("The transformed profunctor value.")]
394		#[document_examples]
395		///
396		/// ```
397		/// use fp_library::{
398		/// 	brands::{
399		/// 		optics::*,
400		/// 		*,
401		/// 	},
402		/// 	classes::optics::*,
403		/// 	functions::*,
404		/// 	types::optics::*,
405		/// };
406		///
407		/// let g: GetterPrime<RcBrand, (i32, String), i32> = GetterPrime::new(|(x, _)| x);
408		/// let f = Forget::<RcBrand, i32, i32, i32>::new(|x| x);
409		/// let folded = GetterOptic::evaluate(&g, f);
410		/// assert_eq!(folded.run((42, "hi".to_string())), 42);
411		/// ```
412		fn evaluate<R: 'a + 'static, Q: UnsizedCoercible + 'static>(
413			&self,
414			pab: Apply!(<ForgetBrand<Q, R> as Kind!( type Of<'b, U: 'b, V: 'b>: 'b; )>::Of<'a, A, A>),
415		) -> Apply!(<ForgetBrand<Q, R> as Kind!( type Of<'b, U: 'b, V: 'b>: 'b; )>::Of<'a, S, S>)
416		{
417			Optic::<ForgetBrand<Q, R>, S, S, A, A>::evaluate(self, pab)
418		}
419	}
420
421	#[document_type_parameters(
422		"The lifetime of the values.",
423		"The reference-counted pointer type.",
424		"The type of the structure.",
425		"The type of the focus."
426	)]
427	#[document_parameters("The getter instance.")]
428	impl<'a, PointerBrand, S: 'a, A: 'a> FoldOptic<'a, S, A> for GetterPrime<'a, PointerBrand, S, A>
429	where
430		PointerBrand: UnsizedCoercible,
431	{
432		#[document_signature]
433		#[document_type_parameters(
434			"The monoid type.",
435			"The reference-counted pointer type for the Forget brand."
436		)]
437		#[document_parameters("The profunctor value to transform.")]
438		#[document_returns("The transformed profunctor value.")]
439		#[document_examples]
440		///
441		/// ```
442		/// use fp_library::{
443		/// 	brands::{
444		/// 		optics::*,
445		/// 		*,
446		/// 	},
447		/// 	classes::optics::*,
448		/// 	functions::*,
449		/// 	types::optics::*,
450		/// };
451		///
452		/// let g: GetterPrime<RcBrand, (i32, String), i32> = GetterPrime::new(|(x, _)| x);
453		/// let f = Forget::<RcBrand, String, i32, i32>::new(|x: i32| x.to_string());
454		/// let folded: Forget<RcBrand, String, (i32, String), (i32, String)> = FoldOptic::evaluate(&g, f);
455		/// assert_eq!(folded.run((42, "hi".to_string())), "42".to_string());
456		/// ```
457		fn evaluate<R: 'a + Monoid + 'static, Q: UnsizedCoercible + 'static>(
458			&self,
459			pab: Apply!(<ForgetBrand<Q, R> as Kind!( type Of<'b, T: 'b, U: 'b>: 'b; )>::Of<'a, A, A>),
460		) -> Apply!(<ForgetBrand<Q, R> as Kind!( type Of<'b, T: 'b, U: 'b>: 'b; )>::Of<'a, S, S>)
461		{
462			Optic::<ForgetBrand<Q, R>, S, S, A, A>::evaluate(self, pab)
463		}
464	}
465}
466pub use inner::*;