1use crossbeam_channel::{Receiver, unbounded};
2use serde::{Serialize, de::DeserializeOwned};
3use std::thread;
4
5use crate::{ChangeEvent, SettingsError, SettingsHandle, StoredValue};
6
7type FieldGetter<T, V> = Box<dyn for<'a> Fn(&'a T) -> &'a V + Send + Sync + 'static>;
8type FieldMutator<T, V> = Box<dyn Fn(&mut T, V) + Send + Sync + 'static>;
9
10pub struct ReadOnlyField<T, V> {
12 handle: SettingsHandle<T>,
13 getter: FieldGetter<T, V>,
14}
15
16impl<T, V> ReadOnlyField<T, V>
17where
18 T: Clone + Send + Sync + 'static,
19 V: Clone,
20{
21 pub fn new(handle: SettingsHandle<T>, getter: FieldGetter<T, V>) -> Self {
23 Self { handle, getter }
24 }
25
26 pub fn get(&self) -> V {
28 let snapshot = self.handle.snapshot();
29 (self.getter)(snapshot.as_ref()).clone()
30 }
31}
32
33pub struct PersistedField<T, V> {
35 handle: SettingsHandle<T>,
36 key: &'static str,
37 getter: FieldGetter<T, V>,
38 mutator: FieldMutator<T, V>,
39}
40
41impl<T, V> PersistedField<T, V>
42where
43 T: Clone + Send + Sync + 'static,
44 V: Clone,
45{
46 pub fn new(
48 handle: SettingsHandle<T>,
49 key: &'static str,
50 getter: FieldGetter<T, V>,
51 mutator: FieldMutator<T, V>,
52 ) -> Self {
53 Self {
54 handle,
55 key,
56 getter,
57 mutator,
58 }
59 }
60
61 pub fn get(&self) -> V {
63 let snapshot = self.handle.snapshot();
64 (self.getter)(snapshot.as_ref()).clone()
65 }
66}
67
68impl<T, V> PersistedField<T, V>
69where
70 T: Clone + Send + Sync + 'static,
71 V: Clone + Serialize,
72{
73 pub fn set(&self, value: V) -> Result<(), SettingsError> {
75 let old_value = Some(StoredValue::encode(&self.get())?);
76 let stored = StoredValue::encode(&value)?;
77 let mutator = &self.mutator;
78
79 self.handle
80 .write_field(self.key, old_value, stored, |next| {
81 mutator(next, value);
82 })
83 }
84}
85
86impl<T, V> PersistedField<T, V>
87where
88 T: Clone + Send + Sync + 'static,
89 V: DeserializeOwned + Send + 'static,
90{
91 pub fn on_change(&self) -> Receiver<V> {
97 let source = self.handle.on_change();
98 let (tx, rx) = unbounded();
99 let key = self.key.to_string();
100
101 thread::spawn(move || {
102 while let Ok(event) = source.recv() {
103 let ChangeEvent::Set {
104 key: event_key,
105 new_value,
106 ..
107 } = event
108 else {
109 continue;
110 };
111
112 if event_key != key {
113 continue;
114 }
115
116 let Ok(decoded) = new_value.decode::<V>() else {
117 continue;
118 };
119
120 if tx.send(decoded).is_err() {
121 return;
122 }
123 }
124 });
125
126 rx
127 }
128}