1use std::{
2 cell::{
3 Ref,
4 RefMut,
5 },
6 marker::PhantomData,
7 rc::Rc,
8};
9
10use freya_core::prelude::*;
11
12use crate::hooks::{
13 Radio,
14 RadioChannel,
15 RadioStation,
16};
17
18pub struct RadioSlice<Value, SliceValue, Channel>
30where
31 Channel: RadioChannel<Value>,
32 Value: 'static,
33 SliceValue: 'static,
34{
35 channel: Channel,
36 station: RadioStation<Value, Channel>,
37 selector: Rc<dyn Fn(&Value) -> &SliceValue>,
38 _marker: PhantomData<SliceValue>,
39}
40
41impl<Value, SliceValue, Channel> Clone for RadioSlice<Value, SliceValue, Channel>
42where
43 Channel: RadioChannel<Value>,
44 SliceValue: 'static,
45{
46 fn clone(&self) -> Self {
47 Self {
48 channel: self.channel.clone(),
49 station: self.station,
50 selector: self.selector.clone(),
51 _marker: PhantomData,
52 }
53 }
54}
55
56impl<Value, SliceValue, Channel> PartialEq for RadioSlice<Value, SliceValue, Channel>
57where
58 Channel: RadioChannel<Value>,
59 SliceValue: 'static,
60{
61 fn eq(&self, other: &Self) -> bool {
62 self.channel == other.channel
63 }
64}
65
66impl<Value, SliceValue, Channel> RadioSlice<Value, SliceValue, Channel>
67where
68 Channel: RadioChannel<Value>,
69 SliceValue: 'static,
70{
71 pub(crate) fn new(
72 channel: Channel,
73 station: RadioStation<Value, Channel>,
74 selector: impl Fn(&Value) -> &SliceValue + 'static,
75 ) -> RadioSlice<Value, SliceValue, Channel> {
76 RadioSlice {
77 channel,
78 station,
79 selector: Rc::new(selector),
80 _marker: PhantomData,
81 }
82 }
83
84 pub(crate) fn subscribe_if_not(&self) {
85 if let Some(rc) = ReactiveContext::try_current() {
86 let is_listening = self.station.is_listening(&self.channel, &rc);
87
88 if !is_listening {
89 self.station.listen(self.channel.clone(), rc);
90 }
91 }
92 }
93
94 #[allow(invalid_reference_casting)]
96 pub fn read(&'_ self) -> ReadRef<'_, SliceValue> {
97 self.subscribe_if_not();
98 self.peek()
99 }
100
101 #[allow(invalid_reference_casting)]
103 pub fn read_unchecked(&'_ self) -> ReadRef<'static, SliceValue> {
104 self.subscribe_if_not();
105 self.peek_unchecked()
106 }
107
108 #[allow(invalid_reference_casting)]
110 pub fn peek(&'_ self) -> ReadRef<'_, SliceValue> {
111 self.peek_unchecked()
112 }
113
114 #[allow(invalid_reference_casting)]
116 pub fn peek_unchecked(&'_ self) -> ReadRef<'static, SliceValue> {
117 let inner = self.station.peek_unchecked();
118 inner.map(|v| {
119 Ref::map(v, |v| {
120 (self.selector)(unsafe { &mut *(v as *const Value as *mut Value) })
121 })
122 })
123 }
124}
125
126pub struct RadioSliceMut<Value, SliceValue, Channel>
137where
138 Channel: RadioChannel<Value>,
139 Value: 'static,
140 SliceValue: 'static,
141{
142 channel: Channel,
143 pub(crate) station: RadioStation<Value, Channel>,
144 selector: Rc<dyn Fn(&mut Value) -> &mut SliceValue>,
145 _marker: PhantomData<SliceValue>,
146}
147
148impl<Value, SliceValue, Channel> Clone for RadioSliceMut<Value, SliceValue, Channel>
149where
150 Channel: RadioChannel<Value>,
151 SliceValue: 'static,
152{
153 fn clone(&self) -> Self {
154 Self {
155 channel: self.channel.clone(),
156 station: self.station,
157 selector: self.selector.clone(),
158 _marker: PhantomData,
159 }
160 }
161}
162
163impl<Value, SliceValue, Channel> PartialEq for RadioSliceMut<Value, SliceValue, Channel>
164where
165 Channel: RadioChannel<Value>,
166 SliceValue: 'static,
167{
168 fn eq(&self, other: &Self) -> bool {
169 self.channel == other.channel
170 }
171}
172
173impl<Value, SliceValue, Channel> RadioSliceMut<Value, SliceValue, Channel>
174where
175 Channel: RadioChannel<Value>,
176 SliceValue: 'static,
177{
178 pub(crate) fn new(
179 channel: Channel,
180 station: RadioStation<Value, Channel>,
181 selector: impl Fn(&mut Value) -> &mut SliceValue + 'static,
182 ) -> RadioSliceMut<Value, SliceValue, Channel> {
183 RadioSliceMut {
184 channel,
185 station,
186 selector: Rc::new(selector),
187 _marker: PhantomData,
188 }
189 }
190
191 pub(crate) fn subscribe_if_not(&self) {
192 if let Some(rc) = ReactiveContext::try_current() {
193 let is_listening = self.station.is_listening(&self.channel, &rc);
194
195 if !is_listening {
196 self.station.listen(self.channel.clone(), rc);
197 }
198 }
199 }
200
201 #[allow(invalid_reference_casting)]
203 pub fn read(&'_ self) -> ReadRef<'_, SliceValue> {
204 self.subscribe_if_not();
205 self.peek()
206 }
207
208 #[allow(invalid_reference_casting)]
210 pub fn read_unchecked(&'_ self) -> ReadRef<'static, SliceValue> {
211 self.subscribe_if_not();
212 self.peek_unchecked()
213 }
214
215 #[allow(invalid_reference_casting)]
217 pub fn peek(&'_ self) -> ReadRef<'_, SliceValue> {
218 self.peek_unchecked()
219 }
220
221 #[allow(invalid_reference_casting)]
223 pub fn peek_unchecked(&'_ self) -> ReadRef<'static, SliceValue> {
224 let inner = self.station.peek_unchecked();
225 inner.map(|v| {
226 Ref::map(v, |v| {
227 (self.selector)(unsafe { &mut *(v as *const Value as *mut Value) })
228 })
229 })
230 }
231
232 pub fn write_unchecked(&'_ self) -> WriteRef<'static, SliceValue> {
234 self.notify();
235 self.write_unchecked_no_notify()
236 }
237
238 pub fn write_unchecked_no_notify(&'_ self) -> WriteRef<'static, SliceValue> {
240 let value = self.station.value.write_unchecked();
241 let selector = self.selector.clone();
242 value.map(|v| RefMut::map(v, |v| selector(v)))
243 }
244
245 pub fn notify(&self) {
247 let value = self.station.peek_unchecked();
248 for channel in self.channel.clone().derive_channel(&value) {
249 self.station.notify_listeners(&channel)
250 }
251 self.station.cleanup();
252 }
253
254 pub fn write(&'_ mut self) -> WriteRef<'_, SliceValue> {
256 self.write_unchecked()
257 }
258}
259
260impl<Value, Channel> Radio<Value, Channel>
261where
262 Channel: RadioChannel<Value>,
263 Value: 'static,
264{
265 pub fn slice<SliceValue>(
273 &self,
274 channel: Channel,
275 selector: impl Fn(&Value) -> &SliceValue + 'static,
276 ) -> RadioSlice<Value, SliceValue, Channel> {
277 let station = self.antenna.peek().station;
278 RadioSlice::new(channel, station, selector)
279 }
280
281 pub fn slice_current<SliceValue>(
289 &self,
290 selector: impl Fn(&Value) -> &SliceValue + 'static,
291 ) -> RadioSlice<Value, SliceValue, Channel> {
292 let channel = self.antenna.peek().channel.clone();
293 self.slice(channel, selector)
294 }
295
296 pub fn slice_mut<SliceValue>(
304 &self,
305 channel: Channel,
306 selector: impl Fn(&mut Value) -> &mut SliceValue + 'static,
307 ) -> RadioSliceMut<Value, SliceValue, Channel> {
308 let station = self.antenna.peek().station;
309 RadioSliceMut::new(channel, station, selector)
310 }
311
312 pub fn slice_mut_current<SliceValue>(
320 &self,
321 selector: impl Fn(&mut Value) -> &mut SliceValue + 'static,
322 ) -> RadioSliceMut<Value, SliceValue, Channel> {
323 let channel = self.antenna.peek().channel.clone();
324 self.slice_mut(channel, selector)
325 }
326}