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))]
350#[derive(Debug, Clone, Copy, Eq, PartialOrd, Ord)]
351pub struct Template {
352 #[cfg_attr(feature = "serialize", serde(deserialize_with = "deserialize_leaky"))]
356 pub roots: StaticTemplateArray,
357
358 #[cfg_attr(
363 feature = "serialize",
364 serde(deserialize_with = "deserialize_bytes_leaky")
365 )]
366 pub node_paths: StaticPathArray,
367
368 #[cfg_attr(
373 feature = "serialize",
374 serde(deserialize_with = "deserialize_bytes_leaky", bound = "")
375 )]
376 pub attr_paths: StaticPathArray,
377}
378
379#[allow(unpredictable_function_pointer_comparisons)] fn static_items_merged() -> bool {
383 fn a() {}
384 fn b() {}
385 a as fn() == b as fn()
386 }
388
389impl std::hash::Hash for Template {
390 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
391 if static_items_merged() {
393 std::ptr::hash(self.roots as *const _, state);
394 std::ptr::hash(self.node_paths as *const _, state);
395 std::ptr::hash(self.attr_paths as *const _, state);
396 }
397 else {
399 self.roots.hash(state);
400 self.node_paths.hash(state);
401 self.attr_paths.hash(state);
402 }
403 }
404}
405
406impl PartialEq for Template {
407 fn eq(&self, other: &Self) -> bool {
408 if static_items_merged() {
410 std::ptr::eq(self.roots as *const _, other.roots as *const _)
411 && std::ptr::eq(self.node_paths as *const _, other.node_paths as *const _)
412 && std::ptr::eq(self.attr_paths as *const _, other.attr_paths as *const _)
413 }
414 else {
416 self.roots == other.roots
417 && self.node_paths == other.node_paths
418 && self.attr_paths == other.attr_paths
419 }
420 }
421}
422
423#[cfg(feature = "serialize")]
424pub(crate) fn deserialize_string_leaky<'a, 'de, D>(
425 deserializer: D,
426) -> Result<&'static str, D::Error>
427where
428 D: serde::Deserializer<'de>,
429{
430 use serde::Deserialize;
431
432 let deserialized = String::deserialize(deserializer)?;
433 Ok(&*Box::leak(deserialized.into_boxed_str()))
434}
435
436#[cfg(feature = "serialize")]
437fn deserialize_bytes_leaky<'a, 'de, D>(
438 deserializer: D,
439) -> Result<&'static [&'static [u8]], D::Error>
440where
441 D: serde::Deserializer<'de>,
442{
443 use serde::Deserialize;
444
445 let deserialized = Vec::<Vec<u8>>::deserialize(deserializer)?;
446 let deserialized = deserialized
447 .into_iter()
448 .map(|v| &*Box::leak(v.into_boxed_slice()))
449 .collect::<Vec<_>>();
450 Ok(&*Box::leak(deserialized.into_boxed_slice()))
451}
452
453#[cfg(feature = "serialize")]
454pub(crate) fn deserialize_leaky<'a, 'de, T, D>(deserializer: D) -> Result<&'static [T], D::Error>
455where
456 T: serde::Deserialize<'de>,
457 D: serde::Deserializer<'de>,
458{
459 use serde::Deserialize;
460
461 let deserialized = Box::<[T]>::deserialize(deserializer)?;
462 Ok(&*Box::leak(deserialized))
463}
464
465#[cfg(feature = "serialize")]
466pub(crate) fn deserialize_option_leaky<'a, 'de, D>(
467 deserializer: D,
468) -> Result<Option<&'static str>, D::Error>
469where
470 D: serde::Deserializer<'de>,
471{
472 use serde::Deserialize;
473
474 let deserialized = Option::<String>::deserialize(deserializer)?;
475 Ok(deserialized.map(|deserialized| &*Box::leak(deserialized.into_boxed_str())))
476}
477
478impl Template {
479 pub fn is_completely_dynamic(&self) -> bool {
483 use TemplateNode::*;
484 self.roots.iter().all(|root| matches!(root, Dynamic { .. }))
485 }
486}
487
488#[derive(Debug, Clone, Copy, PartialEq, Hash, Eq, PartialOrd, Ord)]
492#[cfg_attr(
493 feature = "serialize",
494 derive(serde::Serialize, serde::Deserialize),
495 serde(tag = "type")
496)]
497pub enum TemplateNode {
498 Element {
502 #[cfg_attr(
506 feature = "serialize",
507 serde(deserialize_with = "deserialize_string_leaky")
508 )]
509 tag: StaticStr,
510
511 #[cfg_attr(
516 feature = "serialize",
517 serde(deserialize_with = "deserialize_option_leaky")
518 )]
519 namespace: Option<StaticStr>,
520
521 #[cfg_attr(
525 feature = "serialize",
526 serde(deserialize_with = "deserialize_leaky", bound = "")
527 )]
528 attrs: StaticTemplateAttributeArray,
529
530 #[cfg_attr(feature = "serialize", serde(deserialize_with = "deserialize_leaky"))]
532 children: StaticTemplateArray,
533 },
534
535 Text {
537 #[cfg_attr(
539 feature = "serialize",
540 serde(deserialize_with = "deserialize_string_leaky", bound = "")
541 )]
542 text: StaticStr,
543 },
544
545 Dynamic {
547 id: usize,
549 },
550}
551
552impl TemplateNode {
553 pub fn dynamic_id(&self) -> Option<usize> {
555 use TemplateNode::*;
556 match self {
557 Dynamic { id } => Some(*id),
558 _ => None,
559 }
560 }
561}
562
563#[derive(Debug, Clone)]
567pub enum DynamicNode {
568 Component(VComponent),
576
577 Text(VText),
579
580 Placeholder(VPlaceholder),
586
587 Fragment(Vec<VNode>),
592}
593
594impl DynamicNode {
595 pub fn make_node<'c, I>(into: impl IntoDynNode<I> + 'c) -> DynamicNode {
597 into.into_dyn_node()
598 }
599}
600
601impl Default for DynamicNode {
602 fn default() -> Self {
603 Self::Placeholder(Default::default())
604 }
605}
606
607pub struct VComponent {
609 pub name: &'static str,
611
612 pub(crate) render_fn: usize,
614
615 pub(crate) props: BoxedAnyProps,
617}
618
619impl Clone for VComponent {
620 fn clone(&self) -> Self {
621 Self {
622 name: self.name,
623 props: self.props.duplicate(),
624 render_fn: self.render_fn,
625 }
626 }
627}
628
629impl VComponent {
630 pub fn new<P, M: 'static>(
632 component: impl ComponentFunction<P, M>,
633 props: P,
634 fn_name: &'static str,
635 ) -> Self
636 where
637 P: Properties + 'static,
638 {
639 let render_fn = component.fn_ptr();
640 let props = Box::new(VProps::new(
641 component,
642 <P as Properties>::memoize,
643 props,
644 fn_name,
645 ));
646
647 VComponent {
648 render_fn,
649 name: fn_name,
650 props,
651 }
652 }
653
654 pub fn mounted_scope_id(
660 &self,
661 dynamic_node_index: usize,
662 vnode: &VNode,
663 dom: &VirtualDom,
664 ) -> Option<ScopeId> {
665 let mount = vnode.mount.get().as_usize()?;
666
667 let mounts = dom.runtime.mounts.borrow();
668 let scope_id = mounts.get(mount)?.mounted_dynamic_nodes[dynamic_node_index];
669
670 Some(ScopeId(scope_id))
671 }
672
673 pub fn mounted_scope<'a>(
679 &self,
680 dynamic_node_index: usize,
681 vnode: &VNode,
682 dom: &'a VirtualDom,
683 ) -> Option<&'a ScopeState> {
684 let mount = vnode.mount.get().as_usize()?;
685
686 let mounts = dom.runtime.mounts.borrow();
687 let scope_id = mounts.get(mount)?.mounted_dynamic_nodes[dynamic_node_index];
688
689 dom.scopes.get(scope_id)
690 }
691}
692
693impl std::fmt::Debug for VComponent {
694 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
695 f.debug_struct("VComponent")
696 .field("name", &self.name)
697 .finish()
698 }
699}
700
701#[derive(Clone, Debug)]
703pub struct VText {
704 pub value: String,
706}
707
708impl VText {
709 pub fn new(value: impl ToString) -> Self {
711 Self {
712 value: value.to_string(),
713 }
714 }
715}
716
717impl From<Arguments<'_>> for VText {
718 fn from(args: Arguments) -> Self {
719 Self::new(args.to_string())
720 }
721}
722
723#[derive(Clone, Debug, Default)]
725#[non_exhaustive]
726pub struct VPlaceholder {}
727
728#[derive(Debug, PartialEq, Hash, Eq, PartialOrd, Ord)]
730#[cfg_attr(
731 feature = "serialize",
732 derive(serde::Serialize, serde::Deserialize),
733 serde(tag = "type")
734)]
735pub enum TemplateAttribute {
736 Static {
738 #[cfg_attr(
742 feature = "serialize",
743 serde(deserialize_with = "deserialize_string_leaky", bound = "")
744 )]
745 name: StaticStr,
746
747 #[cfg_attr(
751 feature = "serialize",
752 serde(deserialize_with = "deserialize_string_leaky", bound = "")
753 )]
754 value: StaticStr,
755
756 #[cfg_attr(
758 feature = "serialize",
759 serde(deserialize_with = "deserialize_option_leaky", bound = "")
760 )]
761 namespace: Option<StaticStr>,
762 },
763
764 Dynamic {
768 id: usize,
770 },
771}
772
773#[derive(Debug, Clone, PartialEq)]
775pub struct Attribute {
776 pub name: &'static str,
778
779 pub value: AttributeValue,
781
782 pub namespace: Option<&'static str>,
786
787 pub volatile: bool,
789}
790
791impl Attribute {
792 pub fn new<T>(
797 name: &'static str,
798 value: impl IntoAttributeValue<T>,
799 namespace: Option<&'static str>,
800 volatile: bool,
801 ) -> Attribute {
802 Attribute {
803 name,
804 namespace,
805 volatile,
806 value: value.into_value(),
807 }
808 }
809
810 pub(crate) fn deep_clone(&self) -> Self {
812 Attribute {
813 name: self.name,
814 namespace: self.namespace,
815 volatile: self.volatile,
816 value: match &self.value {
817 AttributeValue::Listener(listener) => {
818 AttributeValue::Listener(listener.leak_reference().unwrap())
819 }
820 value => value.clone(),
821 },
822 }
823 }
824}
825
826#[derive(Clone)]
831pub enum AttributeValue {
832 Text(String),
834
835 Float(f64),
837
838 Int(i64),
840
841 Bool(bool),
843
844 Listener(ListenerCb),
846
847 Any(Rc<dyn AnyValue>),
849
850 None,
852}
853
854impl AttributeValue {
855 pub fn listener<T: 'static>(mut callback: impl FnMut(Event<T>) + 'static) -> AttributeValue {
859 AttributeValue::Listener(EventHandler::leak(move |event: Event<dyn Any>| {
862 let data = event.data.downcast::<T>().unwrap();
863 callback(Event {
864 metadata: event.metadata.clone(),
865 data,
866 });
867 }))
868 }
869
870 pub fn any_value<T: AnyValue>(value: T) -> AttributeValue {
872 AttributeValue::Any(Rc::new(value))
873 }
874}
875
876pub type ListenerCb = EventHandler<Event<dyn Any>>;
877
878impl std::fmt::Debug for AttributeValue {
879 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
880 match self {
881 Self::Text(arg0) => f.debug_tuple("Text").field(arg0).finish(),
882 Self::Float(arg0) => f.debug_tuple("Float").field(arg0).finish(),
883 Self::Int(arg0) => f.debug_tuple("Int").field(arg0).finish(),
884 Self::Bool(arg0) => f.debug_tuple("Bool").field(arg0).finish(),
885 Self::Listener(listener) => f.debug_tuple("Listener").field(listener).finish(),
886 Self::Any(_) => f.debug_tuple("Any").finish(),
887 Self::None => write!(f, "None"),
888 }
889 }
890}
891
892impl PartialEq for AttributeValue {
893 fn eq(&self, other: &Self) -> bool {
894 match (self, other) {
895 (Self::Text(l0), Self::Text(r0)) => l0 == r0,
896 (Self::Float(l0), Self::Float(r0)) => l0 == r0,
897 (Self::Int(l0), Self::Int(r0)) => l0 == r0,
898 (Self::Bool(l0), Self::Bool(r0)) => l0 == r0,
899 (Self::Listener(l0), Self::Listener(r0)) => l0 == r0,
900 (Self::Any(l0), Self::Any(r0)) => l0.as_ref().any_cmp(r0.as_ref()),
901 (Self::None, Self::None) => true,
902 _ => false,
903 }
904 }
905}
906
907#[doc(hidden)]
908pub trait AnyValue: 'static {
909 fn any_cmp(&self, other: &dyn AnyValue) -> bool;
910 fn as_any(&self) -> &dyn Any;
911 fn type_id(&self) -> TypeId {
912 self.as_any().type_id()
913 }
914}
915
916impl<T: Any + PartialEq + 'static> AnyValue for T {
917 fn any_cmp(&self, other: &dyn AnyValue) -> bool {
918 if let Some(other) = other.as_any().downcast_ref() {
919 self == other
920 } else {
921 false
922 }
923 }
924
925 fn as_any(&self) -> &dyn Any {
926 self
927 }
928}
929
930pub trait IntoDynNode<A = ()> {
932 fn into_dyn_node(self) -> DynamicNode;
934}
935
936impl IntoDynNode for () {
937 fn into_dyn_node(self) -> DynamicNode {
938 DynamicNode::default()
939 }
940}
941impl IntoDynNode for VNode {
942 fn into_dyn_node(self) -> DynamicNode {
943 DynamicNode::Fragment(vec![self])
944 }
945}
946impl IntoDynNode for DynamicNode {
947 fn into_dyn_node(self) -> DynamicNode {
948 self
949 }
950}
951impl<T: IntoDynNode> IntoDynNode for Option<T> {
952 fn into_dyn_node(self) -> DynamicNode {
953 match self {
954 Some(val) => val.into_dyn_node(),
955 None => DynamicNode::default(),
956 }
957 }
958}
959impl IntoDynNode for &Element {
960 fn into_dyn_node(self) -> DynamicNode {
961 match self.as_ref() {
962 Ok(val) => val.into_dyn_node(),
963 _ => DynamicNode::default(),
964 }
965 }
966}
967impl IntoDynNode for Element {
968 fn into_dyn_node(self) -> DynamicNode {
969 match self {
970 Ok(val) => val.into_dyn_node(),
971 _ => DynamicNode::default(),
972 }
973 }
974}
975impl IntoDynNode for &Option<VNode> {
976 fn into_dyn_node(self) -> DynamicNode {
977 match self.as_ref() {
978 Some(val) => val.clone().into_dyn_node(),
979 _ => DynamicNode::default(),
980 }
981 }
982}
983impl IntoDynNode for &str {
984 fn into_dyn_node(self) -> DynamicNode {
985 DynamicNode::Text(VText {
986 value: self.to_string(),
987 })
988 }
989}
990impl IntoDynNode for String {
991 fn into_dyn_node(self) -> DynamicNode {
992 DynamicNode::Text(VText { value: self })
993 }
994}
995impl IntoDynNode for Arguments<'_> {
996 fn into_dyn_node(self) -> DynamicNode {
997 DynamicNode::Text(VText {
998 value: self.to_string(),
999 })
1000 }
1001}
1002impl IntoDynNode for &VNode {
1003 fn into_dyn_node(self) -> DynamicNode {
1004 DynamicNode::Fragment(vec![self.clone()])
1005 }
1006}
1007
1008pub trait IntoVNode {
1009 fn into_vnode(self) -> VNode;
1010}
1011impl IntoVNode for VNode {
1012 fn into_vnode(self) -> VNode {
1013 self
1014 }
1015}
1016impl IntoVNode for &VNode {
1017 fn into_vnode(self) -> VNode {
1018 self.clone()
1019 }
1020}
1021impl IntoVNode for Element {
1022 fn into_vnode(self) -> VNode {
1023 match self {
1024 Ok(val) => val.into_vnode(),
1025 _ => VNode::empty().unwrap(),
1026 }
1027 }
1028}
1029impl IntoVNode for &Element {
1030 fn into_vnode(self) -> VNode {
1031 match self {
1032 Ok(val) => val.into_vnode(),
1033 _ => VNode::empty().unwrap(),
1034 }
1035 }
1036}
1037impl IntoVNode for Option<VNode> {
1038 fn into_vnode(self) -> VNode {
1039 match self {
1040 Some(val) => val.into_vnode(),
1041 _ => VNode::empty().unwrap(),
1042 }
1043 }
1044}
1045impl IntoVNode for &Option<VNode> {
1046 fn into_vnode(self) -> VNode {
1047 match self.as_ref() {
1048 Some(val) => val.clone().into_vnode(),
1049 _ => VNode::empty().unwrap(),
1050 }
1051 }
1052}
1053impl IntoVNode for Option<Element> {
1054 fn into_vnode(self) -> VNode {
1055 match self {
1056 Some(val) => val.into_vnode(),
1057 _ => VNode::empty().unwrap(),
1058 }
1059 }
1060}
1061impl IntoVNode for &Option<Element> {
1062 fn into_vnode(self) -> VNode {
1063 match self.as_ref() {
1064 Some(val) => val.clone().into_vnode(),
1065 _ => VNode::empty().unwrap(),
1066 }
1067 }
1068}
1069
1070pub struct FromNodeIterator;
1072impl<T, I> IntoDynNode<FromNodeIterator> for T
1073where
1074 T: Iterator<Item = I>,
1075 I: IntoVNode,
1076{
1077 fn into_dyn_node(self) -> DynamicNode {
1078 let children: Vec<_> = self.into_iter().map(|node| node.into_vnode()).collect();
1079
1080 if children.is_empty() {
1081 DynamicNode::default()
1082 } else {
1083 DynamicNode::Fragment(children)
1084 }
1085 }
1086}
1087
1088pub trait IntoAttributeValue<T = ()> {
1090 fn into_value(self) -> AttributeValue;
1092}
1093
1094impl IntoAttributeValue for AttributeValue {
1095 fn into_value(self) -> AttributeValue {
1096 self
1097 }
1098}
1099
1100impl IntoAttributeValue for &str {
1101 fn into_value(self) -> AttributeValue {
1102 AttributeValue::Text(self.to_string())
1103 }
1104}
1105
1106impl IntoAttributeValue for String {
1107 fn into_value(self) -> AttributeValue {
1108 AttributeValue::Text(self)
1109 }
1110}
1111
1112impl IntoAttributeValue for f32 {
1113 fn into_value(self) -> AttributeValue {
1114 AttributeValue::Float(self as _)
1115 }
1116}
1117impl IntoAttributeValue for f64 {
1118 fn into_value(self) -> AttributeValue {
1119 AttributeValue::Float(self)
1120 }
1121}
1122
1123impl IntoAttributeValue for i8 {
1124 fn into_value(self) -> AttributeValue {
1125 AttributeValue::Int(self as _)
1126 }
1127}
1128impl IntoAttributeValue for i16 {
1129 fn into_value(self) -> AttributeValue {
1130 AttributeValue::Int(self as _)
1131 }
1132}
1133impl IntoAttributeValue for i32 {
1134 fn into_value(self) -> AttributeValue {
1135 AttributeValue::Int(self as _)
1136 }
1137}
1138impl IntoAttributeValue for i64 {
1139 fn into_value(self) -> AttributeValue {
1140 AttributeValue::Int(self)
1141 }
1142}
1143impl IntoAttributeValue for isize {
1144 fn into_value(self) -> AttributeValue {
1145 AttributeValue::Int(self as _)
1146 }
1147}
1148impl IntoAttributeValue for i128 {
1149 fn into_value(self) -> AttributeValue {
1150 AttributeValue::Int(self as _)
1151 }
1152}
1153
1154impl IntoAttributeValue for u8 {
1155 fn into_value(self) -> AttributeValue {
1156 AttributeValue::Int(self as _)
1157 }
1158}
1159impl IntoAttributeValue for u16 {
1160 fn into_value(self) -> AttributeValue {
1161 AttributeValue::Int(self as _)
1162 }
1163}
1164impl IntoAttributeValue for u32 {
1165 fn into_value(self) -> AttributeValue {
1166 AttributeValue::Int(self as _)
1167 }
1168}
1169impl IntoAttributeValue for u64 {
1170 fn into_value(self) -> AttributeValue {
1171 AttributeValue::Int(self as _)
1172 }
1173}
1174impl IntoAttributeValue for usize {
1175 fn into_value(self) -> AttributeValue {
1176 AttributeValue::Int(self as _)
1177 }
1178}
1179impl IntoAttributeValue for u128 {
1180 fn into_value(self) -> AttributeValue {
1181 AttributeValue::Int(self as _)
1182 }
1183}
1184
1185impl IntoAttributeValue for bool {
1186 fn into_value(self) -> AttributeValue {
1187 AttributeValue::Bool(self)
1188 }
1189}
1190
1191impl IntoAttributeValue for Arguments<'_> {
1192 fn into_value(self) -> AttributeValue {
1193 AttributeValue::Text(self.to_string())
1194 }
1195}
1196
1197impl IntoAttributeValue for Rc<dyn AnyValue> {
1198 fn into_value(self) -> AttributeValue {
1199 AttributeValue::Any(self)
1200 }
1201}
1202
1203impl<T: IntoAttributeValue> IntoAttributeValue for Option<T> {
1204 fn into_value(self) -> AttributeValue {
1205 match self {
1206 Some(val) => val.into_value(),
1207 None => AttributeValue::None,
1208 }
1209 }
1210}
1211
1212pub struct AnyFmtMarker;
1213impl<T> IntoAttributeValue<AnyFmtMarker> for T
1214where
1215 T: DioxusFormattable,
1216{
1217 fn into_value(self) -> AttributeValue {
1218 AttributeValue::Text(self.format().to_string())
1219 }
1220}
1221
1222pub trait HasAttributes {
1224 fn push_attribute<T>(
1226 self,
1227 name: &'static str,
1228 ns: Option<&'static str>,
1229 attr: impl IntoAttributeValue<T>,
1230 volatile: bool,
1231 ) -> Self;
1232}