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