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 #[track_caller]
96 #[allow(invalid_reference_casting)]
97 pub fn read(&'_ self) -> ReadRef<'_, SliceValue> {
98 self.subscribe_if_not();
99 self.peek()
100 }
101
102 #[track_caller]
104 #[allow(invalid_reference_casting)]
105 pub fn read_unchecked(&'_ self) -> ReadRef<'static, SliceValue> {
106 self.subscribe_if_not();
107 self.peek_unchecked()
108 }
109
110 #[track_caller]
112 #[allow(invalid_reference_casting)]
113 pub fn peek(&'_ self) -> ReadRef<'_, SliceValue> {
114 self.peek_unchecked()
115 }
116
117 #[track_caller]
119 #[allow(invalid_reference_casting)]
120 pub fn peek_unchecked(&'_ self) -> ReadRef<'static, SliceValue> {
121 let inner = self.station.peek_unchecked();
122 inner.map(|v| {
123 Ref::map(v, |v| {
124 (self.selector)(unsafe { &mut *(v as *const Value as *mut Value) })
125 })
126 })
127 }
128}
129
130pub struct RadioSliceMut<Value, SliceValue, Channel>
141where
142 Channel: RadioChannel<Value>,
143 Value: 'static,
144 SliceValue: 'static,
145{
146 channel: Channel,
147 pub(crate) station: RadioStation<Value, Channel>,
148 selector: Rc<dyn Fn(&mut Value) -> &mut SliceValue>,
149 _marker: PhantomData<SliceValue>,
150}
151
152impl<Value, SliceValue, Channel> Clone for RadioSliceMut<Value, SliceValue, Channel>
153where
154 Channel: RadioChannel<Value>,
155 SliceValue: 'static,
156{
157 fn clone(&self) -> Self {
158 Self {
159 channel: self.channel.clone(),
160 station: self.station,
161 selector: self.selector.clone(),
162 _marker: PhantomData,
163 }
164 }
165}
166
167impl<Value, SliceValue, Channel> PartialEq for RadioSliceMut<Value, SliceValue, Channel>
168where
169 Channel: RadioChannel<Value>,
170 SliceValue: 'static,
171{
172 fn eq(&self, other: &Self) -> bool {
173 self.channel == other.channel
174 }
175}
176
177impl<Value, SliceValue, Channel> RadioSliceMut<Value, SliceValue, Channel>
178where
179 Channel: RadioChannel<Value>,
180 SliceValue: 'static,
181{
182 pub(crate) fn new(
183 channel: Channel,
184 station: RadioStation<Value, Channel>,
185 selector: impl Fn(&mut Value) -> &mut SliceValue + 'static,
186 ) -> RadioSliceMut<Value, SliceValue, Channel> {
187 RadioSliceMut {
188 channel,
189 station,
190 selector: Rc::new(selector),
191 _marker: PhantomData,
192 }
193 }
194
195 pub(crate) fn subscribe_if_not(&self) {
196 if let Some(rc) = ReactiveContext::try_current() {
197 let is_listening = self.station.is_listening(&self.channel, &rc);
198
199 if !is_listening {
200 self.station.listen(self.channel.clone(), rc);
201 }
202 }
203 }
204
205 #[track_caller]
207 #[allow(invalid_reference_casting)]
208 pub fn read(&'_ self) -> ReadRef<'_, SliceValue> {
209 self.subscribe_if_not();
210 self.peek()
211 }
212
213 #[track_caller]
215 #[allow(invalid_reference_casting)]
216 pub fn read_unchecked(&'_ self) -> ReadRef<'static, SliceValue> {
217 self.subscribe_if_not();
218 self.peek_unchecked()
219 }
220
221 #[track_caller]
223 #[allow(invalid_reference_casting)]
224 pub fn peek(&'_ self) -> ReadRef<'_, SliceValue> {
225 self.peek_unchecked()
226 }
227
228 #[track_caller]
230 #[allow(invalid_reference_casting)]
231 pub fn peek_unchecked(&'_ self) -> ReadRef<'static, SliceValue> {
232 let inner = self.station.peek_unchecked();
233 inner.map(|v| {
234 Ref::map(v, |v| {
235 (self.selector)(unsafe { &mut *(v as *const Value as *mut Value) })
236 })
237 })
238 }
239
240 #[track_caller]
242 pub fn write_unchecked(&'_ self) -> WriteRef<'static, SliceValue> {
243 self.notify();
244 self.write_silently()
245 }
246
247 #[track_caller]
249 pub fn write_silently(&'_ self) -> WriteRef<'static, SliceValue> {
250 let value = self.station.value.write_unchecked();
251 let selector = self.selector.clone();
252 value.map(|v| RefMut::map(v, |v| selector(v)))
253 }
254
255 pub fn notify(&self) {
257 let value = self.station.peek_unchecked();
258 for channel in self.channel.clone().derive_channel(&value) {
259 self.station.notify_listeners(&channel)
260 }
261 self.station.cleanup();
262 }
263
264 #[track_caller]
266 pub fn write(&'_ mut self) -> WriteRef<'_, SliceValue> {
267 self.write_unchecked()
268 }
269}
270
271impl<Value, SliceValue, Channel> WritableUtils<SliceValue>
272 for RadioSliceMut<Value, SliceValue, Channel>
273where
274 Channel: RadioChannel<Value>,
275 Value: 'static,
276 SliceValue: 'static,
277{
278 fn write_state(&mut self) -> WriteRef<'static, SliceValue> {
279 self.write_unchecked()
280 }
281
282 fn peek_state(&self) -> ReadRef<'static, SliceValue> {
283 self.peek_unchecked()
284 }
285}
286
287impl<Value, Channel> Radio<Value, Channel>
288where
289 Channel: RadioChannel<Value>,
290 Value: 'static,
291{
292 pub fn slice<SliceValue>(
300 &self,
301 channel: Channel,
302 selector: impl Fn(&Value) -> &SliceValue + 'static,
303 ) -> RadioSlice<Value, SliceValue, Channel> {
304 let station = self.antenna.peek().station;
305 RadioSlice::new(channel, station, selector)
306 }
307
308 pub fn slice_current<SliceValue>(
316 &self,
317 selector: impl Fn(&Value) -> &SliceValue + 'static,
318 ) -> RadioSlice<Value, SliceValue, Channel> {
319 let channel = self.antenna.peek().channel.clone();
320 self.slice(channel, selector)
321 }
322
323 pub fn slice_mut<SliceValue>(
331 &self,
332 channel: Channel,
333 selector: impl Fn(&mut Value) -> &mut SliceValue + 'static,
334 ) -> RadioSliceMut<Value, SliceValue, Channel> {
335 let station = self.antenna.peek().station;
336 RadioSliceMut::new(channel, station, selector)
337 }
338
339 pub fn slice_mut_current<SliceValue>(
347 &self,
348 selector: impl Fn(&mut Value) -> &mut SliceValue + 'static,
349 ) -> RadioSliceMut<Value, SliceValue, Channel> {
350 let channel = self.antenna.peek().channel.clone();
351 self.slice_mut(channel, selector)
352 }
353}