1#[doc(hidden)]
4pub mod key;
5#[doc(hidden)]
6pub mod listeners;
7#[doc(hidden)]
8pub mod vcomp;
9#[doc(hidden)]
10pub mod vlist;
11#[doc(hidden)]
12pub mod vnode;
13#[doc(hidden)]
14pub mod vportal;
15#[doc(hidden)]
16pub mod vraw;
17#[doc(hidden)]
18pub mod vsuspense;
19#[doc(hidden)]
20pub mod vtag;
21#[doc(hidden)]
22pub mod vtext;
23
24use std::hint::unreachable_unchecked;
25use std::rc::Rc;
26
27use indexmap::IndexMap;
28use wasm_bindgen::JsValue;
29
30#[doc(inline)]
31pub use self::key::Key;
32#[doc(inline)]
33pub use self::listeners::*;
34#[doc(inline)]
35pub use self::vcomp::{VChild, VComp};
36#[doc(inline)]
37pub use self::vlist::VList;
38#[doc(inline)]
39pub use self::vnode::VNode;
40#[doc(inline)]
41pub use self::vportal::VPortal;
42#[doc(inline)]
43pub use self::vraw::VRaw;
44#[doc(inline)]
45pub use self::vsuspense::VSuspense;
46#[doc(inline)]
47pub use self::vtag::VTag;
48#[doc(inline)]
49pub use self::vtext::VText;
50
51pub type AttrValue = implicit_clone::unsync::IString;
53
54#[cfg(any(feature = "ssr", feature = "hydration"))]
55mod feat_ssr_hydration {
56 #[cfg(debug_assertions)]
57 type ComponentName = &'static str;
58 #[cfg(not(debug_assertions))]
59 type ComponentName = std::marker::PhantomData<()>;
60
61 #[cfg(feature = "hydration")]
62 use std::borrow::Cow;
63
64 pub enum Collectable {
68 Component(ComponentName),
69 Raw,
70 Suspense,
71 }
72
73 impl Collectable {
74 #[cfg(not(debug_assertions))]
75 #[inline(always)]
76 pub fn for_component<T: 'static>() -> Self {
77 use std::marker::PhantomData;
78 let _comp_type: PhantomData<T> = PhantomData;
82 Self::Component(PhantomData)
83 }
84
85 #[cfg(debug_assertions)]
86 pub fn for_component<T: 'static>() -> Self {
87 let comp_name = std::any::type_name::<T>();
88 Self::Component(comp_name)
89 }
90
91 pub fn open_start_mark(&self) -> &'static str {
92 match self {
93 Self::Component(_) => "<[",
94 Self::Raw => "<#",
95 Self::Suspense => "<?",
96 }
97 }
98
99 pub fn close_start_mark(&self) -> &'static str {
100 match self {
101 Self::Component(_) => "</[",
102 Self::Raw => "</#",
103 Self::Suspense => "</?",
104 }
105 }
106
107 pub fn end_mark(&self) -> &'static str {
108 match self {
109 Self::Component(_) => "]>",
110 Self::Raw => ">",
111 Self::Suspense => ">",
112 }
113 }
114
115 #[cfg(feature = "hydration")]
116 pub fn name(&self) -> Cow<'static, str> {
117 match self {
118 #[cfg(debug_assertions)]
119 Self::Component(m) => format!("Component({m})").into(),
120 #[cfg(not(debug_assertions))]
121 Self::Component(_) => "Component".into(),
122 Self::Raw => "Raw".into(),
123 Self::Suspense => "Suspense".into(),
124 }
125 }
126 }
127}
128
129#[cfg(any(feature = "ssr", feature = "hydration"))]
130pub(crate) use feat_ssr_hydration::*;
131
132#[cfg(feature = "ssr")]
133mod feat_ssr {
134 use std::fmt::Write;
135
136 use super::*;
137 use crate::platform::fmt::BufWriter;
138
139 impl Collectable {
140 pub(crate) fn write_open_tag(&self, w: &mut BufWriter) {
141 let _ = w.write_str("<!--");
142 let _ = w.write_str(self.open_start_mark());
143
144 #[cfg(debug_assertions)]
145 match self {
146 Self::Component(type_name) => {
147 let _ = w.write_str(type_name);
148 }
149 Self::Raw => {}
150 Self::Suspense => {}
151 }
152
153 let _ = w.write_str(self.end_mark());
154 let _ = w.write_str("-->");
155 }
156
157 pub(crate) fn write_close_tag(&self, w: &mut BufWriter) {
158 let _ = w.write_str("<!--");
159 let _ = w.write_str(self.close_start_mark());
160
161 #[cfg(debug_assertions)]
162 match self {
163 Self::Component(type_name) => {
164 let _ = w.write_str(type_name);
165 }
166 Self::Raw => {}
167 Self::Suspense => {}
168 }
169
170 let _ = w.write_str(self.end_mark());
171 let _ = w.write_str("-->");
172 }
173 }
174}
175
176#[allow(missing_docs)]
178#[derive(PartialEq, Clone, Debug)]
179pub enum AttributeOrProperty {
180 Static(&'static str),
187 Attribute(AttrValue),
188 Property(JsValue),
189}
190
191#[derive(PartialEq, Clone, Debug)]
193pub enum Attributes {
194 Static(&'static [(&'static str, AttributeOrProperty)]),
199
200 Dynamic {
206 keys: &'static [&'static str],
208
209 values: Box<[Option<AttributeOrProperty>]>,
212 },
213
214 IndexMap(Rc<IndexMap<AttrValue, AttributeOrProperty>>),
217}
218
219impl Attributes {
220 pub fn new() -> Self {
222 Self::default()
223 }
224
225 pub fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = (&'a str, &'a str)> + 'a> {
230 match self {
231 Self::Static(arr) => Box::new(arr.iter().filter_map(|(k, v)| match v {
232 AttributeOrProperty::Attribute(v) => Some((*k, v.as_ref())),
233 AttributeOrProperty::Property(_) => None,
234 AttributeOrProperty::Static(v) => Some((*k, v)),
235 })),
236 Self::Dynamic { keys, values } => {
237 Box::new(keys.iter().zip(values.iter()).filter_map(|(k, v)| match v {
238 Some(AttributeOrProperty::Attribute(v)) => Some((*k, v.as_ref())),
239 _ => None,
240 }))
241 }
242 Self::IndexMap(m) => Box::new(m.iter().filter_map(|(k, v)| match v {
243 AttributeOrProperty::Attribute(v) => Some((k.as_ref(), v.as_ref())),
244 _ => None,
245 })),
246 }
247 }
248
249 pub fn get_mut_index_map(&mut self) -> &mut IndexMap<AttrValue, AttributeOrProperty> {
252 macro_rules! unpack {
253 () => {
254 match self {
255 Self::IndexMap(m) => Rc::make_mut(m),
256 _ => unsafe { unreachable_unchecked() },
258 }
259 };
260 }
261
262 match self {
263 Self::IndexMap(m) => Rc::make_mut(m),
264 Self::Static(arr) => {
265 *self = Self::IndexMap(Rc::new(
266 arr.iter().map(|(k, v)| ((*k).into(), v.clone())).collect(),
267 ));
268 unpack!()
269 }
270 Self::Dynamic { keys, values } => {
271 *self = Self::IndexMap(Rc::new(
272 std::mem::take(values)
273 .iter_mut()
274 .zip(keys.iter())
275 .filter_map(|(v, k)| v.take().map(|v| (AttrValue::from(*k), v)))
276 .collect(),
277 ));
278 unpack!()
279 }
280 }
281 }
282}
283
284impl From<IndexMap<AttrValue, AttrValue>> for Attributes {
285 fn from(map: IndexMap<AttrValue, AttrValue>) -> Self {
286 let v = map
287 .into_iter()
288 .map(|(k, v)| (k, AttributeOrProperty::Attribute(v)))
289 .collect();
290 Self::IndexMap(Rc::new(v))
291 }
292}
293
294impl From<IndexMap<&'static str, AttrValue>> for Attributes {
295 fn from(v: IndexMap<&'static str, AttrValue>) -> Self {
296 let v = v
297 .into_iter()
298 .map(|(k, v)| (AttrValue::Static(k), (AttributeOrProperty::Attribute(v))))
299 .collect();
300 Self::IndexMap(Rc::new(v))
301 }
302}
303
304impl From<IndexMap<&'static str, JsValue>> for Attributes {
305 fn from(v: IndexMap<&'static str, JsValue>) -> Self {
306 let v = v
307 .into_iter()
308 .map(|(k, v)| (AttrValue::Static(k), (AttributeOrProperty::Property(v))))
309 .collect();
310 Self::IndexMap(Rc::new(v))
311 }
312}
313
314impl Default for Attributes {
315 fn default() -> Self {
316 Self::Static(&[])
317 }
318}