rust_overture/
keypath.rs

1use std::{cell::RefCell, rc::Rc};
2
3// Immutable getter
4pub fn get<Root, Value>(getter: impl Fn(&Root) -> Value + Clone + 'static) -> impl Fn(Root) -> Value
5where
6    Value: Clone + 'static,
7{
8    move |root: Root| getter(&root)
9}
10
11// Immutable setter
12pub fn set<Root, Value>(
13    setter: impl Fn(&mut Root, Value) + Clone + 'static,
14    getter: impl Fn(&Root) -> Value + Clone + 'static,
15    value: Value,
16) -> impl Fn(Root) -> Root
17where
18    Root: Clone + 'static,
19    Value: Clone + 'static,
20{
21    move |root: Root| {
22        let mut copy = root.clone();
23        setter(&mut copy, value.clone());
24        copy
25    }
26}
27
28// Mutable setter using interior mutability (Rc<RefCell>)
29pub fn mut_<Root, Value>(
30    setter: impl Fn(&mut Root, Value) + Clone + 'static,
31    getter: impl Fn(&mut Root) -> &mut Value + Clone + 'static,
32    value: Value,
33) -> impl FnMut(&mut Root)
34where
35    Root: 'static,
36    Value: Clone + 'static,
37{
38    move |root: &mut Root| {
39        setter(root, value.clone());
40    }
41}
42
43// /// Immutable get
44// pub fn get<Root, Value>(
45//     getter: impl Fn(&Root) -> Value + Clone + 'static,
46// ) -> impl Fn(Root) -> Value
47// where
48//     Value: Clone + 'static,
49// {
50//     move |root: Root| getter(&root)
51// }
52
53/// Immutable prop
54pub fn prop<Root, Value>(
55    setter: impl Fn(&mut Root, Value) + Clone + 'static,
56    getter: impl Fn(&Root) -> Value + Clone + 'static,
57) -> impl Fn(Box<dyn Fn(Value) -> Value>) -> Box<dyn Fn(Root) -> Root>
58where
59    Root: Clone + 'static,
60    Value: Clone + 'static,
61{
62    let setter = Rc::new(setter);
63    let getter = Rc::new(getter);
64    move |update: Box<dyn Fn(Value) -> Value>| {
65        let setter = setter.clone();
66        let getter = getter.clone();
67        Box::new(move |root: Root| {
68            let mut copy = root.clone();
69            let value = getter(&copy);
70            let new_value = update(value);
71            setter(&mut copy, new_value);
72            copy
73        })
74    }
75}
76
77/// Immutable over
78pub fn over<Root, Value>(
79    setter: impl Fn(&mut Root, Value) + Clone + 'static,
80    getter: impl Fn(&Root) -> Value + Clone + 'static,
81    update: impl Fn(Value) -> Value + 'static,
82) -> impl Fn(Root) -> Root
83where
84    Root: Clone + 'static,
85    Value: Clone + 'static,
86{
87    let prop_fn = prop(setter, getter);
88    prop_fn(Box::new(update))
89}
90
91// /// Immutable set
92// pub fn set<Root, Value>(
93//     setter: impl Fn(&mut Root, Value) + Clone + 'static,
94//     getter: impl Fn(&Root) -> Value + Clone + 'static,
95//     value: Value,
96// ) -> impl Fn(Root) -> Root
97// where
98//     Root: Clone + 'static,
99//     Value: Clone + 'static,
100// {
101//     over(setter, getter, move |_| value.clone())
102// }
103
104/// Mutable prop
105pub fn mprop<Root, Value>(
106    setter: impl Fn(&mut Root, Value) + Clone + 'static,
107    getter: impl Fn(&mut Root) -> &mut Value + Clone + 'static,
108) -> impl Fn(Box<dyn FnMut(&mut Value)>) -> Box<dyn FnMut(&mut Root)>
109where
110    Root: 'static,
111    Value: 'static,
112{
113    let setter = Rc::new(setter);
114    let getter = Rc::new(getter);
115    move |mut update: Box<dyn FnMut(&mut Value)>| {
116        let setter = setter.clone();
117        let getter = getter.clone();
118        Box::new(move |root: &mut Root| {
119            let value = getter(root);
120            update(value);
121        })
122    }
123}
124
125/// Mutable version (uncurried)
126pub fn mver<Root, Value>(
127    setter: impl Fn(&mut Root, Value) + Clone + 'static,
128    getter: impl Fn(&mut Root) -> &mut Value + Clone + 'static,
129    mut update: impl FnMut(&mut Value) + 'static,
130) -> impl FnMut(&mut Root)
131where
132    Root: 'static,
133    Value: 'static,
134{
135    let mprop_fn = mprop(setter, getter);
136    let boxed_update = Box::new(update);
137    let mut setter_fn = mprop_fn(boxed_update);
138    move |root| setter_fn(root)
139}
140
141// /// Mutable in-place set with a constant value
142// pub fn mut_<Root, Value>(
143//     setter: impl Fn(&mut Root, Value) + Clone + 'static,
144//     getter: impl Fn(&mut Root) -> &mut Value + Clone + 'static,
145//     value: Value,
146// ) -> impl FnMut(&mut Root)
147// where
148//     Root: 'static,
149//     Value: Clone + 'static,
150// {
151//     mver(setter, getter, move |v| *v = value.clone())
152// }