1use dioxus_core_types::DioxusFormattable;
2
3use crate::innerlude::VProps;
4use crate::prelude::RenderError;
5use crate::{any_props::BoxedAnyProps, innerlude::ScopeState};
6use crate::{arena::ElementId, Element, Event};
7use crate::{
8 innerlude::{ElementRef, EventHandler, MountId},
9 properties::ComponentFunction,
10};
11use crate::{Properties, ScopeId, VirtualDom};
12use std::ops::Deref;
13use std::rc::Rc;
14use std::vec;
15use std::{
16 any::{Any, TypeId},
17 cell::Cell,
18 fmt::{Arguments, Debug},
19};
20
21#[derive(Debug)]
23pub(crate) struct VNodeMount {
24 pub parent: Option<ElementRef>,
26
27 pub node: VNode,
29
30 pub root_ids: Box<[ElementId]>,
33
34 pub(crate) mounted_attributes: Box<[ElementId]>,
36
37 pub(crate) mounted_dynamic_nodes: Box<[usize]>,
40}
41
42#[derive(Debug)]
47pub struct VNodeInner {
48 pub key: Option<String>,
52
53 pub template: Template,
55
56 pub dynamic_nodes: Box<[DynamicNode]>,
58
59 pub dynamic_attrs: Box<[Box<[Attribute]>]>,
91}
92
93#[derive(Debug, Clone)]
98pub struct VNode {
99 vnode: Rc<VNodeInner>,
100
101 pub(crate) mount: Cell<MountId>,
103}
104
105impl AsRef<VNode> for Element {
106 fn as_ref(&self) -> &VNode {
107 match self {
108 Element::Ok(node) => node,
109 Element::Err(RenderError::Aborted(err)) => &err.render,
110 Element::Err(RenderError::Suspended(fut)) => &fut.placeholder,
111 }
112 }
113}
114
115impl From<&Element> for VNode {
116 fn from(val: &Element) -> Self {
117 AsRef::as_ref(val).clone()
118 }
119}
120
121impl From<Element> for VNode {
122 fn from(val: Element) -> Self {
123 match val {
124 Element::Ok(node) => node,
125 Element::Err(RenderError::Aborted(err)) => err.render,
126 Element::Err(RenderError::Suspended(fut)) => fut.placeholder,
127 }
128 }
129}
130
131pub(crate) trait AsVNode {
133 fn as_vnode(&self) -> &VNode;
135
136 fn deep_clone(&self) -> Self;
138}
139
140impl AsVNode for Element {
141 fn as_vnode(&self) -> &VNode {
142 AsRef::as_ref(self)
143 }
144
145 fn deep_clone(&self) -> Self {
146 match self {
147 Ok(node) => Ok(node.deep_clone()),
148 Err(RenderError::Aborted(err)) => Err(RenderError::Aborted(err.deep_clone())),
149 Err(RenderError::Suspended(fut)) => Err(RenderError::Suspended(fut.deep_clone())),
150 }
151 }
152}
153
154impl Default for VNode {
155 fn default() -> Self {
156 Self::placeholder()
157 }
158}
159
160impl Drop for VNode {
161 fn drop(&mut self) {
162 if Rc::strong_count(&self.vnode) == 1 {
172 for attrs in self.vnode.dynamic_attrs.iter() {
173 for attr in attrs.iter() {
174 if let AttributeValue::Listener(listener) = &attr.value {
175 listener.callback.manually_drop();
176 }
177 }
178 }
179 }
180 }
181}
182
183impl PartialEq for VNode {
184 fn eq(&self, other: &Self) -> bool {
185 Rc::ptr_eq(&self.vnode, &other.vnode)
186 }
187}
188
189impl Deref for VNode {
190 type Target = VNodeInner;
191
192 fn deref(&self) -> &Self::Target {
193 &self.vnode
194 }
195}
196
197impl VNode {
198 pub fn empty() -> Element {
200 Ok(Self::default())
201 }
202
203 pub fn placeholder() -> Self {
205 use std::cell::OnceCell;
206 thread_local! {
208 static PLACEHOLDER_VNODE: OnceCell<Rc<VNodeInner>> = const { OnceCell::new() };
209 }
210 let vnode = PLACEHOLDER_VNODE.with(|cell| {
211 cell.get_or_init(move || {
212 Rc::new(VNodeInner {
213 key: None,
214 dynamic_nodes: Box::new([DynamicNode::Placeholder(Default::default())]),
215 dynamic_attrs: Box::new([]),
216 template: Template {
217 roots: &[TemplateNode::Dynamic { id: 0 }],
218 node_paths: &[&[0]],
219 attr_paths: &[],
220 },
221 })
222 })
223 .clone()
224 });
225 Self {
226 vnode,
227 mount: Default::default(),
228 }
229 }
230
231 pub fn new(
233 key: Option<String>,
234 template: Template,
235 dynamic_nodes: Box<[DynamicNode]>,
236 dynamic_attrs: Box<[Box<[Attribute]>]>,
237 ) -> Self {
238 Self {
239 vnode: Rc::new(VNodeInner {
240 key,
241 template,
242 dynamic_nodes,
243 dynamic_attrs,
244 }),
245 mount: Default::default(),
246 }
247 }
248
249 pub fn dynamic_root(&self, idx: usize) -> Option<&DynamicNode> {
253 self.template.roots[idx]
254 .dynamic_id()
255 .map(|id| &self.dynamic_nodes[id])
256 }
257
258 pub fn mounted_dynamic_node(
260 &self,
261 dynamic_node_idx: usize,
262 dom: &VirtualDom,
263 ) -> Option<ElementId> {
264 let mount = self.mount.get().as_usize()?;
265
266 match &self.dynamic_nodes[dynamic_node_idx] {
267 DynamicNode::Text(_) | DynamicNode::Placeholder(_) => {
268 let mounts = dom.runtime.mounts.borrow();
269 mounts
270 .get(mount)?
271 .mounted_dynamic_nodes
272 .get(dynamic_node_idx)
273 .map(|id| ElementId(*id))
274 }
275 _ => None,
276 }
277 }
278
279 pub fn mounted_root(&self, root_idx: usize, dom: &VirtualDom) -> Option<ElementId> {
281 let mount = self.mount.get().as_usize()?;
282
283 let mounts = dom.runtime.mounts.borrow();
284 mounts.get(mount)?.root_ids.get(root_idx).copied()
285 }
286
287 pub fn mounted_dynamic_attribute(
289 &self,
290 dynamic_attribute_idx: usize,
291 dom: &VirtualDom,
292 ) -> Option<ElementId> {
293 let mount = self.mount.get().as_usize()?;
294
295 let mounts = dom.runtime.mounts.borrow();
296 mounts
297 .get(mount)?
298 .mounted_attributes
299 .get(dynamic_attribute_idx)
300 .copied()
301 }
302
303 pub(crate) fn deep_clone(&self) -> Self {
305 Self {
306 vnode: Rc::new(VNodeInner {
307 key: self.vnode.key.clone(),
308 template: self.vnode.template,
309 dynamic_nodes: self
310 .vnode
311 .dynamic_nodes
312 .iter()
313 .map(|node| match node {
314 DynamicNode::Fragment(nodes) => DynamicNode::Fragment(
315 nodes.iter().map(|node| node.deep_clone()).collect(),
316 ),
317 other => other.clone(),
318 })
319 .collect(),
320 dynamic_attrs: self
321 .vnode
322 .dynamic_attrs
323 .iter()
324 .map(|attr| {
325 attr.iter()
326 .map(|attribute| attribute.deep_clone())
327 .collect()
328 })
329 .collect(),
330 }),
331 mount: Default::default(),
332 }
333 }
334}
335
336type StaticStr = &'static str;
337type StaticPathArray = &'static [&'static [u8]];
338type StaticTemplateArray = &'static [TemplateNode];
339type StaticTemplateAttributeArray = &'static [TemplateAttribute];
340
341#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
347#[derive(Debug, Clone, Copy, Eq, PartialOrd, Ord)]
348pub struct Template {
349 #[cfg_attr(feature = "serialize", serde(deserialize_with = "deserialize_leaky"))]
353 pub roots: StaticTemplateArray,
354
355 #[cfg_attr(
360 feature = "serialize",
361 serde(deserialize_with = "deserialize_bytes_leaky")
362 )]
363 pub node_paths: StaticPathArray,
364
365 #[cfg_attr(
370 feature = "serialize",
371 serde(deserialize_with = "deserialize_bytes_leaky", bound = "")
372 )]
373 pub attr_paths: StaticPathArray,
374}
375
376#[allow(unpredictable_function_pointer_comparisons)] fn static_items_merged() -> bool {
380 fn a() {}
381 fn b() {}
382 a as fn() == b as fn()
383 }
385
386impl std::hash::Hash for Template {
387 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
388 if static_items_merged() {
390 std::ptr::hash(self.roots as *const _, state);
391 std::ptr::hash(self.node_paths as *const _, state);
392 std::ptr::hash(self.attr_paths as *const _, state);
393 }
394 else {
396 self.roots.hash(state);
397 self.node_paths.hash(state);
398 self.attr_paths.hash(state);
399 }
400 }
401}
402
403impl PartialEq for Template {
404 fn eq(&self, other: &Self) -> bool {
405 if static_items_merged() {
407 std::ptr::eq(self.roots as *const _, other.roots as *const _)
408 && std::ptr::eq(self.node_paths as *const _, other.node_paths as *const _)
409 && std::ptr::eq(self.attr_paths as *const _, other.attr_paths as *const _)
410 }
411 else {
413 self.roots == other.roots
414 && self.node_paths == other.node_paths
415 && self.attr_paths == other.attr_paths
416 }
417 }
418}
419
420#[cfg(feature = "serialize")]
421pub(crate) fn deserialize_string_leaky<'a, 'de, D>(
422 deserializer: D,
423) -> Result<&'static str, D::Error>
424where
425 D: serde::Deserializer<'de>,
426{
427 use serde::Deserialize;
428
429 let deserialized = String::deserialize(deserializer)?;
430 Ok(&*Box::leak(deserialized.into_boxed_str()))
431}
432
433#[cfg(feature = "serialize")]
434fn deserialize_bytes_leaky<'a, 'de, D>(
435 deserializer: D,
436) -> Result<&'static [&'static [u8]], D::Error>
437where
438 D: serde::Deserializer<'de>,
439{
440 use serde::Deserialize;
441
442 let deserialized = Vec::<Vec<u8>>::deserialize(deserializer)?;
443 let deserialized = deserialized
444 .into_iter()
445 .map(|v| &*Box::leak(v.into_boxed_slice()))
446 .collect::<Vec<_>>();
447 Ok(&*Box::leak(deserialized.into_boxed_slice()))
448}
449
450#[cfg(feature = "serialize")]
451pub(crate) fn deserialize_leaky<'a, 'de, T, D>(deserializer: D) -> Result<&'static [T], D::Error>
452where
453 T: serde::Deserialize<'de>,
454 D: serde::Deserializer<'de>,
455{
456 use serde::Deserialize;
457
458 let deserialized = Box::<[T]>::deserialize(deserializer)?;
459 Ok(&*Box::leak(deserialized))
460}
461
462#[cfg(feature = "serialize")]
463pub(crate) fn deserialize_option_leaky<'a, 'de, D>(
464 deserializer: D,
465) -> Result<Option<&'static str>, D::Error>
466where
467 D: serde::Deserializer<'de>,
468{
469 use serde::Deserialize;
470
471 let deserialized = Option::<String>::deserialize(deserializer)?;
472 Ok(deserialized.map(|deserialized| &*Box::leak(deserialized.into_boxed_str())))
473}
474
475impl Template {
476 pub fn is_completely_dynamic(&self) -> bool {
480 use TemplateNode::*;
481 self.roots.iter().all(|root| matches!(root, Dynamic { .. }))
482 }
483}
484
485#[derive(Debug, Clone, Copy, PartialEq, Hash, Eq, PartialOrd, Ord)]
489#[cfg_attr(
490 feature = "serialize",
491 derive(serde::Serialize, serde::Deserialize),
492 serde(tag = "type")
493)]
494pub enum TemplateNode {
495 Element {
499 #[cfg_attr(
503 feature = "serialize",
504 serde(deserialize_with = "deserialize_string_leaky")
505 )]
506 tag: StaticStr,
507
508 #[cfg_attr(
513 feature = "serialize",
514 serde(deserialize_with = "deserialize_option_leaky")
515 )]
516 namespace: Option<StaticStr>,
517
518 #[cfg_attr(
522 feature = "serialize",
523 serde(deserialize_with = "deserialize_leaky", bound = "")
524 )]
525 attrs: StaticTemplateAttributeArray,
526
527 #[cfg_attr(feature = "serialize", serde(deserialize_with = "deserialize_leaky"))]
529 children: StaticTemplateArray,
530 },
531
532 Text {
534 #[cfg_attr(
536 feature = "serialize",
537 serde(deserialize_with = "deserialize_string_leaky", bound = "")
538 )]
539 text: StaticStr,
540 },
541
542 Dynamic {
544 id: usize,
546 },
547}
548
549impl TemplateNode {
550 pub fn dynamic_id(&self) -> Option<usize> {
552 use TemplateNode::*;
553 match self {
554 Dynamic { id } => Some(*id),
555 _ => None,
556 }
557 }
558}
559
560#[derive(Debug, Clone)]
564pub enum DynamicNode {
565 Component(VComponent),
573
574 Text(VText),
576
577 Placeholder(VPlaceholder),
583
584 Fragment(Vec<VNode>),
589}
590
591impl DynamicNode {
592 pub fn make_node<'c, I>(into: impl IntoDynNode<I> + 'c) -> DynamicNode {
594 into.into_dyn_node()
595 }
596}
597
598impl Default for DynamicNode {
599 fn default() -> Self {
600 Self::Placeholder(Default::default())
601 }
602}
603
604pub struct VComponent {
606 pub name: &'static str,
608
609 pub(crate) render_fn: usize,
611
612 pub(crate) props: BoxedAnyProps,
614}
615
616impl Clone for VComponent {
617 fn clone(&self) -> Self {
618 Self {
619 name: self.name,
620 props: self.props.duplicate(),
621 render_fn: self.render_fn,
622 }
623 }
624}
625
626impl VComponent {
627 pub fn new<P, M: 'static>(
629 component: impl ComponentFunction<P, M>,
630 props: P,
631 fn_name: &'static str,
632 ) -> Self
633 where
634 P: Properties + 'static,
635 {
636 let render_fn = component.fn_ptr();
637 let props = Box::new(VProps::new(
638 component,
639 <P as Properties>::memoize,
640 props,
641 fn_name,
642 ));
643
644 VComponent {
645 render_fn,
646 name: fn_name,
647 props,
648 }
649 }
650
651 pub fn mounted_scope_id(
657 &self,
658 dynamic_node_index: usize,
659 vnode: &VNode,
660 dom: &VirtualDom,
661 ) -> Option<ScopeId> {
662 let mount = vnode.mount.get().as_usize()?;
663
664 let mounts = dom.runtime.mounts.borrow();
665 let scope_id = mounts.get(mount)?.mounted_dynamic_nodes[dynamic_node_index];
666
667 Some(ScopeId(scope_id))
668 }
669
670 pub fn mounted_scope<'a>(
676 &self,
677 dynamic_node_index: usize,
678 vnode: &VNode,
679 dom: &'a VirtualDom,
680 ) -> Option<&'a ScopeState> {
681 let mount = vnode.mount.get().as_usize()?;
682
683 let mounts = dom.runtime.mounts.borrow();
684 let scope_id = mounts.get(mount)?.mounted_dynamic_nodes[dynamic_node_index];
685
686 dom.scopes.get(scope_id)
687 }
688}
689
690impl std::fmt::Debug for VComponent {
691 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
692 f.debug_struct("VComponent")
693 .field("name", &self.name)
694 .finish()
695 }
696}
697
698#[derive(Clone, Debug)]
700pub struct VText {
701 pub value: String,
703}
704
705impl VText {
706 pub fn new(value: impl ToString) -> Self {
708 Self {
709 value: value.to_string(),
710 }
711 }
712}
713
714impl From<Arguments<'_>> for VText {
715 fn from(args: Arguments) -> Self {
716 Self::new(args.to_string())
717 }
718}
719
720#[derive(Clone, Debug, Default)]
722#[non_exhaustive]
723pub struct VPlaceholder {}
724
725#[derive(Debug, PartialEq, Hash, Eq, PartialOrd, Ord)]
727#[cfg_attr(
728 feature = "serialize",
729 derive(serde::Serialize, serde::Deserialize),
730 serde(tag = "type")
731)]
732pub enum TemplateAttribute {
733 Static {
735 #[cfg_attr(
739 feature = "serialize",
740 serde(deserialize_with = "deserialize_string_leaky", bound = "")
741 )]
742 name: StaticStr,
743
744 #[cfg_attr(
748 feature = "serialize",
749 serde(deserialize_with = "deserialize_string_leaky", bound = "")
750 )]
751 value: StaticStr,
752
753 #[cfg_attr(
755 feature = "serialize",
756 serde(deserialize_with = "deserialize_option_leaky", bound = "")
757 )]
758 namespace: Option<StaticStr>,
759 },
760
761 Dynamic {
765 id: usize,
767 },
768}
769
770#[derive(Debug, Clone, PartialEq)]
772pub struct Attribute {
773 pub name: &'static str,
775
776 pub value: AttributeValue,
778
779 pub namespace: Option<&'static str>,
783
784 pub volatile: bool,
786}
787
788impl Attribute {
789 pub fn new<T>(
794 name: &'static str,
795 value: impl IntoAttributeValue<T>,
796 namespace: Option<&'static str>,
797 volatile: bool,
798 ) -> Attribute {
799 Attribute {
800 name,
801 namespace,
802 volatile,
803 value: value.into_value(),
804 }
805 }
806
807 pub(crate) fn deep_clone(&self) -> Self {
809 Attribute {
810 name: self.name,
811 namespace: self.namespace,
812 volatile: self.volatile,
813 value: match &self.value {
814 AttributeValue::Listener(listener) => {
815 AttributeValue::Listener(listener.leak_reference().unwrap())
816 }
817 value => value.clone(),
818 },
819 }
820 }
821}
822
823#[derive(Clone)]
828pub enum AttributeValue {
829 Text(String),
831
832 Float(f64),
834
835 Int(i64),
837
838 Bool(bool),
840
841 Listener(ListenerCb),
843
844 Any(Rc<dyn AnyValue>),
846
847 None,
849}
850
851impl AttributeValue {
852 pub fn listener<T: 'static>(mut callback: impl FnMut(Event<T>) + 'static) -> AttributeValue {
856 AttributeValue::Listener(EventHandler::leak(move |event: Event<dyn Any>| {
859 let data = event.data.downcast::<T>().unwrap();
860 callback(Event {
861 metadata: event.metadata.clone(),
862 data,
863 });
864 }))
865 }
866
867 pub fn any_value<T: AnyValue>(value: T) -> AttributeValue {
869 AttributeValue::Any(Rc::new(value))
870 }
871}
872
873pub type ListenerCb = EventHandler<Event<dyn Any>>;
874
875impl std::fmt::Debug for AttributeValue {
876 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
877 match self {
878 Self::Text(arg0) => f.debug_tuple("Text").field(arg0).finish(),
879 Self::Float(arg0) => f.debug_tuple("Float").field(arg0).finish(),
880 Self::Int(arg0) => f.debug_tuple("Int").field(arg0).finish(),
881 Self::Bool(arg0) => f.debug_tuple("Bool").field(arg0).finish(),
882 Self::Listener(listener) => f.debug_tuple("Listener").field(listener).finish(),
883 Self::Any(_) => f.debug_tuple("Any").finish(),
884 Self::None => write!(f, "None"),
885 }
886 }
887}
888
889impl PartialEq for AttributeValue {
890 fn eq(&self, other: &Self) -> bool {
891 match (self, other) {
892 (Self::Text(l0), Self::Text(r0)) => l0 == r0,
893 (Self::Float(l0), Self::Float(r0)) => l0 == r0,
894 (Self::Int(l0), Self::Int(r0)) => l0 == r0,
895 (Self::Bool(l0), Self::Bool(r0)) => l0 == r0,
896 (Self::Listener(l0), Self::Listener(r0)) => l0 == r0,
897 (Self::Any(l0), Self::Any(r0)) => l0.as_ref().any_cmp(r0.as_ref()),
898 (Self::None, Self::None) => true,
899 _ => false,
900 }
901 }
902}
903
904#[doc(hidden)]
905pub trait AnyValue: 'static {
906 fn any_cmp(&self, other: &dyn AnyValue) -> bool;
907 fn as_any(&self) -> &dyn Any;
908 fn type_id(&self) -> TypeId {
909 self.as_any().type_id()
910 }
911}
912
913impl<T: Any + PartialEq + 'static> AnyValue for T {
914 fn any_cmp(&self, other: &dyn AnyValue) -> bool {
915 if let Some(other) = other.as_any().downcast_ref() {
916 self == other
917 } else {
918 false
919 }
920 }
921
922 fn as_any(&self) -> &dyn Any {
923 self
924 }
925}
926
927pub trait IntoDynNode<A = ()> {
929 fn into_dyn_node(self) -> DynamicNode;
931}
932
933impl IntoDynNode for () {
934 fn into_dyn_node(self) -> DynamicNode {
935 DynamicNode::default()
936 }
937}
938impl IntoDynNode for VNode {
939 fn into_dyn_node(self) -> DynamicNode {
940 DynamicNode::Fragment(vec![self])
941 }
942}
943impl IntoDynNode for DynamicNode {
944 fn into_dyn_node(self) -> DynamicNode {
945 self
946 }
947}
948impl<T: IntoDynNode> IntoDynNode for Option<T> {
949 fn into_dyn_node(self) -> DynamicNode {
950 match self {
951 Some(val) => val.into_dyn_node(),
952 None => DynamicNode::default(),
953 }
954 }
955}
956impl IntoDynNode for &Element {
957 fn into_dyn_node(self) -> DynamicNode {
958 match self.as_ref() {
959 Ok(val) => val.into_dyn_node(),
960 _ => DynamicNode::default(),
961 }
962 }
963}
964impl IntoDynNode for Element {
965 fn into_dyn_node(self) -> DynamicNode {
966 match self {
967 Ok(val) => val.into_dyn_node(),
968 _ => DynamicNode::default(),
969 }
970 }
971}
972impl IntoDynNode for &Option<VNode> {
973 fn into_dyn_node(self) -> DynamicNode {
974 match self.as_ref() {
975 Some(val) => val.clone().into_dyn_node(),
976 _ => DynamicNode::default(),
977 }
978 }
979}
980impl IntoDynNode for &str {
981 fn into_dyn_node(self) -> DynamicNode {
982 DynamicNode::Text(VText {
983 value: self.to_string(),
984 })
985 }
986}
987impl IntoDynNode for String {
988 fn into_dyn_node(self) -> DynamicNode {
989 DynamicNode::Text(VText { value: self })
990 }
991}
992impl IntoDynNode for Arguments<'_> {
993 fn into_dyn_node(self) -> DynamicNode {
994 DynamicNode::Text(VText {
995 value: self.to_string(),
996 })
997 }
998}
999impl IntoDynNode for &VNode {
1000 fn into_dyn_node(self) -> DynamicNode {
1001 DynamicNode::Fragment(vec![self.clone()])
1002 }
1003}
1004
1005pub trait IntoVNode {
1006 fn into_vnode(self) -> VNode;
1007}
1008impl IntoVNode for VNode {
1009 fn into_vnode(self) -> VNode {
1010 self
1011 }
1012}
1013impl IntoVNode for &VNode {
1014 fn into_vnode(self) -> VNode {
1015 self.clone()
1016 }
1017}
1018impl IntoVNode for Element {
1019 fn into_vnode(self) -> VNode {
1020 match self {
1021 Ok(val) => val.into_vnode(),
1022 _ => VNode::empty().unwrap(),
1023 }
1024 }
1025}
1026impl IntoVNode for &Element {
1027 fn into_vnode(self) -> VNode {
1028 match self {
1029 Ok(val) => val.into_vnode(),
1030 _ => VNode::empty().unwrap(),
1031 }
1032 }
1033}
1034impl IntoVNode for Option<VNode> {
1035 fn into_vnode(self) -> VNode {
1036 match self {
1037 Some(val) => val.into_vnode(),
1038 _ => VNode::empty().unwrap(),
1039 }
1040 }
1041}
1042impl IntoVNode for &Option<VNode> {
1043 fn into_vnode(self) -> VNode {
1044 match self.as_ref() {
1045 Some(val) => val.clone().into_vnode(),
1046 _ => VNode::empty().unwrap(),
1047 }
1048 }
1049}
1050impl IntoVNode for Option<Element> {
1051 fn into_vnode(self) -> VNode {
1052 match self {
1053 Some(val) => val.into_vnode(),
1054 _ => VNode::empty().unwrap(),
1055 }
1056 }
1057}
1058impl IntoVNode for &Option<Element> {
1059 fn into_vnode(self) -> VNode {
1060 match self.as_ref() {
1061 Some(val) => val.clone().into_vnode(),
1062 _ => VNode::empty().unwrap(),
1063 }
1064 }
1065}
1066
1067pub struct FromNodeIterator;
1069impl<T, I> IntoDynNode<FromNodeIterator> for T
1070where
1071 T: Iterator<Item = I>,
1072 I: IntoVNode,
1073{
1074 fn into_dyn_node(self) -> DynamicNode {
1075 let children: Vec<_> = self.into_iter().map(|node| node.into_vnode()).collect();
1076
1077 if children.is_empty() {
1078 DynamicNode::default()
1079 } else {
1080 DynamicNode::Fragment(children)
1081 }
1082 }
1083}
1084
1085pub trait IntoAttributeValue<T = ()> {
1087 fn into_value(self) -> AttributeValue;
1089}
1090
1091impl IntoAttributeValue for AttributeValue {
1092 fn into_value(self) -> AttributeValue {
1093 self
1094 }
1095}
1096
1097impl IntoAttributeValue for &str {
1098 fn into_value(self) -> AttributeValue {
1099 AttributeValue::Text(self.to_string())
1100 }
1101}
1102
1103impl IntoAttributeValue for String {
1104 fn into_value(self) -> AttributeValue {
1105 AttributeValue::Text(self)
1106 }
1107}
1108
1109impl IntoAttributeValue for f32 {
1110 fn into_value(self) -> AttributeValue {
1111 AttributeValue::Float(self as _)
1112 }
1113}
1114impl IntoAttributeValue for f64 {
1115 fn into_value(self) -> AttributeValue {
1116 AttributeValue::Float(self)
1117 }
1118}
1119
1120impl IntoAttributeValue for i8 {
1121 fn into_value(self) -> AttributeValue {
1122 AttributeValue::Int(self as _)
1123 }
1124}
1125impl IntoAttributeValue for i16 {
1126 fn into_value(self) -> AttributeValue {
1127 AttributeValue::Int(self as _)
1128 }
1129}
1130impl IntoAttributeValue for i32 {
1131 fn into_value(self) -> AttributeValue {
1132 AttributeValue::Int(self as _)
1133 }
1134}
1135impl IntoAttributeValue for i64 {
1136 fn into_value(self) -> AttributeValue {
1137 AttributeValue::Int(self)
1138 }
1139}
1140impl IntoAttributeValue for isize {
1141 fn into_value(self) -> AttributeValue {
1142 AttributeValue::Int(self as _)
1143 }
1144}
1145impl IntoAttributeValue for i128 {
1146 fn into_value(self) -> AttributeValue {
1147 AttributeValue::Int(self as _)
1148 }
1149}
1150
1151impl IntoAttributeValue for u8 {
1152 fn into_value(self) -> AttributeValue {
1153 AttributeValue::Int(self as _)
1154 }
1155}
1156impl IntoAttributeValue for u16 {
1157 fn into_value(self) -> AttributeValue {
1158 AttributeValue::Int(self as _)
1159 }
1160}
1161impl IntoAttributeValue for u32 {
1162 fn into_value(self) -> AttributeValue {
1163 AttributeValue::Int(self as _)
1164 }
1165}
1166impl IntoAttributeValue for u64 {
1167 fn into_value(self) -> AttributeValue {
1168 AttributeValue::Int(self as _)
1169 }
1170}
1171impl IntoAttributeValue for usize {
1172 fn into_value(self) -> AttributeValue {
1173 AttributeValue::Int(self as _)
1174 }
1175}
1176impl IntoAttributeValue for u128 {
1177 fn into_value(self) -> AttributeValue {
1178 AttributeValue::Int(self as _)
1179 }
1180}
1181
1182impl IntoAttributeValue for bool {
1183 fn into_value(self) -> AttributeValue {
1184 AttributeValue::Bool(self)
1185 }
1186}
1187
1188impl IntoAttributeValue for Arguments<'_> {
1189 fn into_value(self) -> AttributeValue {
1190 AttributeValue::Text(self.to_string())
1191 }
1192}
1193
1194impl IntoAttributeValue for Rc<dyn AnyValue> {
1195 fn into_value(self) -> AttributeValue {
1196 AttributeValue::Any(self)
1197 }
1198}
1199
1200impl<T: IntoAttributeValue> IntoAttributeValue for Option<T> {
1201 fn into_value(self) -> AttributeValue {
1202 match self {
1203 Some(val) => val.into_value(),
1204 None => AttributeValue::None,
1205 }
1206 }
1207}
1208
1209pub struct AnyFmtMarker;
1210impl<T> IntoAttributeValue<AnyFmtMarker> for T
1211where
1212 T: DioxusFormattable,
1213{
1214 fn into_value(self) -> AttributeValue {
1215 AttributeValue::Text(self.format().to_string())
1216 }
1217}
1218
1219pub trait HasAttributes {
1221 fn push_attribute<T>(
1223 self,
1224 name: &'static str,
1225 ns: Option<&'static str>,
1226 attr: impl IntoAttributeValue<T>,
1227 volatile: bool,
1228 ) -> Self;
1229}