ravenrs_reactive/
binding.rs1use std::fmt;
2use std::rc::Rc;
3
4pub struct Binding<T> {
10 get: Rc<dyn Fn() -> T>,
11 set: Rc<dyn Fn(T)>,
12}
13
14impl<T: 'static> Binding<T> {
15 pub fn new(get: impl Fn() -> T + 'static, set: impl Fn(T) + 'static) -> Self {
17 Self { get: Rc::new(get), set: Rc::new(set) }
18 }
19
20 pub fn constant(value: T) -> Self
22 where
23 T: Clone,
24 {
25 Self::new(move || value.clone(), |_| {})
26 }
27
28 pub fn get(&self) -> T {
30 (self.get)()
31 }
32
33 pub fn set(&self, value: T) {
35 (self.set)(value)
36 }
37
38 pub fn update(&self, f: impl FnOnce(&mut T)) {
40 let mut v = self.get();
41 f(&mut v);
42 self.set(v);
43 }
44
45 pub fn map<U: 'static>(
47 &self,
48 get: impl Fn(&T) -> U + 'static,
49 set: impl Fn(&mut T, U) + 'static,
50 ) -> Binding<U> {
51 let (outer_get, outer_set) = (self.get.clone(), self.set.clone());
52 let read = self.get.clone();
53 Binding::new(
54 move || get(&read()),
55 move |u| {
56 let mut whole = outer_get();
57 set(&mut whole, u);
58 outer_set(whole);
59 },
60 )
61 }
62}
63
64impl<T> Clone for Binding<T> {
65 fn clone(&self) -> Self {
66 Self { get: self.get.clone(), set: self.set.clone() }
67 }
68}
69
70impl<T> fmt::Debug for Binding<T> {
71 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72 f.write_str("Binding")
73 }
74}
75
76#[cfg(test)]
77mod tests {
78 use crate::State;
79
80 #[derive(Clone, Debug, PartialEq)]
81 struct Settings {
82 volume: u8,
83 muted: bool,
84 }
85
86 #[test]
87 fn binding_writes_through_to_state() {
88 let s = State::new(1);
89 let b = s.binding();
90 b.update(|v| *v += 41);
91 assert_eq!(s.get(), 42);
92 }
93
94 #[test]
95 fn mapped_binding_edits_one_field() {
96 let s = State::new(Settings { volume: 3, muted: false });
97 let muted = s.binding().map(|s| s.muted, |s, m| s.muted = m);
98 muted.set(true);
99 assert_eq!(s.get(), Settings { volume: 3, muted: true });
100 }
101}