1use crate::optic::Optic;
2
3pub struct Getter<S, A> {
7 get: fn(&S) -> A,
8}
9
10impl<S, A> Optic for Getter<S, A> {}
11
12impl<S, A> Getter<S, A> {
13 pub fn new(get: fn(&S) -> A) -> Self {
14 Self { get }
15 }
16
17 pub fn get(&self, s: &S) -> A {
18 (self.get)(s)
19 }
20
21 pub fn then<B>(self, inner: Getter<A, B>) -> ComposedGetter<S, B>
23 where
24 S: 'static,
25 A: 'static,
26 B: 'static,
27 {
28 let outer_get = self.get;
29 let inner_get = inner.get;
30 ComposedGetter {
31 get: Box::new(move |s| inner_get(&outer_get(s))),
32 }
33 }
34}
35
36pub struct ComposedGetter<S, A> {
38 get: Box<dyn Fn(&S) -> A>,
39}
40
41impl<S, A> Optic for ComposedGetter<S, A> {}
42
43impl<S, A> ComposedGetter<S, A> {
44 pub fn get(&self, s: &S) -> A {
45 (self.get)(s)
46 }
47}
48
49#[cfg(test)]
50mod tests {
51 use super::*;
52
53 #[derive(Clone)]
54 struct Point {
55 x: f64,
56 y: f64,
57 }
58
59 #[test]
60 fn getter_get() {
61 let getter = Getter::new(|p: &Point| p.x);
62 let p = Point { x: 1.0, y: 2.0 };
63 assert!((getter.get(&p) - 1.0).abs() < f64::EPSILON);
64 }
65
66 #[test]
67 fn getter_composition() {
68 #[derive(Clone)]
69 struct Line {
70 start: Point,
71 }
72 let line_start = Getter::new(|l: &Line| l.start.clone());
73 let point_x = Getter::new(|p: &Point| p.x);
74 let composed = line_start.then(point_x);
75 let line = Line {
76 start: Point { x: 3.0, y: 4.0 },
77 };
78 assert!((composed.get(&line) - 3.0).abs() < f64::EPSILON);
79 }
80
81 #[test]
82 fn getter_from_lens() {
83 use crate::lens::Lens;
84 let lens = Lens::new(|p: &Point| p.x, |p: Point, x| Point { x, ..p });
85 let getter = lens.to_getter();
86 let p = Point { x: 5.0, y: 6.0 };
87 assert!((getter.get(&p) - 5.0).abs() < f64::EPSILON);
88 }
89
90 #[test]
91 fn getter_from_iso() {
92 use crate::iso::Iso;
93 let iso = Iso::new(|n: &i32| *n as f64, |f: f64| f as i32);
94 let getter = iso.to_getter();
95 assert!((getter.get(&42) - 42.0).abs() < f64::EPSILON);
96 }
97}