1use crate::{
2 Element, Event, Properties, ScopeId, VirtualDom,
3 any_props::BoxedAnyProps,
4 arena::ElementId,
5 events::ListenerCallback,
6 innerlude::{ElementRef, MountId, ScopeState, VProps},
7 properties::ComponentFunction,
8};
9use dioxus_core_types::DioxusFormattable;
10use std::ops::Deref;
11use std::rc::Rc;
12use std::vec;
13use std::{
14 any::{Any, TypeId},
15 cell::Cell,
16 fmt::{Arguments, Debug},
17};
18
19#[derive(Debug)]
21pub(crate) struct VNodeMount {
22 pub parent: Option<ElementRef>,
24
25 pub node: VNode,
27
28 pub root_ids: Box<[ElementId]>,
31
32 pub(crate) mounted_attributes: Box<[ElementId]>,
34
35 pub(crate) mounted_dynamic_nodes: Box<[usize]>,
38}
39
40#[derive(Debug)]
45pub struct VNodeInner {
46 pub key: Option<String>,
50
51 pub template: Template,
53
54 pub dynamic_nodes: Box<[DynamicNode]>,
56
57 pub dynamic_attrs: Box<[Box<[Attribute]>]>,
89}
90
91#[derive(Debug, Clone)]
96pub struct VNode {
97 vnode: Rc<VNodeInner>,
98
99 pub(crate) mount: Cell<MountId>,
101}
102
103impl Default for VNode {
104 fn default() -> Self {
105 Self::placeholder()
106 }
107}
108
109impl PartialEq for VNode {
110 fn eq(&self, other: &Self) -> bool {
111 Rc::ptr_eq(&self.vnode, &other.vnode)
112 }
113}
114
115impl Deref for VNode {
116 type Target = VNodeInner;
117
118 fn deref(&self) -> &Self::Target {
119 &self.vnode
120 }
121}
122
123impl VNode {
124 pub fn empty() -> Element {
126 Ok(Self::default())
127 }
128
129 pub fn placeholder() -> Self {
131 use std::cell::OnceCell;
132 thread_local! {
134 static PLACEHOLDER_VNODE: OnceCell<Rc<VNodeInner>> = const { OnceCell::new() };
135 }
136 let vnode = PLACEHOLDER_VNODE.with(|cell| {
137 cell.get_or_init(move || {
138 Rc::new(VNodeInner {
139 key: None,
140 dynamic_nodes: Box::new([DynamicNode::Placeholder(Default::default())]),
141 dynamic_attrs: Box::new([]),
142 template: Template::new(&[TemplateNode::Dynamic { id: 0 }], &[&[0]], &[]),
143 })
144 })
145 .clone()
146 });
147 Self {
148 vnode,
149 mount: Default::default(),
150 }
151 }
152
153 pub fn new(
155 key: Option<String>,
156 template: Template,
157 dynamic_nodes: Box<[DynamicNode]>,
158 dynamic_attrs: Box<[Box<[Attribute]>]>,
159 ) -> Self {
160 Self {
161 vnode: Rc::new(VNodeInner {
162 key,
163 template,
164 dynamic_nodes,
165 dynamic_attrs,
166 }),
167 mount: Default::default(),
168 }
169 }
170
171 pub fn dynamic_root(&self, idx: usize) -> Option<&DynamicNode> {
175 self.template.roots()[idx]
176 .dynamic_id()
177 .map(|id| &self.dynamic_nodes[id])
178 }
179
180 pub fn mounted_dynamic_node(
182 &self,
183 dynamic_node_idx: usize,
184 dom: &VirtualDom,
185 ) -> Option<ElementId> {
186 let mount = self.mount.get().as_usize()?;
187
188 match &self.dynamic_nodes[dynamic_node_idx] {
189 DynamicNode::Text(_) | DynamicNode::Placeholder(_) => {
190 let mounts = dom.runtime.mounts.borrow();
191 mounts
192 .get(mount)?
193 .mounted_dynamic_nodes
194 .get(dynamic_node_idx)
195 .map(|id| ElementId(*id))
196 }
197 _ => None,
198 }
199 }
200
201 pub fn mounted_root(&self, root_idx: usize, dom: &VirtualDom) -> Option<ElementId> {
203 let mount = self.mount.get().as_usize()?;
204
205 let mounts = dom.runtime.mounts.borrow();
206 mounts.get(mount)?.root_ids.get(root_idx).copied()
207 }
208
209 pub fn mounted_dynamic_attribute(
211 &self,
212 dynamic_attribute_idx: usize,
213 dom: &VirtualDom,
214 ) -> Option<ElementId> {
215 let mount = self.mount.get().as_usize()?;
216
217 let mounts = dom.runtime.mounts.borrow();
218 mounts
219 .get(mount)?
220 .mounted_attributes
221 .get(dynamic_attribute_idx)
222 .copied()
223 }
224
225 pub(crate) fn deep_clone(&self) -> Self {
227 Self {
228 vnode: Rc::new(VNodeInner {
229 key: self.vnode.key.clone(),
230 template: self.vnode.template,
231 dynamic_nodes: self
232 .vnode
233 .dynamic_nodes
234 .iter()
235 .map(|node| match node {
236 DynamicNode::Fragment(nodes) => DynamicNode::Fragment(
237 nodes.iter().map(|node| node.deep_clone()).collect(),
238 ),
239 other => other.clone(),
240 })
241 .collect(),
242 dynamic_attrs: self
243 .vnode
244 .dynamic_attrs
245 .iter()
246 .map(|attr| {
247 attr.iter()
248 .map(|attribute| attribute.deep_clone())
249 .collect()
250 })
251 .collect(),
252 }),
253 mount: Default::default(),
254 }
255 }
256}
257
258type StaticStr = &'static str;
259type StaticPathArray = &'static [&'static [u8]];
260type StaticTemplateArray = &'static [TemplateNode];
261type StaticTemplateAttributeArray = &'static [TemplateAttribute];
262
263#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
269#[derive(Debug, Clone, Copy, Eq, PartialOrd, Ord)]
270pub struct Template {
271 #[cfg_attr(feature = "serialize", serde(deserialize_with = "deserialize_leaky"))]
275 roots: StaticTemplateArray,
276
277 #[cfg_attr(
282 feature = "serialize",
283 serde(deserialize_with = "deserialize_bytes_leaky")
284 )]
285 node_paths: StaticPathArray,
286
287 #[cfg_attr(
292 feature = "serialize",
293 serde(deserialize_with = "deserialize_bytes_leaky", bound = "")
294 )]
295 attr_paths: StaticPathArray,
296
297 hash: u64,
310}
311
312impl Template {
313 pub const fn new(
316 roots: &'static [TemplateNode],
317 node_paths: &'static [&'static [u8]],
318 attr_paths: &'static [&'static [u8]],
319 ) -> Self {
320 Self {
321 roots,
322 node_paths,
323 attr_paths,
324 hash: Self::compute_hash(roots, node_paths, attr_paths),
325 }
326 }
327
328 pub const fn roots(&self) -> &'static [TemplateNode] {
330 self.roots
331 }
332
333 pub const fn node_paths(&self) -> &'static [&'static [u8]] {
335 self.node_paths
336 }
337
338 pub const fn attr_paths(&self) -> &'static [&'static [u8]] {
340 self.attr_paths
341 }
342
343 const fn compute_hash(
346 roots: &[TemplateNode],
347 node_paths: &[&[u8]],
348 attr_paths: &[&[u8]],
349 ) -> u64 {
350 use xxhash_rust::const_xxh64::xxh64;
351
352 const fn hash_template_node(node: &TemplateNode, seed: u64) -> u64 {
353 match node {
354 TemplateNode::Element {
355 tag,
356 namespace,
357 attrs,
358 children,
359 } => {
360 let mut h = xxh64(tag.as_bytes(), seed);
361 if let Some(ns) = *namespace {
362 h = xxh64(ns.as_bytes(), h);
363 }
364
365 let mut i = 0;
367 while i < attrs.len() {
368 h = match &attrs[i] {
369 TemplateAttribute::Static {
370 name,
371 value,
372 namespace,
373 } => {
374 let mut new_h = xxh64(name.as_bytes(), h);
375 new_h = xxh64(value.as_bytes(), new_h);
376 if let Some(ns) = *namespace {
377 new_h = xxh64(ns.as_bytes(), new_h);
378 }
379 new_h
380 }
381 TemplateAttribute::Dynamic { id } => {
382 xxh64(&(*id as u64).to_le_bytes(), xxh64(&[0xFE], h))
383 }
384 };
385 i += 1;
386 }
387
388 let mut i = 0;
390 while i < children.len() {
391 h = hash_template_node(&children[i], h);
392 i += 1;
393 }
394
395 h
396 }
397 TemplateNode::Text { text } => xxh64(text.as_bytes(), seed),
398 TemplateNode::Dynamic { id } => {
399 xxh64(&(*id as u64).to_le_bytes(), xxh64(&[0xFF], seed))
400 }
401 }
402 }
403
404 let mut hash = 0u64;
405
406 let mut i = 0;
408 while i < roots.len() {
409 hash = hash_template_node(&roots[i], hash);
410 i += 1;
411 }
412
413 hash = xxh64(&[0xA1], hash);
415 let mut i = 0;
416 while i < node_paths.len() {
417 hash = xxh64(node_paths[i], hash);
418 i += 1;
419 }
420
421 hash = xxh64(&[0xA2], hash);
423 let mut i = 0;
424 while i < attr_paths.len() {
425 hash = xxh64(attr_paths[i], hash);
426 i += 1;
427 }
428
429 hash
430 }
431}
432
433impl std::hash::Hash for Template {
434 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
435 self.hash.hash(state);
436 }
437}
438
439impl PartialEq for Template {
440 fn eq(&self, other: &Self) -> bool {
441 self.hash == other.hash
442 }
443}
444
445#[cfg(feature = "serialize")]
446pub(crate) fn deserialize_string_leaky<'a, 'de, D>(
447 deserializer: D,
448) -> Result<&'static str, D::Error>
449where
450 D: serde::Deserializer<'de>,
451{
452 use serde::Deserialize;
453
454 let deserialized = String::deserialize(deserializer)?;
455 Ok(&*Box::leak(deserialized.into_boxed_str()))
456}
457
458#[cfg(feature = "serialize")]
459fn deserialize_bytes_leaky<'a, 'de, D>(
460 deserializer: D,
461) -> Result<&'static [&'static [u8]], D::Error>
462where
463 D: serde::Deserializer<'de>,
464{
465 use serde::Deserialize;
466
467 let deserialized = Vec::<Vec<u8>>::deserialize(deserializer)?;
468 let deserialized = deserialized
469 .into_iter()
470 .map(|v| &*Box::leak(v.into_boxed_slice()))
471 .collect::<Vec<_>>();
472 Ok(&*Box::leak(deserialized.into_boxed_slice()))
473}
474
475#[cfg(feature = "serialize")]
476pub(crate) fn deserialize_leaky<'a, 'de, T, D>(deserializer: D) -> Result<&'static [T], D::Error>
477where
478 T: serde::Deserialize<'de>,
479 D: serde::Deserializer<'de>,
480{
481 use serde::Deserialize;
482
483 let deserialized = Box::<[T]>::deserialize(deserializer)?;
484 Ok(&*Box::leak(deserialized))
485}
486
487#[cfg(feature = "serialize")]
488pub(crate) fn deserialize_option_leaky<'a, 'de, D>(
489 deserializer: D,
490) -> Result<Option<&'static str>, D::Error>
491where
492 D: serde::Deserializer<'de>,
493{
494 use serde::Deserialize;
495
496 let deserialized = Option::<String>::deserialize(deserializer)?;
497 Ok(deserialized.map(|deserialized| &*Box::leak(deserialized.into_boxed_str())))
498}
499
500impl Template {
501 pub fn is_completely_dynamic(&self) -> bool {
505 use TemplateNode::*;
506 self.roots.iter().all(|root| matches!(root, Dynamic { .. }))
507 }
508}
509
510#[derive(Debug, Clone, Copy, PartialEq, Hash, Eq, PartialOrd, Ord)]
514#[cfg_attr(
515 feature = "serialize",
516 derive(serde::Serialize, serde::Deserialize),
517 serde(tag = "type")
518)]
519pub enum TemplateNode {
520 Element {
524 #[cfg_attr(
528 feature = "serialize",
529 serde(deserialize_with = "deserialize_string_leaky")
530 )]
531 tag: StaticStr,
532
533 #[cfg_attr(
538 feature = "serialize",
539 serde(deserialize_with = "deserialize_option_leaky")
540 )]
541 namespace: Option<StaticStr>,
542
543 #[cfg_attr(
547 feature = "serialize",
548 serde(deserialize_with = "deserialize_leaky", bound = "")
549 )]
550 attrs: StaticTemplateAttributeArray,
551
552 #[cfg_attr(feature = "serialize", serde(deserialize_with = "deserialize_leaky"))]
554 children: StaticTemplateArray,
555 },
556
557 Text {
559 #[cfg_attr(
561 feature = "serialize",
562 serde(deserialize_with = "deserialize_string_leaky", bound = "")
563 )]
564 text: StaticStr,
565 },
566
567 Dynamic {
569 id: usize,
571 },
572}
573
574impl TemplateNode {
575 pub fn dynamic_id(&self) -> Option<usize> {
577 use TemplateNode::*;
578 match self {
579 Dynamic { id } => Some(*id),
580 _ => None,
581 }
582 }
583}
584
585#[derive(Debug, Clone)]
589pub enum DynamicNode {
590 Component(VComponent),
598
599 Text(VText),
601
602 Placeholder(VPlaceholder),
608
609 Fragment(Vec<VNode>),
614}
615
616impl DynamicNode {
617 pub fn make_node<'c, I>(into: impl IntoDynNode<I> + 'c) -> DynamicNode {
619 into.into_dyn_node()
620 }
621}
622
623impl Default for DynamicNode {
624 fn default() -> Self {
625 Self::Placeholder(Default::default())
626 }
627}
628
629pub struct VComponent {
631 pub name: &'static str,
633
634 pub(crate) render_fn: usize,
636
637 pub(crate) props: BoxedAnyProps,
639}
640
641impl Clone for VComponent {
642 fn clone(&self) -> Self {
643 Self {
644 name: self.name,
645 props: self.props.duplicate(),
646 render_fn: self.render_fn,
647 }
648 }
649}
650
651impl VComponent {
652 pub fn new<P, M: 'static>(
654 component: impl ComponentFunction<P, M>,
655 props: P,
656 fn_name: &'static str,
657 ) -> Self
658 where
659 P: Properties + 'static,
660 {
661 let render_fn = component.fn_ptr();
662 let props = Box::new(VProps::new(
663 component,
664 <P as Properties>::memoize,
665 props,
666 fn_name,
667 ));
668
669 VComponent {
670 render_fn,
671 name: fn_name,
672 props,
673 }
674 }
675
676 pub fn mounted_scope_id(
682 &self,
683 dynamic_node_index: usize,
684 vnode: &VNode,
685 dom: &VirtualDom,
686 ) -> Option<ScopeId> {
687 let mount = vnode.mount.get().as_usize()?;
688
689 let mounts = dom.runtime.mounts.borrow();
690 let scope_id = mounts.get(mount)?.mounted_dynamic_nodes[dynamic_node_index];
691
692 Some(ScopeId(scope_id))
693 }
694
695 pub fn mounted_scope<'a>(
701 &self,
702 dynamic_node_index: usize,
703 vnode: &VNode,
704 dom: &'a VirtualDom,
705 ) -> Option<&'a ScopeState> {
706 let mount = vnode.mount.get().as_usize()?;
707
708 let mounts = dom.runtime.mounts.borrow();
709 let scope_id = mounts.get(mount)?.mounted_dynamic_nodes[dynamic_node_index];
710
711 dom.scopes.get(scope_id)
712 }
713}
714
715impl std::fmt::Debug for VComponent {
716 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
717 f.debug_struct("VComponent")
718 .field("name", &self.name)
719 .finish()
720 }
721}
722
723#[derive(Clone, Debug)]
725pub struct VText {
726 pub value: String,
728}
729
730impl VText {
731 pub fn new(value: impl ToString) -> Self {
733 Self {
734 value: value.to_string(),
735 }
736 }
737}
738
739impl From<Arguments<'_>> for VText {
740 fn from(args: Arguments) -> Self {
741 Self::new(args.to_string())
742 }
743}
744
745#[derive(Clone, Debug, Default)]
747#[non_exhaustive]
748pub struct VPlaceholder {}
749
750#[derive(Debug, PartialEq, Hash, Eq, PartialOrd, Ord)]
752#[cfg_attr(
753 feature = "serialize",
754 derive(serde::Serialize, serde::Deserialize),
755 serde(tag = "type")
756)]
757pub enum TemplateAttribute {
758 Static {
760 #[cfg_attr(
764 feature = "serialize",
765 serde(deserialize_with = "deserialize_string_leaky", bound = "")
766 )]
767 name: StaticStr,
768
769 #[cfg_attr(
773 feature = "serialize",
774 serde(deserialize_with = "deserialize_string_leaky", bound = "")
775 )]
776 value: StaticStr,
777
778 #[cfg_attr(
780 feature = "serialize",
781 serde(deserialize_with = "deserialize_option_leaky", bound = "")
782 )]
783 namespace: Option<StaticStr>,
784 },
785
786 Dynamic {
790 id: usize,
792 },
793}
794
795#[derive(Debug, Clone, PartialEq)]
797pub struct Attribute {
798 pub name: &'static str,
800
801 pub value: AttributeValue,
803
804 pub namespace: Option<&'static str>,
808
809 pub volatile: bool,
811}
812
813impl Attribute {
814 pub fn new<T>(
819 name: &'static str,
820 value: impl IntoAttributeValue<T>,
821 namespace: Option<&'static str>,
822 volatile: bool,
823 ) -> Attribute {
824 Attribute {
825 name,
826 namespace,
827 volatile,
828 value: value.into_value(),
829 }
830 }
831
832 pub(crate) fn deep_clone(&self) -> Self {
834 Attribute {
835 name: self.name,
836 namespace: self.namespace,
837 volatile: self.volatile,
838 value: self.value.clone(),
839 }
840 }
841}
842
843#[derive(Clone)]
848pub enum AttributeValue {
849 Text(String),
851
852 Float(f64),
854
855 Int(i64),
857
858 Bool(bool),
860
861 Listener(ListenerCallback),
863
864 Any(Rc<dyn AnyValue>),
866
867 None,
869}
870
871impl AttributeValue {
872 pub fn listener<T: 'static>(callback: impl FnMut(Event<T>) + 'static) -> AttributeValue {
876 AttributeValue::Listener(ListenerCallback::new(callback).erase())
877 }
878
879 pub fn any_value<T: AnyValue>(value: T) -> AttributeValue {
881 AttributeValue::Any(Rc::new(value))
882 }
883}
884
885impl std::fmt::Debug for AttributeValue {
886 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
887 match self {
888 Self::Text(arg0) => f.debug_tuple("Text").field(arg0).finish(),
889 Self::Float(arg0) => f.debug_tuple("Float").field(arg0).finish(),
890 Self::Int(arg0) => f.debug_tuple("Int").field(arg0).finish(),
891 Self::Bool(arg0) => f.debug_tuple("Bool").field(arg0).finish(),
892 Self::Listener(_) => f.debug_tuple("Listener").finish(),
893 Self::Any(_) => f.debug_tuple("Any").finish(),
894 Self::None => write!(f, "None"),
895 }
896 }
897}
898
899impl PartialEq for AttributeValue {
900 fn eq(&self, other: &Self) -> bool {
901 match (self, other) {
902 (Self::Text(l0), Self::Text(r0)) => l0 == r0,
903 (Self::Float(l0), Self::Float(r0)) => l0 == r0,
904 (Self::Int(l0), Self::Int(r0)) => l0 == r0,
905 (Self::Bool(l0), Self::Bool(r0)) => l0 == r0,
906 (Self::Listener(l0), Self::Listener(r0)) => l0 == r0,
907 (Self::Any(l0), Self::Any(r0)) => l0.as_ref().any_cmp(r0.as_ref()),
908 (Self::None, Self::None) => true,
909 _ => false,
910 }
911 }
912}
913
914#[doc(hidden)]
915pub trait AnyValue: 'static {
916 fn any_cmp(&self, other: &dyn AnyValue) -> bool;
917 fn as_any(&self) -> &dyn Any;
918 fn type_id(&self) -> TypeId {
919 self.as_any().type_id()
920 }
921}
922
923impl<T: Any + PartialEq + 'static> AnyValue for T {
924 fn any_cmp(&self, other: &dyn AnyValue) -> bool {
925 if let Some(other) = other.as_any().downcast_ref() {
926 self == other
927 } else {
928 false
929 }
930 }
931
932 fn as_any(&self) -> &dyn Any {
933 self
934 }
935}
936
937pub trait IntoDynNode<A = ()> {
939 fn into_dyn_node(self) -> DynamicNode;
941}
942
943impl IntoDynNode for () {
944 fn into_dyn_node(self) -> DynamicNode {
945 DynamicNode::default()
946 }
947}
948impl IntoDynNode for VNode {
949 fn into_dyn_node(self) -> DynamicNode {
950 DynamicNode::Fragment(vec![self])
951 }
952}
953impl IntoDynNode for DynamicNode {
954 fn into_dyn_node(self) -> DynamicNode {
955 self
956 }
957}
958impl<T: IntoDynNode> IntoDynNode for Option<T> {
959 fn into_dyn_node(self) -> DynamicNode {
960 match self {
961 Some(val) => val.into_dyn_node(),
962 None => DynamicNode::default(),
963 }
964 }
965}
966impl IntoDynNode for &Element {
967 fn into_dyn_node(self) -> DynamicNode {
968 match self.as_ref() {
969 Ok(val) => val.into_dyn_node(),
970 _ => DynamicNode::default(),
971 }
972 }
973}
974impl IntoDynNode for Element {
975 fn into_dyn_node(self) -> DynamicNode {
976 match self {
977 Ok(val) => val.into_dyn_node(),
978 _ => DynamicNode::default(),
979 }
980 }
981}
982impl IntoDynNode for &Option<VNode> {
983 fn into_dyn_node(self) -> DynamicNode {
984 match self.as_ref() {
985 Some(val) => val.clone().into_dyn_node(),
986 _ => DynamicNode::default(),
987 }
988 }
989}
990impl IntoDynNode for &str {
991 fn into_dyn_node(self) -> DynamicNode {
992 DynamicNode::Text(VText {
993 value: self.to_string(),
994 })
995 }
996}
997impl IntoDynNode for String {
998 fn into_dyn_node(self) -> DynamicNode {
999 DynamicNode::Text(VText { value: self })
1000 }
1001}
1002impl IntoDynNode for Arguments<'_> {
1003 fn into_dyn_node(self) -> DynamicNode {
1004 DynamicNode::Text(VText {
1005 value: self.to_string(),
1006 })
1007 }
1008}
1009impl IntoDynNode for &VNode {
1010 fn into_dyn_node(self) -> DynamicNode {
1011 DynamicNode::Fragment(vec![self.clone()])
1012 }
1013}
1014
1015pub trait IntoVNode {
1016 fn into_vnode(self) -> VNode;
1017}
1018impl IntoVNode for VNode {
1019 fn into_vnode(self) -> VNode {
1020 self
1021 }
1022}
1023impl IntoVNode for &VNode {
1024 fn into_vnode(self) -> VNode {
1025 self.clone()
1026 }
1027}
1028impl IntoVNode for Element {
1029 fn into_vnode(self) -> VNode {
1030 match self {
1031 Ok(val) => val.into_vnode(),
1032 _ => VNode::default(),
1033 }
1034 }
1035}
1036impl IntoVNode for &Element {
1037 fn into_vnode(self) -> VNode {
1038 match self {
1039 Ok(val) => val.into_vnode(),
1040 _ => VNode::default(),
1041 }
1042 }
1043}
1044impl IntoVNode for Option<VNode> {
1045 fn into_vnode(self) -> VNode {
1046 match self {
1047 Some(val) => val.into_vnode(),
1048 _ => VNode::default(),
1049 }
1050 }
1051}
1052impl IntoVNode for &Option<VNode> {
1053 fn into_vnode(self) -> VNode {
1054 match self.as_ref() {
1055 Some(val) => val.clone().into_vnode(),
1056 _ => VNode::default(),
1057 }
1058 }
1059}
1060impl IntoVNode for Option<Element> {
1061 fn into_vnode(self) -> VNode {
1062 match self {
1063 Some(val) => val.into_vnode(),
1064 _ => VNode::default(),
1065 }
1066 }
1067}
1068impl IntoVNode for &Option<Element> {
1069 fn into_vnode(self) -> VNode {
1070 match self.as_ref() {
1071 Some(val) => val.clone().into_vnode(),
1072 _ => VNode::default(),
1073 }
1074 }
1075}
1076
1077pub struct FromNodeIterator;
1079impl<T, I> IntoDynNode<FromNodeIterator> for T
1080where
1081 T: Iterator<Item = I>,
1082 I: IntoVNode,
1083{
1084 fn into_dyn_node(self) -> DynamicNode {
1085 let children: Vec<_> = self.into_iter().map(|node| node.into_vnode()).collect();
1086
1087 if children.is_empty() {
1088 DynamicNode::default()
1089 } else {
1090 DynamicNode::Fragment(children)
1091 }
1092 }
1093}
1094
1095pub trait IntoAttributeValue<T = ()> {
1097 fn into_value(self) -> AttributeValue;
1099}
1100
1101impl IntoAttributeValue for AttributeValue {
1102 fn into_value(self) -> AttributeValue {
1103 self
1104 }
1105}
1106
1107impl IntoAttributeValue for &str {
1108 fn into_value(self) -> AttributeValue {
1109 AttributeValue::Text(self.to_string())
1110 }
1111}
1112
1113impl IntoAttributeValue for String {
1114 fn into_value(self) -> AttributeValue {
1115 AttributeValue::Text(self)
1116 }
1117}
1118
1119impl IntoAttributeValue for f32 {
1120 fn into_value(self) -> AttributeValue {
1121 AttributeValue::Float(self as _)
1122 }
1123}
1124impl IntoAttributeValue for f64 {
1125 fn into_value(self) -> AttributeValue {
1126 AttributeValue::Float(self)
1127 }
1128}
1129
1130impl IntoAttributeValue for i8 {
1131 fn into_value(self) -> AttributeValue {
1132 AttributeValue::Int(self as _)
1133 }
1134}
1135impl IntoAttributeValue for i16 {
1136 fn into_value(self) -> AttributeValue {
1137 AttributeValue::Int(self as _)
1138 }
1139}
1140impl IntoAttributeValue for i32 {
1141 fn into_value(self) -> AttributeValue {
1142 AttributeValue::Int(self as _)
1143 }
1144}
1145impl IntoAttributeValue for i64 {
1146 fn into_value(self) -> AttributeValue {
1147 AttributeValue::Int(self)
1148 }
1149}
1150impl IntoAttributeValue for isize {
1151 fn into_value(self) -> AttributeValue {
1152 AttributeValue::Int(self as _)
1153 }
1154}
1155impl IntoAttributeValue for i128 {
1156 fn into_value(self) -> AttributeValue {
1157 AttributeValue::Int(self as _)
1158 }
1159}
1160
1161impl IntoAttributeValue for u8 {
1162 fn into_value(self) -> AttributeValue {
1163 AttributeValue::Int(self as _)
1164 }
1165}
1166impl IntoAttributeValue for u16 {
1167 fn into_value(self) -> AttributeValue {
1168 AttributeValue::Int(self as _)
1169 }
1170}
1171impl IntoAttributeValue for u32 {
1172 fn into_value(self) -> AttributeValue {
1173 AttributeValue::Int(self as _)
1174 }
1175}
1176impl IntoAttributeValue for u64 {
1177 fn into_value(self) -> AttributeValue {
1178 AttributeValue::Int(self as _)
1179 }
1180}
1181impl IntoAttributeValue for usize {
1182 fn into_value(self) -> AttributeValue {
1183 AttributeValue::Int(self as _)
1184 }
1185}
1186impl IntoAttributeValue for u128 {
1187 fn into_value(self) -> AttributeValue {
1188 AttributeValue::Int(self as _)
1189 }
1190}
1191
1192impl IntoAttributeValue for bool {
1193 fn into_value(self) -> AttributeValue {
1194 AttributeValue::Bool(self)
1195 }
1196}
1197
1198impl IntoAttributeValue for Arguments<'_> {
1199 fn into_value(self) -> AttributeValue {
1200 AttributeValue::Text(self.to_string())
1201 }
1202}
1203
1204impl IntoAttributeValue for Rc<dyn AnyValue> {
1205 fn into_value(self) -> AttributeValue {
1206 AttributeValue::Any(self)
1207 }
1208}
1209
1210impl<T> IntoAttributeValue for ListenerCallback<T> {
1211 fn into_value(self) -> AttributeValue {
1212 AttributeValue::Listener(self.erase())
1213 }
1214}
1215
1216impl<T: IntoAttributeValue> IntoAttributeValue for Option<T> {
1217 fn into_value(self) -> AttributeValue {
1218 match self {
1219 Some(val) => val.into_value(),
1220 None => AttributeValue::None,
1221 }
1222 }
1223}
1224
1225impl<T: ToOwned<Owned = R>, R: IntoAttributeValue> IntoAttributeValue for &T {
1226 fn into_value(self) -> AttributeValue {
1227 self.to_owned().into_value()
1228 }
1229}
1230
1231pub struct AnyFmtMarker;
1232impl<T> IntoAttributeValue<AnyFmtMarker> for T
1233where
1234 T: DioxusFormattable,
1235{
1236 fn into_value(self) -> AttributeValue {
1237 AttributeValue::Text(self.format().to_string())
1238 }
1239}
1240
1241pub trait HasAttributes {
1243 fn push_attribute<T>(
1245 self,
1246 name: &'static str,
1247 ns: Option<&'static str>,
1248 attr: impl IntoAttributeValue<T>,
1249 volatile: bool,
1250 ) -> Self;
1251}