freya_core/lifecycle/
writable.rs1use std::{
4 cell::{
5 Ref,
6 RefMut,
7 },
8 rc::Rc,
9};
10
11use crate::prelude::*;
12
13pub struct Writable<T: 'static> {
54 pub(crate) peek_fn: Rc<dyn Fn() -> ReadRef<'static, T>>,
55 pub(crate) write_fn: Rc<dyn Fn() -> WriteRef<'static, T>>,
56 pub(crate) subscribe_fn: Rc<dyn Fn()>,
57 pub(crate) notify_fn: Rc<dyn Fn()>,
58}
59
60impl<T: 'static> PartialEq for Writable<T> {
61 fn eq(&self, _other: &Self) -> bool {
62 true
63 }
64}
65
66impl<T: 'static> Clone for Writable<T> {
67 fn clone(&self) -> Self {
68 Self {
69 peek_fn: self.peek_fn.clone(),
70 write_fn: self.write_fn.clone(),
71 subscribe_fn: self.subscribe_fn.clone(),
72 notify_fn: self.notify_fn.clone(),
73 }
74 }
75}
76
77impl<T: 'static> Writable<T> {
78 pub fn from_state(state: State<T>) -> Self {
80 Self {
81 peek_fn: Rc::new(move || state.peek_unchecked()),
82 write_fn: Rc::new(move || state.write_silently()),
83 subscribe_fn: Rc::new(move || state.subscribe()),
84 notify_fn: Rc::new(move || state.notify()),
85 }
86 }
87
88 pub fn new(
90 peek_fn: impl Fn() -> ReadRef<'static, T> + 'static,
91 write_fn: impl Fn() -> WriteRef<'static, T> + 'static,
92 subscribe_fn: impl Fn() + 'static,
93 notify_fn: impl Fn() + 'static,
94 ) -> Self {
95 Self {
96 peek_fn: Rc::new(peek_fn),
97 write_fn: Rc::new(write_fn),
98 subscribe_fn: Rc::new(subscribe_fn),
99 notify_fn: Rc::new(notify_fn),
100 }
101 }
102
103 #[track_caller]
105 pub fn read(&self) -> ReadRef<'_, T> {
106 self.subscribe();
107 self.peek()
108 }
109
110 #[track_caller]
112 pub fn peek(&self) -> ReadRef<'_, T> {
113 (self.peek_fn)()
114 }
115
116 #[track_caller]
121 pub fn read_unchecked(&self) -> ReadRef<'static, T> {
122 self.subscribe();
123 (self.peek_fn)()
124 }
125
126 #[track_caller]
128 pub fn write(&mut self) -> WriteRef<'_, T> {
129 self.notify();
130 (self.write_fn)()
131 }
132
133 #[track_caller]
134 pub fn write_if(&mut self, with: impl FnOnce(WriteRef<'_, T>) -> bool) -> bool {
135 let changed = with((self.write_fn)());
136 if changed {
137 self.notify();
138 }
139 changed
140 }
141
142 fn subscribe(&self) {
144 (self.subscribe_fn)()
145 }
146
147 fn notify(&self) {
149 (self.notify_fn)()
150 }
151
152 pub fn map<O>(
163 &self,
164 get: impl Fn(&T) -> &O + 'static,
165 get_mut: impl Fn(&mut T) -> &mut O + 'static,
166 ) -> Writable<O> {
167 let peek_fn = self.peek_fn.clone();
168 let write_fn = self.write_fn.clone();
169 Writable {
170 peek_fn: Rc::new(move || (peek_fn)().map(|r| Ref::map(r, |v| get(v)))),
171 write_fn: Rc::new(move || (write_fn)().map(|r| RefMut::map(r, |v| get_mut(v)))),
172 subscribe_fn: self.subscribe_fn.clone(),
173 notify_fn: self.notify_fn.clone(),
174 }
175 }
176}
177
178pub trait IntoWritable<T: 'static> {
179 fn into_writable(self) -> Writable<T>;
180}
181
182impl<T: 'static> IntoWritable<T> for Writable<T> {
183 fn into_writable(self) -> Writable<T> {
184 self
185 }
186}
187
188impl<T: 'static> IntoWritable<T> for State<T> {
189 fn into_writable(self) -> Writable<T> {
190 Writable::from_state(self)
191 }
192}
193
194impl<T> From<State<T>> for Writable<T> {
195 fn from(value: State<T>) -> Self {
196 value.into_writable()
197 }
198}
199
200impl<T> From<Writable<T>> for Readable<T> {
201 fn from(value: Writable<T>) -> Self {
202 Readable {
203 read_fn: Rc::new({
204 let value = value.clone();
205 move || {
206 value.subscribe();
207 ReadableRef::Ref((value.peek_fn)())
208 }
209 }),
210 peek_fn: Rc::new(move || ReadableRef::Ref((value.peek_fn)())),
211 equal_fn: Rc::new(move |_| true),
212 }
213 }
214}