Skip to main content

fp_library/types/optics/
review.rs

1//! Review optics for constructing values.
2//!
3//! A review represents a way to construct a structure from a focus value.
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				optics::*,
18			},
19			kinds::*,
20			types::optics::Tagged,
21		},
22		fp_macros::*,
23		std::marker::PhantomData,
24	};
25
26	/// A polymorphic review.
27	///
28	/// Matches PureScript's `Review 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 Review<'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 construct a structure from a focus value.
45		pub review_fn: Apply!(<FnBrand<PointerBrand> as Kind!( type Of<'b, U: 'b, V: 'b>: 'b; )>::Of<'a, B, T>),
46		pub(crate) _phantom: PhantomData<&'a (S, A)>,
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 review instance.")]
58	impl<'a, PointerBrand, S, T, A, B> Clone for Review<'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 `Review` instance that is a copy of the original.")]
68		#[document_examples]
69		///
70		/// ```
71		/// use fp_library::{
72		/// 	brands::RcBrand,
73		/// 	types::optics::Review,
74		/// };
75		///
76		/// let r: Review<RcBrand, Option<i32>, Option<i32>, i32, i32> = Review::new(Some);
77		/// let cloned = r.clone();
78		/// assert_eq!(cloned.review(42), Some(42));
79		/// ```
80		fn clone(&self) -> Self {
81			Review {
82				review_fn: self.review_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 review instance.")]
97	impl<'a, PointerBrand, S, T, A, B> Review<'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 polymorphic review from a review function.
106		#[document_signature]
107		///
108		#[document_parameters("The review 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::Review,
118		/// };
119		///
120		/// let r: Review<RcBrand, Option<i32>, Option<i32>, i32, i32> = Review::new(Some);
121		/// assert_eq!(r.review(42), Some(42));
122		/// ```
123		pub fn new(review: impl 'a + Fn(B) -> T) -> Self {
124			Review {
125				review_fn: <FnBrand<PointerBrand> as CloneableFn>::new(review),
126				_phantom: PhantomData,
127			}
128		}
129
130		/// Review a focus value into a structure.
131		#[document_signature]
132		///
133		#[document_parameters("The focus value to review.")]
134		///
135		#[document_returns("The structure containing the focus value.")]
136		///
137		#[document_examples]
138		///
139		/// ```
140		/// use fp_library::{
141		/// 	brands::RcBrand,
142		/// 	types::optics::Review,
143		/// };
144		///
145		/// let r: Review<RcBrand, Option<i32>, Option<i32>, i32, i32> = Review::new(Some);
146		/// assert_eq!(r.review(42), Some(42));
147		/// ```
148		pub fn review(
149			&self,
150			b: B,
151		) -> T {
152			(self.review_fn)(b)
153		}
154	}
155
156	#[document_type_parameters(
157		"The lifetime of the values.",
158		"The reference-counted pointer type.",
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	)]
164	#[document_parameters("The review instance.")]
165	impl<'a, PointerBrand, S, T, A, B> Optic<'a, TaggedBrand, S, T, A, B>
166		for Review<'a, PointerBrand, S, T, A, B>
167	where
168		PointerBrand: UnsizedCoercible,
169		S: 'a,
170		T: 'a,
171		A: 'a,
172		B: 'a,
173	{
174		#[document_signature]
175		#[document_parameters("The profunctor value to transform.")]
176		#[document_returns("The transformed profunctor value.")]
177		#[document_examples]
178		///
179		/// ```
180		/// use fp_library::{
181		/// 	brands::{
182		/// 		optics::*,
183		/// 		*,
184		/// 	},
185		/// 	classes::optics::*,
186		/// 	functions::*,
187		/// 	types::optics::*,
188		/// };
189		///
190		/// let r: Review<RcBrand, Option<i32>, Option<i32>, i32, i32> = Review::new(Some);
191		/// let f = Tagged::new(42);
192		/// let reviewed = Optic::<TaggedBrand, _, _, _, _>::evaluate(&r, f);
193		/// assert_eq!(reviewed.0, Some(42));
194		/// ```
195		fn evaluate(
196			&self,
197			pab: Apply!(<TaggedBrand as Kind!( type Of<'b, X: 'b, Y: 'b>: 'b; )>::Of<'a, A, B>),
198		) -> Apply!(<TaggedBrand as Kind!( type Of<'b, X: 'b, Y: 'b>: 'b; )>::Of<'a, S, T>) {
199			let review = self.review_fn.clone();
200			Tagged::new(review(pab.0))
201		}
202	}
203
204	#[document_type_parameters(
205		"The lifetime of the values.",
206		"The reference-counted pointer type.",
207		"The source type of the structure.",
208		"The target type of the structure.",
209		"The source type of the focus.",
210		"The target type of the focus."
211	)]
212	#[document_parameters("The review instance.")]
213	impl<'a, PointerBrand, S, T, A, B> ReviewOptic<'a, S, T, A, B>
214		for Review<'a, PointerBrand, S, T, A, B>
215	where
216		PointerBrand: UnsizedCoercible,
217		S: 'a,
218		T: 'a,
219		A: 'a,
220		B: 'a,
221	{
222		#[document_signature]
223		#[document_parameters("The profunctor value to transform.")]
224		#[document_returns("The transformed profunctor value.")]
225		#[document_examples]
226		///
227		/// ```
228		/// use fp_library::{
229		/// 	brands::{
230		/// 		optics::*,
231		/// 		*,
232		/// 	},
233		/// 	classes::optics::*,
234		/// 	functions::*,
235		/// 	types::optics::*,
236		/// };
237		///
238		/// let r: Review<RcBrand, Option<i32>, Option<i32>, i32, i32> = Review::new(Some);
239		/// let f = Tagged::new(42);
240		/// let reviewed = ReviewOptic::evaluate(&r, f);
241		/// assert_eq!(reviewed.0, Some(42));
242		/// ```
243		fn evaluate(
244			&self,
245			pab: Apply!(<TaggedBrand as Kind!( type Of<'b, X: 'b, Y: 'b>: 'b; )>::Of<'a, A, B>),
246		) -> Apply!(<TaggedBrand as Kind!( type Of<'b, X: 'b, Y: 'b>: 'b; )>::Of<'a, S, T>) {
247			Optic::<TaggedBrand, S, T, A, B>::evaluate(self, pab)
248		}
249	}
250
251	/// A concrete review type where types do not change.
252	///
253	/// Matches PureScript's `Review' s a`.
254	#[document_type_parameters(
255		"The lifetime of the values.",
256		"The reference-counted pointer type.",
257		"The type of the structure.",
258		"The type of the focus."
259	)]
260	pub struct ReviewPrime<'a, PointerBrand, S, A>
261	where
262		PointerBrand: UnsizedCoercible,
263		S: 'a,
264		A: 'a, {
265		/// Function to construct a structure from a focus value.
266		pub review_fn: Apply!(<FnBrand<PointerBrand> as Kind!( type Of<'b, U: 'b, V: 'b>: 'b; )>::Of<'a, A, S>),
267		pub(crate) _phantom: PhantomData<PointerBrand>,
268	}
269
270	#[document_type_parameters(
271		"The lifetime of the values.",
272		"The reference-counted pointer type.",
273		"The type of the structure.",
274		"The type of the focus."
275	)]
276	#[document_parameters("The review instance.")]
277	impl<'a, PointerBrand, S, A> Clone for ReviewPrime<'a, PointerBrand, S, A>
278	where
279		PointerBrand: UnsizedCoercible,
280		S: 'a,
281		A: 'a,
282	{
283		#[document_signature]
284		#[document_returns("A new `ReviewPrime` instance that is a copy of the original.")]
285		#[document_examples]
286		///
287		/// ```
288		/// use fp_library::{
289		/// 	brands::RcBrand,
290		/// 	types::optics::ReviewPrime,
291		/// };
292		///
293		/// let r: ReviewPrime<RcBrand, Option<i32>, i32> = ReviewPrime::new(Some);
294		/// let cloned = r.clone();
295		/// assert_eq!(cloned.review(42), Some(42));
296		/// ```
297		fn clone(&self) -> Self {
298			ReviewPrime {
299				review_fn: self.review_fn.clone(),
300				_phantom: PhantomData,
301			}
302		}
303	}
304
305	#[document_type_parameters(
306		"The lifetime of the values.",
307		"The reference-counted pointer type.",
308		"The type of the structure.",
309		"The type of the focus."
310	)]
311	#[document_parameters("The review instance.")]
312	impl<'a, PointerBrand, S, A> ReviewPrime<'a, PointerBrand, S, A>
313	where
314		PointerBrand: UnsizedCoercible,
315		S: 'a,
316		A: 'a,
317	{
318		/// Create a new monomorphic review.
319		#[document_signature]
320		///
321		#[document_parameters("The review function.")]
322		///
323		#[document_returns("A new instance of the type.")]
324		///
325		#[document_examples]
326		///
327		/// ```
328		/// use fp_library::{
329		/// 	brands::RcBrand,
330		/// 	types::optics::ReviewPrime,
331		/// };
332		///
333		/// let r: ReviewPrime<RcBrand, Option<i32>, i32> = ReviewPrime::new(Some);
334		/// assert_eq!(r.review(42), Some(42));
335		/// ```
336		pub fn new(review: impl 'a + Fn(A) -> S) -> Self {
337			ReviewPrime {
338				review_fn: <FnBrand<PointerBrand> as CloneableFn>::new(review),
339				_phantom: PhantomData,
340			}
341		}
342
343		/// Review a focus value into a structure.
344		#[document_signature]
345		///
346		#[document_parameters("The focus value to review.")]
347		///
348		#[document_returns("The structure containing the focus value.")]
349		///
350		#[document_examples]
351		///
352		/// ```
353		/// use fp_library::{
354		/// 	brands::RcBrand,
355		/// 	types::optics::ReviewPrime,
356		/// };
357		///
358		/// let r: ReviewPrime<RcBrand, Option<i32>, i32> = ReviewPrime::new(Some);
359		/// assert_eq!(r.review(42), Some(42));
360		/// ```
361		pub fn review(
362			&self,
363			a: A,
364		) -> S {
365			(self.review_fn)(a)
366		}
367	}
368
369	#[document_type_parameters(
370		"The lifetime of the values.",
371		"The reference-counted pointer type.",
372		"The type of the structure.",
373		"The type of the focus."
374	)]
375	#[document_parameters("The review instance.")]
376	impl<'a, PointerBrand, S, A> Optic<'a, TaggedBrand, S, S, A, A>
377		for ReviewPrime<'a, PointerBrand, S, A>
378	where
379		PointerBrand: UnsizedCoercible,
380		S: 'a,
381		A: 'a,
382	{
383		#[document_signature]
384		#[document_parameters("The profunctor value to transform.")]
385		#[document_returns("The transformed profunctor value.")]
386		#[document_examples]
387		///
388		/// ```
389		/// use fp_library::{
390		/// 	brands::{
391		/// 		optics::*,
392		/// 		*,
393		/// 	},
394		/// 	classes::optics::*,
395		/// 	functions::*,
396		/// 	types::optics::*,
397		/// };
398		///
399		/// let r: ReviewPrime<RcBrand, Option<i32>, i32> = ReviewPrime::new(Some);
400		/// let f = Tagged::new(42);
401		/// let reviewed = Optic::<TaggedBrand, _, _, _, _>::evaluate(&r, f);
402		/// assert_eq!(reviewed.0, Some(42));
403		/// ```
404		fn evaluate(
405			&self,
406			pab: Apply!(<TaggedBrand as Kind!( type Of<'b, X: 'b, Y: 'b>: 'b; )>::Of<'a, A, A>),
407		) -> Apply!(<TaggedBrand as Kind!( type Of<'b, X: 'b, Y: 'b>: 'b; )>::Of<'a, S, S>) {
408			let review = self.review_fn.clone();
409			Tagged::new(review(pab.0))
410		}
411	}
412
413	#[document_type_parameters(
414		"The lifetime of the values.",
415		"The reference-counted pointer type.",
416		"The type of the structure.",
417		"The type of the focus."
418	)]
419	#[document_parameters("The review instance.")]
420	impl<'a, PointerBrand, S, A> ReviewOptic<'a, S, S, A, A> for ReviewPrime<'a, PointerBrand, S, A>
421	where
422		PointerBrand: UnsizedCoercible,
423		S: 'a,
424		A: 'a,
425	{
426		#[document_signature]
427		#[document_parameters("The profunctor value to transform.")]
428		#[document_returns("The transformed profunctor value.")]
429		#[document_examples]
430		///
431		/// ```
432		/// use fp_library::{
433		/// 	brands::{
434		/// 		optics::*,
435		/// 		*,
436		/// 	},
437		/// 	classes::optics::*,
438		/// 	functions::*,
439		/// 	types::optics::*,
440		/// };
441		///
442		/// let r: ReviewPrime<RcBrand, Option<i32>, i32> = ReviewPrime::new(Some);
443		/// let f = Tagged::new(42);
444		/// let reviewed = ReviewOptic::evaluate(&r, f);
445		/// assert_eq!(reviewed.0, Some(42));
446		/// ```
447		fn evaluate(
448			&self,
449			pab: Apply!(<TaggedBrand as Kind!( type Of<'b, X: 'b, Y: 'b>: 'b; )>::Of<'a, A, A>),
450		) -> Apply!(<TaggedBrand as Kind!( type Of<'b, X: 'b, Y: 'b>: 'b; )>::Of<'a, S, S>) {
451			Optic::<TaggedBrand, S, S, A, A>::evaluate(self, pab)
452		}
453	}
454}
455pub use inner::*;