1use crate::{
2 any_props::BoxedAnyProps,
3 arena::ElementId,
4 events::ListenerCallback,
5 innerlude::{ElementRef, MountId, ScopeState, VProps},
6 properties::ComponentFunction,
7 Element, Event, Properties, ScopeId, VirtualDom,
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 {
143 roots: &[TemplateNode::Dynamic { id: 0 }],
144 node_paths: &[&[0]],
145 attr_paths: &[],
146 },
147 })
148 })
149 .clone()
150 });
151 Self {
152 vnode,
153 mount: Default::default(),
154 }
155 }
156
157 pub fn new(
159 key: Option<String>,
160 template: Template,
161 dynamic_nodes: Box<[DynamicNode]>,
162 dynamic_attrs: Box<[Box<[Attribute]>]>,
163 ) -> Self {
164 Self {
165 vnode: Rc::new(VNodeInner {
166 key,
167 template,
168 dynamic_nodes,
169 dynamic_attrs,
170 }),
171 mount: Default::default(),
172 }
173 }
174
175 pub fn dynamic_root(&self, idx: usize) -> Option<&DynamicNode> {
179 self.template.roots[idx]
180 .dynamic_id()
181 .map(|id| &self.dynamic_nodes[id])
182 }
183
184 pub fn mounted_dynamic_node(
186 &self,
187 dynamic_node_idx: usize,
188 dom: &VirtualDom,
189 ) -> Option<ElementId> {
190 let mount = self.mount.get().as_usize()?;
191
192 match &self.dynamic_nodes[dynamic_node_idx] {
193 DynamicNode::Text(_) | DynamicNode::Placeholder(_) => {
194 let mounts = dom.runtime.mounts.borrow();
195 mounts
196 .get(mount)?
197 .mounted_dynamic_nodes
198 .get(dynamic_node_idx)
199 .map(|id| ElementId(*id))
200 }
201 _ => None,
202 }
203 }
204
205 pub fn mounted_root(&self, root_idx: usize, dom: &VirtualDom) -> Option<ElementId> {
207 let mount = self.mount.get().as_usize()?;
208
209 let mounts = dom.runtime.mounts.borrow();
210 mounts.get(mount)?.root_ids.get(root_idx).copied()
211 }
212
213 pub fn mounted_dynamic_attribute(
215 &self,
216 dynamic_attribute_idx: usize,
217 dom: &VirtualDom,
218 ) -> Option<ElementId> {
219 let mount = self.mount.get().as_usize()?;
220
221 let mounts = dom.runtime.mounts.borrow();
222 mounts
223 .get(mount)?
224 .mounted_attributes
225 .get(dynamic_attribute_idx)
226 .copied()
227 }
228
229 pub(crate) fn deep_clone(&self) -> Self {
231 Self {
232 vnode: Rc::new(VNodeInner {
233 key: self.vnode.key.clone(),
234 template: self.vnode.template,
235 dynamic_nodes: self
236 .vnode
237 .dynamic_nodes
238 .iter()
239 .map(|node| match node {
240 DynamicNode::Fragment(nodes) => DynamicNode::Fragment(
241 nodes.iter().map(|node| node.deep_clone()).collect(),
242 ),
243 other => other.clone(),
244 })
245 .collect(),
246 dynamic_attrs: self
247 .vnode
248 .dynamic_attrs
249 .iter()
250 .map(|attr| {
251 attr.iter()
252 .map(|attribute| attribute.deep_clone())
253 .collect()
254 })
255 .collect(),
256 }),
257 mount: Default::default(),
258 }
259 }
260}
261
262type StaticStr = &'static str;
263type StaticPathArray = &'static [&'static [u8]];
264type StaticTemplateArray = &'static [TemplateNode];
265type StaticTemplateAttributeArray = &'static [TemplateAttribute];
266
267#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
273#[derive(Debug, Clone, Copy, Eq, PartialOrd, Ord)]
274pub struct Template {
275 #[cfg_attr(feature = "serialize", serde(deserialize_with = "deserialize_leaky"))]
279 pub roots: StaticTemplateArray,
280
281 #[cfg_attr(
286 feature = "serialize",
287 serde(deserialize_with = "deserialize_bytes_leaky")
288 )]
289 pub node_paths: StaticPathArray,
290
291 #[cfg_attr(
296 feature = "serialize",
297 serde(deserialize_with = "deserialize_bytes_leaky", bound = "")
298 )]
299 pub attr_paths: StaticPathArray,
300}
301
302#[allow(unpredictable_function_pointer_comparisons)] fn static_items_merged() -> bool {
306 fn a() {}
307 fn b() {}
308 a as fn() == b as fn()
309 }
311
312impl std::hash::Hash for Template {
313 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
314 if static_items_merged() {
316 std::ptr::hash(self.roots as *const _, state);
317 std::ptr::hash(self.node_paths as *const _, state);
318 std::ptr::hash(self.attr_paths as *const _, state);
319 }
320 else {
322 self.roots.hash(state);
323 self.node_paths.hash(state);
324 self.attr_paths.hash(state);
325 }
326 }
327}
328
329impl PartialEq for Template {
330 fn eq(&self, other: &Self) -> bool {
331 if static_items_merged() {
333 std::ptr::eq(self.roots as *const _, other.roots as *const _)
334 && std::ptr::eq(self.node_paths as *const _, other.node_paths as *const _)
335 && std::ptr::eq(self.attr_paths as *const _, other.attr_paths as *const _)
336 }
337 else {
339 self.roots == other.roots
340 && self.node_paths == other.node_paths
341 && self.attr_paths == other.attr_paths
342 }
343 }
344}
345
346#[cfg(feature = "serialize")]
347pub(crate) fn deserialize_string_leaky<'a, 'de, D>(
348 deserializer: D,
349) -> Result<&'static str, D::Error>
350where
351 D: serde::Deserializer<'de>,
352{
353 use serde::Deserialize;
354
355 let deserialized = String::deserialize(deserializer)?;
356 Ok(&*Box::leak(deserialized.into_boxed_str()))
357}
358
359#[cfg(feature = "serialize")]
360fn deserialize_bytes_leaky<'a, 'de, D>(
361 deserializer: D,
362) -> Result<&'static [&'static [u8]], D::Error>
363where
364 D: serde::Deserializer<'de>,
365{
366 use serde::Deserialize;
367
368 let deserialized = Vec::<Vec<u8>>::deserialize(deserializer)?;
369 let deserialized = deserialized
370 .into_iter()
371 .map(|v| &*Box::leak(v.into_boxed_slice()))
372 .collect::<Vec<_>>();
373 Ok(&*Box::leak(deserialized.into_boxed_slice()))
374}
375
376#[cfg(feature = "serialize")]
377pub(crate) fn deserialize_leaky<'a, 'de, T, D>(deserializer: D) -> Result<&'static [T], D::Error>
378where
379 T: serde::Deserialize<'de>,
380 D: serde::Deserializer<'de>,
381{
382 use serde::Deserialize;
383
384 let deserialized = Box::<[T]>::deserialize(deserializer)?;
385 Ok(&*Box::leak(deserialized))
386}
387
388#[cfg(feature = "serialize")]
389pub(crate) fn deserialize_option_leaky<'a, 'de, D>(
390 deserializer: D,
391) -> Result<Option<&'static str>, D::Error>
392where
393 D: serde::Deserializer<'de>,
394{
395 use serde::Deserialize;
396
397 let deserialized = Option::<String>::deserialize(deserializer)?;
398 Ok(deserialized.map(|deserialized| &*Box::leak(deserialized.into_boxed_str())))
399}
400
401impl Template {
402 pub fn is_completely_dynamic(&self) -> bool {
406 use TemplateNode::*;
407 self.roots.iter().all(|root| matches!(root, Dynamic { .. }))
408 }
409}
410
411#[derive(Debug, Clone, Copy, PartialEq, Hash, Eq, PartialOrd, Ord)]
415#[cfg_attr(
416 feature = "serialize",
417 derive(serde::Serialize, serde::Deserialize),
418 serde(tag = "type")
419)]
420pub enum TemplateNode {
421 Element {
425 #[cfg_attr(
429 feature = "serialize",
430 serde(deserialize_with = "deserialize_string_leaky")
431 )]
432 tag: StaticStr,
433
434 #[cfg_attr(
439 feature = "serialize",
440 serde(deserialize_with = "deserialize_option_leaky")
441 )]
442 namespace: Option<StaticStr>,
443
444 #[cfg_attr(
448 feature = "serialize",
449 serde(deserialize_with = "deserialize_leaky", bound = "")
450 )]
451 attrs: StaticTemplateAttributeArray,
452
453 #[cfg_attr(feature = "serialize", serde(deserialize_with = "deserialize_leaky"))]
455 children: StaticTemplateArray,
456 },
457
458 Text {
460 #[cfg_attr(
462 feature = "serialize",
463 serde(deserialize_with = "deserialize_string_leaky", bound = "")
464 )]
465 text: StaticStr,
466 },
467
468 Dynamic {
470 id: usize,
472 },
473}
474
475impl TemplateNode {
476 pub fn dynamic_id(&self) -> Option<usize> {
478 use TemplateNode::*;
479 match self {
480 Dynamic { id } => Some(*id),
481 _ => None,
482 }
483 }
484}
485
486#[derive(Debug, Clone)]
490pub enum DynamicNode {
491 Component(VComponent),
499
500 Text(VText),
502
503 Placeholder(VPlaceholder),
509
510 Fragment(Vec<VNode>),
515}
516
517impl DynamicNode {
518 pub fn make_node<'c, I>(into: impl IntoDynNode<I> + 'c) -> DynamicNode {
520 into.into_dyn_node()
521 }
522}
523
524impl Default for DynamicNode {
525 fn default() -> Self {
526 Self::Placeholder(Default::default())
527 }
528}
529
530pub struct VComponent {
532 pub name: &'static str,
534
535 pub(crate) render_fn: usize,
537
538 pub(crate) props: BoxedAnyProps,
540}
541
542impl Clone for VComponent {
543 fn clone(&self) -> Self {
544 Self {
545 name: self.name,
546 props: self.props.duplicate(),
547 render_fn: self.render_fn,
548 }
549 }
550}
551
552impl VComponent {
553 pub fn new<P, M: 'static>(
555 component: impl ComponentFunction<P, M>,
556 props: P,
557 fn_name: &'static str,
558 ) -> Self
559 where
560 P: Properties + 'static,
561 {
562 let render_fn = component.fn_ptr();
563 let props = Box::new(VProps::new(
564 component,
565 <P as Properties>::memoize,
566 props,
567 fn_name,
568 ));
569
570 VComponent {
571 render_fn,
572 name: fn_name,
573 props,
574 }
575 }
576
577 pub fn mounted_scope_id(
583 &self,
584 dynamic_node_index: usize,
585 vnode: &VNode,
586 dom: &VirtualDom,
587 ) -> Option<ScopeId> {
588 let mount = vnode.mount.get().as_usize()?;
589
590 let mounts = dom.runtime.mounts.borrow();
591 let scope_id = mounts.get(mount)?.mounted_dynamic_nodes[dynamic_node_index];
592
593 Some(ScopeId(scope_id))
594 }
595
596 pub fn mounted_scope<'a>(
602 &self,
603 dynamic_node_index: usize,
604 vnode: &VNode,
605 dom: &'a VirtualDom,
606 ) -> Option<&'a ScopeState> {
607 let mount = vnode.mount.get().as_usize()?;
608
609 let mounts = dom.runtime.mounts.borrow();
610 let scope_id = mounts.get(mount)?.mounted_dynamic_nodes[dynamic_node_index];
611
612 dom.scopes.get(scope_id)
613 }
614}
615
616impl std::fmt::Debug for VComponent {
617 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
618 f.debug_struct("VComponent")
619 .field("name", &self.name)
620 .finish()
621 }
622}
623
624#[derive(Clone, Debug)]
626pub struct VText {
627 pub value: String,
629}
630
631impl VText {
632 pub fn new(value: impl ToString) -> Self {
634 Self {
635 value: value.to_string(),
636 }
637 }
638}
639
640impl From<Arguments<'_>> for VText {
641 fn from(args: Arguments) -> Self {
642 Self::new(args.to_string())
643 }
644}
645
646#[derive(Clone, Debug, Default)]
648#[non_exhaustive]
649pub struct VPlaceholder {}
650
651#[derive(Debug, PartialEq, Hash, Eq, PartialOrd, Ord)]
653#[cfg_attr(
654 feature = "serialize",
655 derive(serde::Serialize, serde::Deserialize),
656 serde(tag = "type")
657)]
658pub enum TemplateAttribute {
659 Static {
661 #[cfg_attr(
665 feature = "serialize",
666 serde(deserialize_with = "deserialize_string_leaky", bound = "")
667 )]
668 name: StaticStr,
669
670 #[cfg_attr(
674 feature = "serialize",
675 serde(deserialize_with = "deserialize_string_leaky", bound = "")
676 )]
677 value: StaticStr,
678
679 #[cfg_attr(
681 feature = "serialize",
682 serde(deserialize_with = "deserialize_option_leaky", bound = "")
683 )]
684 namespace: Option<StaticStr>,
685 },
686
687 Dynamic {
691 id: usize,
693 },
694}
695
696#[derive(Debug, Clone, PartialEq)]
698pub struct Attribute {
699 pub name: &'static str,
701
702 pub value: AttributeValue,
704
705 pub namespace: Option<&'static str>,
709
710 pub volatile: bool,
712}
713
714impl Attribute {
715 pub fn new<T>(
720 name: &'static str,
721 value: impl IntoAttributeValue<T>,
722 namespace: Option<&'static str>,
723 volatile: bool,
724 ) -> Attribute {
725 Attribute {
726 name,
727 namespace,
728 volatile,
729 value: value.into_value(),
730 }
731 }
732
733 pub(crate) fn deep_clone(&self) -> Self {
735 Attribute {
736 name: self.name,
737 namespace: self.namespace,
738 volatile: self.volatile,
739 value: self.value.clone(),
740 }
741 }
742}
743
744#[derive(Clone)]
749pub enum AttributeValue {
750 Text(String),
752
753 Float(f64),
755
756 Int(i64),
758
759 Bool(bool),
761
762 Listener(ListenerCallback),
764
765 Any(Rc<dyn AnyValue>),
767
768 None,
770}
771
772impl AttributeValue {
773 pub fn listener<T: 'static>(callback: impl FnMut(Event<T>) + 'static) -> AttributeValue {
777 AttributeValue::Listener(ListenerCallback::new(callback).erase())
778 }
779
780 pub fn any_value<T: AnyValue>(value: T) -> AttributeValue {
782 AttributeValue::Any(Rc::new(value))
783 }
784}
785
786impl std::fmt::Debug for AttributeValue {
787 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
788 match self {
789 Self::Text(arg0) => f.debug_tuple("Text").field(arg0).finish(),
790 Self::Float(arg0) => f.debug_tuple("Float").field(arg0).finish(),
791 Self::Int(arg0) => f.debug_tuple("Int").field(arg0).finish(),
792 Self::Bool(arg0) => f.debug_tuple("Bool").field(arg0).finish(),
793 Self::Listener(_) => f.debug_tuple("Listener").finish(),
794 Self::Any(_) => f.debug_tuple("Any").finish(),
795 Self::None => write!(f, "None"),
796 }
797 }
798}
799
800impl PartialEq for AttributeValue {
801 fn eq(&self, other: &Self) -> bool {
802 match (self, other) {
803 (Self::Text(l0), Self::Text(r0)) => l0 == r0,
804 (Self::Float(l0), Self::Float(r0)) => l0 == r0,
805 (Self::Int(l0), Self::Int(r0)) => l0 == r0,
806 (Self::Bool(l0), Self::Bool(r0)) => l0 == r0,
807 (Self::Listener(l0), Self::Listener(r0)) => l0 == r0,
808 (Self::Any(l0), Self::Any(r0)) => l0.as_ref().any_cmp(r0.as_ref()),
809 (Self::None, Self::None) => true,
810 _ => false,
811 }
812 }
813}
814
815#[doc(hidden)]
816pub trait AnyValue: 'static {
817 fn any_cmp(&self, other: &dyn AnyValue) -> bool;
818 fn as_any(&self) -> &dyn Any;
819 fn type_id(&self) -> TypeId {
820 self.as_any().type_id()
821 }
822}
823
824impl<T: Any + PartialEq + 'static> AnyValue for T {
825 fn any_cmp(&self, other: &dyn AnyValue) -> bool {
826 if let Some(other) = other.as_any().downcast_ref() {
827 self == other
828 } else {
829 false
830 }
831 }
832
833 fn as_any(&self) -> &dyn Any {
834 self
835 }
836}
837
838pub trait IntoDynNode<A = ()> {
840 fn into_dyn_node(self) -> DynamicNode;
842}
843
844impl IntoDynNode for () {
845 fn into_dyn_node(self) -> DynamicNode {
846 DynamicNode::default()
847 }
848}
849impl IntoDynNode for VNode {
850 fn into_dyn_node(self) -> DynamicNode {
851 DynamicNode::Fragment(vec![self])
852 }
853}
854impl IntoDynNode for DynamicNode {
855 fn into_dyn_node(self) -> DynamicNode {
856 self
857 }
858}
859impl<T: IntoDynNode> IntoDynNode for Option<T> {
860 fn into_dyn_node(self) -> DynamicNode {
861 match self {
862 Some(val) => val.into_dyn_node(),
863 None => DynamicNode::default(),
864 }
865 }
866}
867impl IntoDynNode for &Element {
868 fn into_dyn_node(self) -> DynamicNode {
869 match self.as_ref() {
870 Ok(val) => val.into_dyn_node(),
871 _ => DynamicNode::default(),
872 }
873 }
874}
875impl IntoDynNode for Element {
876 fn into_dyn_node(self) -> DynamicNode {
877 match self {
878 Ok(val) => val.into_dyn_node(),
879 _ => DynamicNode::default(),
880 }
881 }
882}
883impl IntoDynNode for &Option<VNode> {
884 fn into_dyn_node(self) -> DynamicNode {
885 match self.as_ref() {
886 Some(val) => val.clone().into_dyn_node(),
887 _ => DynamicNode::default(),
888 }
889 }
890}
891impl IntoDynNode for &str {
892 fn into_dyn_node(self) -> DynamicNode {
893 DynamicNode::Text(VText {
894 value: self.to_string(),
895 })
896 }
897}
898impl IntoDynNode for String {
899 fn into_dyn_node(self) -> DynamicNode {
900 DynamicNode::Text(VText { value: self })
901 }
902}
903impl IntoDynNode for Arguments<'_> {
904 fn into_dyn_node(self) -> DynamicNode {
905 DynamicNode::Text(VText {
906 value: self.to_string(),
907 })
908 }
909}
910impl IntoDynNode for &VNode {
911 fn into_dyn_node(self) -> DynamicNode {
912 DynamicNode::Fragment(vec![self.clone()])
913 }
914}
915
916pub trait IntoVNode {
917 fn into_vnode(self) -> VNode;
918}
919impl IntoVNode for VNode {
920 fn into_vnode(self) -> VNode {
921 self
922 }
923}
924impl IntoVNode for &VNode {
925 fn into_vnode(self) -> VNode {
926 self.clone()
927 }
928}
929impl IntoVNode for Element {
930 fn into_vnode(self) -> VNode {
931 match self {
932 Ok(val) => val.into_vnode(),
933 _ => VNode::default(),
934 }
935 }
936}
937impl IntoVNode for &Element {
938 fn into_vnode(self) -> VNode {
939 match self {
940 Ok(val) => val.into_vnode(),
941 _ => VNode::default(),
942 }
943 }
944}
945impl IntoVNode for Option<VNode> {
946 fn into_vnode(self) -> VNode {
947 match self {
948 Some(val) => val.into_vnode(),
949 _ => VNode::default(),
950 }
951 }
952}
953impl IntoVNode for &Option<VNode> {
954 fn into_vnode(self) -> VNode {
955 match self.as_ref() {
956 Some(val) => val.clone().into_vnode(),
957 _ => VNode::default(),
958 }
959 }
960}
961impl IntoVNode for Option<Element> {
962 fn into_vnode(self) -> VNode {
963 match self {
964 Some(val) => val.into_vnode(),
965 _ => VNode::default(),
966 }
967 }
968}
969impl IntoVNode for &Option<Element> {
970 fn into_vnode(self) -> VNode {
971 match self.as_ref() {
972 Some(val) => val.clone().into_vnode(),
973 _ => VNode::default(),
974 }
975 }
976}
977
978pub struct FromNodeIterator;
980impl<T, I> IntoDynNode<FromNodeIterator> for T
981where
982 T: Iterator<Item = I>,
983 I: IntoVNode,
984{
985 fn into_dyn_node(self) -> DynamicNode {
986 let children: Vec<_> = self.into_iter().map(|node| node.into_vnode()).collect();
987
988 if children.is_empty() {
989 DynamicNode::default()
990 } else {
991 DynamicNode::Fragment(children)
992 }
993 }
994}
995
996pub trait IntoAttributeValue<T = ()> {
998 fn into_value(self) -> AttributeValue;
1000}
1001
1002impl IntoAttributeValue for AttributeValue {
1003 fn into_value(self) -> AttributeValue {
1004 self
1005 }
1006}
1007
1008impl IntoAttributeValue for &str {
1009 fn into_value(self) -> AttributeValue {
1010 AttributeValue::Text(self.to_string())
1011 }
1012}
1013
1014impl IntoAttributeValue for String {
1015 fn into_value(self) -> AttributeValue {
1016 AttributeValue::Text(self)
1017 }
1018}
1019
1020impl IntoAttributeValue for f32 {
1021 fn into_value(self) -> AttributeValue {
1022 AttributeValue::Float(self as _)
1023 }
1024}
1025impl IntoAttributeValue for f64 {
1026 fn into_value(self) -> AttributeValue {
1027 AttributeValue::Float(self)
1028 }
1029}
1030
1031impl IntoAttributeValue for i8 {
1032 fn into_value(self) -> AttributeValue {
1033 AttributeValue::Int(self as _)
1034 }
1035}
1036impl IntoAttributeValue for i16 {
1037 fn into_value(self) -> AttributeValue {
1038 AttributeValue::Int(self as _)
1039 }
1040}
1041impl IntoAttributeValue for i32 {
1042 fn into_value(self) -> AttributeValue {
1043 AttributeValue::Int(self as _)
1044 }
1045}
1046impl IntoAttributeValue for i64 {
1047 fn into_value(self) -> AttributeValue {
1048 AttributeValue::Int(self)
1049 }
1050}
1051impl IntoAttributeValue for isize {
1052 fn into_value(self) -> AttributeValue {
1053 AttributeValue::Int(self as _)
1054 }
1055}
1056impl IntoAttributeValue for i128 {
1057 fn into_value(self) -> AttributeValue {
1058 AttributeValue::Int(self as _)
1059 }
1060}
1061
1062impl IntoAttributeValue for u8 {
1063 fn into_value(self) -> AttributeValue {
1064 AttributeValue::Int(self as _)
1065 }
1066}
1067impl IntoAttributeValue for u16 {
1068 fn into_value(self) -> AttributeValue {
1069 AttributeValue::Int(self as _)
1070 }
1071}
1072impl IntoAttributeValue for u32 {
1073 fn into_value(self) -> AttributeValue {
1074 AttributeValue::Int(self as _)
1075 }
1076}
1077impl IntoAttributeValue for u64 {
1078 fn into_value(self) -> AttributeValue {
1079 AttributeValue::Int(self as _)
1080 }
1081}
1082impl IntoAttributeValue for usize {
1083 fn into_value(self) -> AttributeValue {
1084 AttributeValue::Int(self as _)
1085 }
1086}
1087impl IntoAttributeValue for u128 {
1088 fn into_value(self) -> AttributeValue {
1089 AttributeValue::Int(self as _)
1090 }
1091}
1092
1093impl IntoAttributeValue for bool {
1094 fn into_value(self) -> AttributeValue {
1095 AttributeValue::Bool(self)
1096 }
1097}
1098
1099impl IntoAttributeValue for Arguments<'_> {
1100 fn into_value(self) -> AttributeValue {
1101 AttributeValue::Text(self.to_string())
1102 }
1103}
1104
1105impl IntoAttributeValue for Rc<dyn AnyValue> {
1106 fn into_value(self) -> AttributeValue {
1107 AttributeValue::Any(self)
1108 }
1109}
1110
1111impl<T> IntoAttributeValue for ListenerCallback<T> {
1112 fn into_value(self) -> AttributeValue {
1113 AttributeValue::Listener(self.erase())
1114 }
1115}
1116
1117impl<T: IntoAttributeValue> IntoAttributeValue for Option<T> {
1118 fn into_value(self) -> AttributeValue {
1119 match self {
1120 Some(val) => val.into_value(),
1121 None => AttributeValue::None,
1122 }
1123 }
1124}
1125
1126pub struct AnyFmtMarker;
1127impl<T> IntoAttributeValue<AnyFmtMarker> for T
1128where
1129 T: DioxusFormattable,
1130{
1131 fn into_value(self) -> AttributeValue {
1132 AttributeValue::Text(self.format().to_string())
1133 }
1134}
1135
1136pub trait HasAttributes {
1138 fn push_attribute<T>(
1140 self,
1141 name: &'static str,
1142 ns: Option<&'static str>,
1143 attr: impl IntoAttributeValue<T>,
1144 volatile: bool,
1145 ) -> Self;
1146}