freya_core/lifecycle/
writable.rs1use std::rc::Rc;
4
5use crate::prelude::*;
6
7pub struct Writable<T: 'static> {
48 pub(crate) peek_fn: Rc<dyn Fn() -> ReadRef<'static, T>>,
49 pub(crate) write_fn: Rc<dyn Fn() -> WriteRef<'static, T>>,
50 pub(crate) subscribe_fn: Rc<dyn Fn()>,
51 pub(crate) notify_fn: Rc<dyn Fn()>,
52}
53
54impl<T: 'static> PartialEq for Writable<T> {
55 fn eq(&self, _other: &Self) -> bool {
56 true
57 }
58}
59
60impl<T: 'static> Clone for Writable<T> {
61 fn clone(&self) -> Self {
62 Self {
63 peek_fn: self.peek_fn.clone(),
64 write_fn: self.write_fn.clone(),
65 subscribe_fn: self.subscribe_fn.clone(),
66 notify_fn: self.notify_fn.clone(),
67 }
68 }
69}
70
71impl<T: 'static> Writable<T> {
72 pub fn from_state(state: State<T>) -> Self {
74 Self {
75 peek_fn: Rc::new(move || state.peek()),
76 write_fn: Rc::new(move || state.write_silently()),
77 subscribe_fn: Rc::new(move || state.subscribe()),
78 notify_fn: Rc::new(move || state.notify()),
79 }
80 }
81
82 pub fn new(
84 peek_fn: impl Fn() -> ReadRef<'static, T> + 'static,
85 write_fn: impl Fn() -> WriteRef<'static, T> + 'static,
86 subscribe_fn: impl Fn() + 'static,
87 notify_fn: impl Fn() + 'static,
88 ) -> Self {
89 Self {
90 peek_fn: Rc::new(peek_fn),
91 write_fn: Rc::new(write_fn),
92 subscribe_fn: Rc::new(subscribe_fn),
93 notify_fn: Rc::new(notify_fn),
94 }
95 }
96
97 #[track_caller]
99 pub fn read(&self) -> ReadRef<'static, T> {
100 self.subscribe();
101 self.peek()
102 }
103
104 #[track_caller]
106 pub fn peek(&self) -> ReadRef<'static, T> {
107 (self.peek_fn)()
108 }
109
110 #[track_caller]
112 pub fn write(&mut self) -> WriteRef<'static, T> {
113 self.notify();
114 (self.write_fn)()
115 }
116
117 #[track_caller]
118 pub fn write_if(&mut self, with: impl FnOnce(WriteRef<'static, T>) -> bool) -> bool {
119 let changed = with((self.write_fn)());
120 if changed {
121 self.notify();
122 }
123 changed
124 }
125
126 fn subscribe(&self) {
128 (self.subscribe_fn)()
129 }
130
131 fn notify(&self) {
133 (self.notify_fn)()
134 }
135
136 pub fn map<O>(
150 &self,
151 peek_fn: impl Fn() -> ReadRef<'static, O> + 'static,
152 write_fn: impl Fn() -> WriteRef<'static, O> + 'static,
153 ) -> Writable<O> {
154 Writable {
155 peek_fn: Rc::new(peek_fn),
156 write_fn: Rc::new(write_fn),
157 subscribe_fn: self.subscribe_fn.clone(),
158 notify_fn: self.notify_fn.clone(),
159 }
160 }
161}
162
163pub trait IntoWritable<T: 'static> {
164 fn into_writable(self) -> Writable<T>;
165}
166
167impl<T: 'static> IntoWritable<T> for State<T> {
168 fn into_writable(self) -> Writable<T> {
169 Writable::from_state(self)
170 }
171}
172
173impl<T> From<State<T>> for Writable<T> {
174 fn from(value: State<T>) -> Self {
175 value.into_writable()
176 }
177}
178
179impl<T> From<Writable<T>> for Readable<T> {
180 fn from(value: Writable<T>) -> Self {
181 Readable {
182 read_fn: Rc::new({
183 let value = value.clone();
184 move || {
185 value.subscribe();
186 ReadableRef::Ref((value.peek_fn)())
187 }
188 }),
189 peek_fn: Rc::new(move || ReadableRef::Ref((value.peek_fn)())),
190 equal_fn: Rc::new(move |_| true),
191 }
192 }
193}