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