Skip to main content

euv_core/reactive/cast/
impl.rs

1use super::*;
2
3/// Converts a static `String` into a text attribute value.
4impl From<String> for AttributeValue {
5    /// Converts this string into an `AttributeValue::Text`.
6    ///
7    /// # Returns
8    ///
9    /// - `AttributeValue` - A text attribute value containing this string.
10    ///
11    /// # Arguments
12    ///
13    /// - `String` - Input value to convert from.
14    fn from(value: String) -> Self {
15        AttributeValue::Text(value)
16    }
17}
18
19/// Converts a string slice into a text attribute value.
20impl From<&str> for AttributeValue {
21    /// Converts this string slice into an `AttributeValue::Text`.
22    ///
23    /// # Returns
24    ///
25    /// - `AttributeValue` - A text attribute value containing the owned string.
26    ///
27    /// # Arguments
28    ///
29    /// - `&str` - Input value to convert from.
30    fn from(value: &str) -> Self {
31        AttributeValue::Text(value.to_string())
32    }
33}
34
35/// Converts a string signal into a reactive attribute value.
36impl From<Signal<String>> for AttributeValue {
37    /// Converts this string signal into an `AttributeValue::Signal`.
38    ///
39    /// # Returns
40    ///
41    /// - `AttributeValue` - A signal-backed attribute value.
42    ///
43    /// # Arguments
44    ///
45    /// - `Signal<String>` - Input value to convert from.
46    fn from(signal: Signal<String>) -> Self {
47        AttributeValue::Signal(signal)
48    }
49}
50
51/// Converts a mutable bool signal into a reactive attribute value.
52///
53/// The signal is mapped to a `Signal<String>` that yields `"true"` or `"false"`,
54/// enabling boolean attributes like `checked` to reactively update the DOM.
55impl From<Signal<bool>> for AttributeValue {
56    /// Converts this bool signal into an `AttributeValue` via string mapping.
57    ///
58    /// # Returns
59    ///
60    /// - `AttributeValue` - A signal-backed attribute value yielding `"true"` or `"false"`.
61    ///
62    /// # Arguments
63    ///
64    /// - `Signal<bool>` - Input value to convert from.
65    fn from(signal: Signal<bool>) -> Self {
66        AttributeValue::bool_to_attr(signal)
67    }
68}
69
70/// Converts a `bool` into a dynamic attribute value.
71///
72/// Stored as `AttributeValue::Dynamic("true"/"false")` so components can
73/// extract the original boolean via `try_get_typed_prop`.
74impl From<bool> for AttributeValue {
75    /// Converts this boolean into an `AttributeValue::Dynamic`.
76    ///
77    /// # Returns
78    ///
79    /// - `AttributeValue` - A dynamic attribute value containing the boolean string.
80    ///
81    /// # Arguments
82    ///
83    /// - `bool` - Input value to convert from.
84    fn from(value: bool) -> Self {
85        AttributeValue::Dynamic(value.to_string())
86    }
87}
88
89/// Converts an `i32` into a dynamic attribute value.
90///
91/// Stored as `AttributeValue::Dynamic` so components can extract the
92/// original integer via `try_get_typed_prop`.
93impl From<i32> for AttributeValue {
94    /// Converts this integer into an `AttributeValue::Dynamic`.
95    ///
96    /// # Returns
97    ///
98    /// - `AttributeValue` - A dynamic attribute value containing the integer string.
99    ///
100    /// # Arguments
101    ///
102    /// - `i32` - Input value to convert from.
103    fn from(value: i32) -> Self {
104        AttributeValue::Dynamic(value.to_string())
105    }
106}
107
108/// Converts an `f64` into a dynamic attribute value.
109///
110/// Stored as `AttributeValue::Dynamic` so components can extract the
111/// original float via `try_get_typed_prop`.
112impl From<f64> for AttributeValue {
113    /// Converts this float into an `AttributeValue::Dynamic`.
114    ///
115    /// # Returns
116    ///
117    /// - `AttributeValue` - A dynamic attribute value containing the float string.
118    ///
119    /// # Arguments
120    ///
121    /// - `f64` - Input value to convert from.
122    fn from(value: f64) -> Self {
123        AttributeValue::Dynamic(value.to_string())
124    }
125}
126
127/// Converts a CSS class reference into an attribute value.
128impl From<Css> for AttributeValue {
129    /// Converts this CSS class into an `AttributeValue::Css`.
130    ///
131    /// # Returns
132    ///
133    /// - `AttributeValue` - A CSS class attribute value.
134    ///
135    /// # Arguments
136    ///
137    /// - `Css` - Input value to convert from.
138    fn from(css: Css) -> Self {
139        AttributeValue::Css(css)
140    }
141}
142
143/// Converts a reference to a CSS class into an attribute value without cloning.
144///
145/// OPT 11: previously this impl deep-cloned the `Css` struct (name, style,
146/// pseudo_rules, media_rules) every time a static class was referenced from
147/// `html!`. The `class!` macro produces `&'static Css` references backed
148/// by `OnceLock`, so storing the reference directly is sound and removes
149/// the per-element allocation.
150impl From<&'static Css> for AttributeValue {
151    /// Converts this CSS class reference into an `AttributeValue::CssRef`
152    /// without cloning.
153    ///
154    /// # Returns
155    ///
156    /// - `AttributeValue` - A CSS class attribute value borrowing the
157    ///   `class!` macro's static storage.
158    ///
159    /// # Arguments
160    ///
161    /// - `&'static Css` - Input value to convert from.
162    fn from(css: &'static Css) -> Self {
163        AttributeValue::CssRef(css)
164    }
165}
166
167/// Converts a closure into a callback attribute value.
168impl<F> From<F> for AttributeValue
169where
170    F: FnMut(Event) + 'static,
171{
172    /// Wraps this closure into an `AttributeValue::Event` with a generic "callback" event name.
173    ///
174    /// # Returns
175    ///
176    /// - `AttributeValue` - An event attribute value wrapping this closure.
177    ///
178    /// # Arguments
179    ///
180    /// - `F` - Input value to convert from.
181    fn from(closure: F) -> Self {
182        AttributeValue::Event(NativeEventHandler::create(CALLBACK_EVENT_NAME, closure))
183    }
184}
185
186/// Converts an owned event handler into a callback attribute value.
187///
188/// Re-wraps the handler with a generic "callback" event name so that
189/// subsequent `EventAdapter::into_attribute` calls can override it with
190/// the correct DOM event type.
191impl From<NativeEventHandler> for AttributeValue {
192    /// Converts this event handler into an `AttributeValue::Event`.
193    ///
194    /// # Returns
195    ///
196    /// - `AttributeValue` - An event attribute value with a generic callback event name.
197    ///
198    /// # Arguments
199    ///
200    /// - `NativeEventHandler` - Input value to convert from.
201    ///
202    /// This is the base case of the `NativeEventHandler` ->
203    /// `AttrValueAdapter<NativeEventHandler>` -> `NativeEventHandler`
204    /// conversion cycle. Calling `.into()` on the adapter instead would
205    /// land back in this impl through the generic
206    /// `From<AttrValueAdapter<T>>` (which unwraps and calls `T::into()`),
207    /// recursing forever.
208    fn from(handler: NativeEventHandler) -> Self {
209        AttrValueAdapter::new(handler).into_callback_named(CALLBACK_EVENT_NAME)
210    }
211}
212
213/// Converts an optional event handler into a callback attribute value.
214///
215/// Re-wraps a `Some` handler with a generic "callback" event name so that
216/// subsequent `EventAdapter::into_attribute` calls can override it with
217/// the correct DOM event type.
218impl From<Option<NativeEventHandler>> for AttributeValue {
219    /// Converts this optional handler into an `AttributeValue::Event` or `AttributeValue::Text` if `None`.
220    ///
221    /// # Returns
222    ///
223    /// - `AttributeValue` - An event attribute value if `Some`, otherwise an empty text attribute.
224    ///
225    /// # Arguments
226    ///
227    /// - `Option<NativeEventHandler>` - Input value to convert from.
228    fn from(handler: Option<NativeEventHandler>) -> Self {
229        match handler {
230            Some(event_handler) => {
231                AttrValueAdapter::new(event_handler).into_callback_named(CALLBACK_EVENT_NAME)
232            }
233            None => AttributeValue::Text(String::new()),
234        }
235    }
236}
237
238/// Converts an optional string signal into a reactive or empty attribute value.
239///
240/// `Some(signal)` becomes `AttributeValue::Signal`, `None` becomes
241/// `AttributeValue::Text(String::new())`. This supports component props
242/// that use `Option<Signal<String>>` for optional reactive attributes.
243impl From<Option<Signal<String>>> for AttributeValue {
244    /// Converts this optional signal into an `AttributeValue::Signal` or `AttributeValue::Text` if `None`.
245    ///
246    /// # Returns
247    ///
248    /// - `AttributeValue` - A signal-backed attribute value if `Some`, otherwise an empty text attribute.
249    ///
250    /// # Arguments
251    ///
252    /// - `Option<Signal<String>>` - Input value to convert from.
253    fn from(signal: Option<Signal<String>>) -> Self {
254        match signal {
255            Some(string_signal) => AttributeValue::Signal(string_signal),
256            None => AttributeValue::Text(String::new()),
257        }
258    }
259}