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