topcoat_runtime/surrogate/
signal.rs1use ref_cast::RefCast;
2use serde::Serialize;
3
4use crate::{
5 Signal, StrSurrogate, Surrogated, impl_surrogate, impl_surrogate_mut, impl_surrogate_ref,
6};
7
8#[derive(RefCast)]
9#[repr(transparent)]
10pub struct SignalSurrogate<T>(Signal<T>);
11
12impl<T> SignalSurrogate<T> {
13 #[inline]
14 pub(crate) const fn new(v: Signal<T>) -> Self {
15 Self(v)
16 }
17}
18
19impl<T> SignalSurrogate<T>
20where
21 for<'b> &'b T: Surrogated,
22{
23 pub fn read(&self) -> <&T as Surrogated>::Surrogate {
24 self.0.read().into_surrogate()
25 }
26}
27
28impl<T> SignalSurrogate<T>
29where
30 T: Surrogated + Clone,
31{
32 pub fn get(&self) -> <T as Surrogated>::Surrogate {
33 self.0.get().into_surrogate()
34 }
35}
36
37impl<T> SignalSurrogate<T>
38where
39 T: Surrogated,
40{
41 pub fn set(&self, _v: T::Surrogate) {
47 write_in_browser_only();
48 }
49}
50
51impl SignalSurrogate<bool> {
52 pub fn toggle(&self) {
58 write_in_browser_only();
59 }
60}
61
62impl SignalSurrogate<f64> {
63 pub fn increment(&self) {
69 write_in_browser_only();
70 }
71
72 pub fn decrement(&self) {
78 write_in_browser_only();
79 }
80}
81
82impl SignalSurrogate<String> {
83 pub fn push_str(&self, _s: &StrSurrogate) {
89 write_in_browser_only();
90 }
91}
92
93fn write_in_browser_only() -> ! {
95 panic!("expressions in which a signal is written to cannot be run server-side");
96}
97
98impl_surrogate!({T} Signal<T>, SignalSurrogate<T>);
99impl_surrogate_ref!({T} Signal<T>, SignalSurrogate<T>);
100impl_surrogate_mut!({T} Signal<T>, SignalSurrogate<T>);
101
102impl<T> Serialize for SignalSurrogate<T> {
103 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
104 where
105 S: serde::Serializer,
106 {
107 #[derive(Serialize)]
108 struct TaggedSignal {
109 t: &'static str,
110 id: std::string::String,
111 }
112
113 TaggedSignal {
114 t: "Signal",
115 id: self.0.id().to_string(),
116 }
117 .serialize(serializer)
118 }
119}
120
121#[cfg(test)]
122mod tests {
123 use super::*;
124
125 #[test]
126 #[should_panic(expected = "cannot be run server-side")]
127 fn toggle_panics_server_side() {
128 SignalSurrogate::new(Signal::new(false)).toggle();
129 }
130
131 #[test]
132 #[should_panic(expected = "cannot be run server-side")]
133 fn increment_panics_server_side() {
134 SignalSurrogate::new(Signal::new(0.0)).increment();
135 }
136
137 #[test]
138 #[should_panic(expected = "cannot be run server-side")]
139 fn decrement_panics_server_side() {
140 SignalSurrogate::new(Signal::new(0.0)).decrement();
141 }
142
143 #[test]
144 #[should_panic(expected = "cannot be run server-side")]
145 fn push_str_panics_server_side() {
146 SignalSurrogate::new(Signal::new(String::new())).push_str(StrSurrogate::ref_cast(""));
147 }
148}