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