1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
pub trait Getter<S, A> {
fn view(&self, s: &S) -> A;
}
pub trait Lens<S, A>: Getter<S, A> {
fn set(&self, s: &S, a: &A) -> S;
}
pub fn lens<'a, S, A>(getter: &'a Fn(&S) -> A, setter: &'a Fn(&S, &A) -> S) -> LensImpl<'a, S, A> {
LensImpl {
view: getter,
set: setter,
}
}
pub fn compose<'a, S, A, B>(lhs: &'a Lens<S, A>, rhs: &'a Lens<A, B>) -> CompoundLensImpl<'a, S, A, B> {
CompoundLensImpl {
lhs: lhs,
rhs: rhs,
}
}
#[macro_export]
macro_rules! struct_lens {
(clone $thetype:ident, $expr:ident) => {
lenses::lens::lens(&|obj: &$thetype| obj.$expr.clone(), &|obj, newval| {
$thetype {
$expr: newval.clone(),
.. obj.clone()
}
})
};
(copy $thetype:ident, $expr:ident) => {
lenses::lens::lens(&|obj: &$thetype| obj.$expr, &|obj, newval| {
$thetype {
$expr: *newval,
.. *obj
}
})
};
}
#[macro_export]
macro_rules! gen_lens {
(clone $thetype:ident, $($expr:ident).*) => {
lenses::lens::lens(&|obj: &$thetype| obj.$($expr).*.clone(), &|obj, newval| {
let mut new = obj.clone();
new.$($expr).* = newval.clone();
new
})
};
(copy $thetype:ident, $($expr:ident).*) => {
lenses::lens::lens(&|obj: &$thetype| obj.$($expr).*, &|obj, newval| {
let mut new = *obj;
new.$($expr).* = *newval;
new
})
};
}
pub struct LensImpl<'a, S, A> {
view: &'a Fn(&S) -> A,
set: &'a Fn (&S, &A) -> S,
}
pub struct CompoundLensImpl<'a, S, A, B> {
lhs: &'a Lens<S, A>,
rhs: &'a Lens<A, B>,
}
impl <'a, S, A> Getter<S, A> for LensImpl<'a, S, A> {
fn view(&self, s: &S) -> A { (self.view)(s) }
}
impl <'a, S, A> Lens<S, A> for LensImpl<'a, S, A> {
fn set(&self, s: &S, a: &A) -> S { (self.set)(s, a) }
}
impl <'a, S, A, B> Getter<S, B> for CompoundLensImpl<'a, S, A, B> {
fn view(&self, s: &S) -> B { self.rhs.view(&self.lhs.view(s)) }
}
impl <'a, S, A, B> Lens<S, B> for CompoundLensImpl<'a, S, A, B> {
fn set(&self, s: &S, b: &B) -> S { self.lhs.set(s, &self.rhs.set(&self.lhs.view(s), b)) }
}