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