Skip to main content

fp_library/types/optics/
setter.rs

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