1pub trait Lens<S, A> {
68 fn view(&self, whole: &S) -> A;
70
71 fn set(&self, whole: &mut S, part: A);
73
74 fn over(&self, whole: &mut S, f: impl FnOnce(A) -> A)
76 where
77 A: Clone,
78 {
79 let current = self.view(whole);
80 self.set(whole, f(current));
81 }
82
83 fn then<B, L2: Lens<A, B>>(self, inner: L2) -> Composed<Self, L2, A>
85 where
86 Self: Sized,
87 A: Clone,
88 {
89 Composed {
90 outer: self,
91 inner,
92 _mid: std::marker::PhantomData,
93 }
94 }
95}
96
97pub struct FieldLens<G, P> {
99 getter: G,
100 putter: P,
101}
102
103impl<S, A, G, P> Lens<S, A> for FieldLens<G, P>
104where
105 G: Fn(&S) -> A,
106 P: Fn(&mut S, A),
107{
108 fn view(&self, whole: &S) -> A {
109 (self.getter)(whole)
110 }
111
112 fn set(&self, whole: &mut S, part: A) {
113 (self.putter)(whole, part);
114 }
115}
116
117pub fn field_lens<S, A>(
134 getter: impl Fn(&S) -> A + 'static,
135 setter: impl Fn(&mut S, A) + 'static,
136) -> FieldLens<impl Fn(&S) -> A, impl Fn(&mut S, A)> {
137 FieldLens {
138 getter,
139 putter: setter,
140 }
141}
142
143pub struct Composed<L1, L2, B> {
148 outer: L1,
149 inner: L2,
150 _mid: std::marker::PhantomData<B>,
151}
152
153impl<S, B, A, L1, L2> Lens<S, A> for Composed<L1, L2, B>
154where
155 L1: Lens<S, B>,
156 L2: Lens<B, A>,
157 B: Clone,
158{
159 fn view(&self, whole: &S) -> A {
160 let mid = self.outer.view(whole);
161 self.inner.view(&mid)
162 }
163
164 fn set(&self, whole: &mut S, part: A) {
165 let mut mid = self.outer.view(whole);
166 self.inner.set(&mut mid, part);
167 self.outer.set(whole, mid);
168 }
169}
170
171pub fn compose<S, B, A, L1, L2>(outer: L1, inner: L2) -> Composed<L1, L2, B>
175where
176 L1: Lens<S, B>,
177 L2: Lens<B, A>,
178 B: Clone,
179{
180 Composed {
181 outer,
182 inner,
183 _mid: std::marker::PhantomData,
184 }
185}
186
187pub struct Identity;
189
190impl<S: Clone> Lens<S, S> for Identity {
191 fn view(&self, whole: &S) -> S {
192 whole.clone()
193 }
194
195 fn set(&self, whole: &mut S, part: S) {
196 *whole = part;
197 }
198}
199
200pub struct Fst;
202
203impl<A: Clone, B: Clone> Lens<(A, B), A> for Fst {
204 fn view(&self, whole: &(A, B)) -> A {
205 whole.0.clone()
206 }
207
208 fn set(&self, whole: &mut (A, B), part: A) {
209 whole.0 = part;
210 }
211}
212
213pub struct Snd;
215
216impl<A: Clone, B: Clone> Lens<(A, B), B> for Snd {
217 fn view(&self, whole: &(A, B)) -> B {
218 whole.1.clone()
219 }
220
221 fn set(&self, whole: &mut (A, B), part: B) {
222 whole.1 = part;
223 }
224}
225
226pub struct AtIndex {
232 index: usize,
233}
234
235impl AtIndex {
236 pub fn new(index: usize) -> Self {
237 Self { index }
238 }
239}
240
241impl<T: Clone> Lens<Vec<T>, T> for AtIndex {
242 fn view(&self, whole: &Vec<T>) -> T {
243 whole[self.index].clone()
244 }
245
246 fn set(&self, whole: &mut Vec<T>, part: T) {
247 whole[self.index] = part;
248 }
249}
250
251pub fn at_index(index: usize) -> AtIndex {
253 AtIndex::new(index)
254}
255
256pub trait Prism<S, A> {
261 fn preview(&self, whole: &S) -> Option<A>;
263
264 fn set_if(&self, whole: &mut S, part: A) -> bool;
266}
267
268pub struct SomePrism;
270
271impl<T: Clone> Prism<Option<T>, T> for SomePrism {
272 fn preview(&self, whole: &Option<T>) -> Option<T> {
273 whole.clone()
274 }
275
276 fn set_if(&self, whole: &mut Option<T>, part: T) -> bool {
277 if whole.is_some() {
278 *whole = Some(part);
279 true
280 } else {
281 false
282 }
283 }
284}
285
286#[cfg(test)]
287mod tests {
288 use super::*;
289
290 #[derive(Clone, Debug, PartialEq)]
291 struct Point {
292 x: f64,
293 y: f64,
294 }
295
296 #[derive(Clone, Debug, PartialEq)]
297 struct Line {
298 start: Point,
299 end: Point,
300 }
301
302 fn x_lens() -> FieldLens<impl Fn(&Point) -> f64, impl Fn(&mut Point, f64)> {
303 field_lens(|p: &Point| p.x, |p: &mut Point, v| p.x = v)
304 }
305
306 fn y_lens() -> FieldLens<impl Fn(&Point) -> f64, impl Fn(&mut Point, f64)> {
307 field_lens(|p: &Point| p.y, |p: &mut Point, v| p.y = v)
308 }
309
310 fn start_lens() -> FieldLens<impl Fn(&Line) -> Point, impl Fn(&mut Line, Point)> {
311 field_lens(|l: &Line| l.start.clone(), |l: &mut Line, p| l.start = p)
312 }
313
314 fn end_lens() -> FieldLens<impl Fn(&Line) -> Point, impl Fn(&mut Line, Point)> {
315 field_lens(|l: &Line| l.end.clone(), |l: &mut Line, p| l.end = p)
316 }
317
318 #[test]
321 fn view_reads_field() {
322 let lens = x_lens();
323 let p = Point { x: 3.0, y: 4.0 };
324 assert_eq!(lens.view(&p), 3.0);
325 }
326
327 #[test]
328 fn set_writes_field() {
329 let lens = x_lens();
330 let mut p = Point { x: 3.0, y: 4.0 };
331 lens.set(&mut p, 5.0);
332 assert_eq!(p.x, 5.0);
333 assert_eq!(p.y, 4.0); }
335
336 #[test]
337 fn over_modifies_with_function() {
338 let lens = x_lens();
339 let mut p = Point { x: 3.0, y: 4.0 };
340 lens.over(&mut p, |x| x * 2.0);
341 assert_eq!(p.x, 6.0);
342 }
343
344 #[test]
347 fn law_get_put() {
348 let lens = x_lens();
350 let mut p = Point { x: 3.0, y: 4.0 };
351 let original = p.clone();
352 let viewed = lens.view(&p);
353 lens.set(&mut p, viewed);
354 assert_eq!(p, original);
355 }
356
357 #[test]
358 fn law_put_get() {
359 let lens = x_lens();
361 let mut p = Point { x: 3.0, y: 4.0 };
362 lens.set(&mut p, 99.0);
363 assert_eq!(lens.view(&p), 99.0);
364 }
365
366 #[test]
367 fn law_put_put() {
368 let lens = x_lens();
370 let mut p1 = Point { x: 3.0, y: 4.0 };
371 let mut p2 = p1.clone();
372
373 lens.set(&mut p1, 10.0);
374 lens.set(&mut p1, 20.0);
375
376 lens.set(&mut p2, 20.0);
377
378 assert_eq!(p1, p2);
379 }
380
381 #[test]
384 fn compose_view() {
385 let start_x = compose(start_lens(), x_lens());
386 let line = Line {
387 start: Point { x: 1.0, y: 2.0 },
388 end: Point { x: 3.0, y: 4.0 },
389 };
390 assert_eq!(start_x.view(&line), 1.0);
391 }
392
393 #[test]
394 fn compose_set() {
395 let start_x = compose(start_lens(), x_lens());
396 let mut line = Line {
397 start: Point { x: 1.0, y: 2.0 },
398 end: Point { x: 3.0, y: 4.0 },
399 };
400 start_x.set(&mut line, 99.0);
401 assert_eq!(line.start.x, 99.0);
402 assert_eq!(line.start.y, 2.0); assert_eq!(line.end.x, 3.0); }
405
406 #[test]
407 fn compose_laws_hold() {
408 let start_x = compose(start_lens(), x_lens());
409 let mut line = Line {
410 start: Point { x: 1.0, y: 2.0 },
411 end: Point { x: 3.0, y: 4.0 },
412 };
413
414 let original = line.clone();
416 let v = start_x.view(&line);
417 start_x.set(&mut line, v);
418 assert_eq!(line, original);
419
420 start_x.set(&mut line, 42.0);
422 assert_eq!(start_x.view(&line), 42.0);
423 }
424
425 #[test]
426 fn compose_end_y() {
427 let end_y = compose(end_lens(), y_lens());
428 let mut line = Line {
429 start: Point { x: 1.0, y: 2.0 },
430 end: Point { x: 3.0, y: 4.0 },
431 };
432 assert_eq!(end_y.view(&line), 4.0);
433 end_y.set(&mut line, 100.0);
434 assert_eq!(line.end.y, 100.0);
435 }
436
437 #[test]
440 fn identity_view() {
441 let p = Point { x: 1.0, y: 2.0 };
442 assert_eq!(Identity.view(&p), p);
443 }
444
445 #[test]
446 fn identity_set() {
447 let mut p = Point { x: 1.0, y: 2.0 };
448 let new = Point { x: 5.0, y: 6.0 };
449 Identity.set(&mut p, new.clone());
450 assert_eq!(p, new);
451 }
452
453 #[test]
456 fn fst_lens() {
457 let mut pair = (10u32, "hello");
458 assert_eq!(Fst.view(&pair), 10);
459 Fst.set(&mut pair, 20);
460 assert_eq!(pair, (20, "hello"));
461 }
462
463 #[test]
464 fn snd_lens() {
465 let mut pair = (10u32, 20u32);
466 assert_eq!(Snd.view(&pair), 20);
467 Snd.set(&mut pair, 30);
468 assert_eq!(pair, (10, 30));
469 }
470
471 #[test]
474 fn at_index_view() {
475 let v = vec![10, 20, 30];
476 assert_eq!(at_index(1).view(&v), 20);
477 }
478
479 #[test]
480 fn at_index_set() {
481 let mut v = vec![10, 20, 30];
482 at_index(1).set(&mut v, 99);
483 assert_eq!(v, vec![10, 99, 30]);
484 }
485
486 #[test]
487 #[should_panic]
488 fn at_index_out_of_bounds() {
489 let v = vec![1, 2, 3];
490 at_index(5).view(&v);
491 }
492
493 #[test]
496 fn some_prism_preview() {
497 let opt = Some(42);
498 assert_eq!(SomePrism.preview(&opt), Some(42));
499
500 let none: Option<i32> = None;
501 assert_eq!(SomePrism.preview(&none), None);
502 }
503
504 #[test]
505 fn some_prism_set_if_some() {
506 let mut opt = Some(42);
507 assert!(SomePrism.set_if(&mut opt, 99));
508 assert_eq!(opt, Some(99));
509 }
510
511 #[test]
512 fn some_prism_set_if_none() {
513 let mut opt: Option<i32> = None;
514 assert!(!SomePrism.set_if(&mut opt, 99));
515 assert_eq!(opt, None);
516 }
517
518 #[test]
521 fn composed_over() {
522 let start_x = compose(start_lens(), x_lens());
523 let mut line = Line {
524 start: Point { x: 10.0, y: 20.0 },
525 end: Point { x: 30.0, y: 40.0 },
526 };
527 start_x.over(&mut line, |x| x + 5.0);
528 assert_eq!(line.start.x, 15.0);
529 }
530
531 #[test]
534 fn then_composition() {
535 let start_x = start_lens().then(x_lens());
536 let line = Line {
537 start: Point { x: 7.0, y: 8.0 },
538 end: Point { x: 9.0, y: 10.0 },
539 };
540 assert_eq!(start_x.view(&line), 7.0);
541 }
542}