1use crate::{
2 DynamicAnchor, DynamicNodeSlot, Element, Event, Properties, ScopeId, Template, VirtualDom,
3 arena::ElementId,
4 events::ListenerCallback,
5 innerlude::{BoxedAnyProps, MountId, ScopeState, VProps},
6 properties::ComponentFunction,
7 view::ViewExt,
8};
9use dioxus_core_types::DioxusFormattable;
10
11use std::ops::Deref;
12use std::rc::Rc;
13use std::{
14 any::{Any, TypeId},
15 fmt::{Arguments, Debug},
16};
17
18pub struct DynamicValues {
20 pub(crate) key: Option<String>,
22
23 pub(crate) dynamic_nodes: Vec<DynamicNode>,
25
26 pub(crate) dynamic_attrs: Vec<Box<[Attribute]>>,
28}
29
30impl Debug for DynamicValues {
31 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32 f.debug_struct("DynamicValues").finish_non_exhaustive()
33 }
34}
35
36impl DynamicValues {
37 #[inline]
43 pub fn from_parts(
44 key: Option<String>,
45 dynamic_nodes: Box<[DynamicNode]>,
46 dynamic_attrs: Box<[Box<[Attribute]>]>,
47 ) -> Self {
48 let mut values = Self {
49 key,
50 dynamic_nodes: dynamic_nodes.into_vec(),
51 dynamic_attrs: dynamic_attrs.into_vec(),
52 };
53 values.normalize();
54 values
55 }
56
57 pub(crate) fn new() -> Self {
59 Self {
60 key: None,
61 dynamic_nodes: Vec::new(),
62 dynamic_attrs: Vec::new(),
63 }
64 }
65
66 pub(crate) fn set_key(&mut self, key: Option<String>) {
68 self.key = key;
69 }
70
71 pub(crate) fn push_node(&mut self, value: DynamicNode) {
73 self.dynamic_nodes.push(value);
74 }
75
76 pub(crate) fn push_attrs(&mut self, value: Box<[Attribute]>) {
81 self.dynamic_attrs.push(value);
82 }
83
84 pub(crate) fn normalize(&mut self) {
86 for slot in self.dynamic_attrs.iter_mut() {
87 slot.sort_by_key(|attribute| (attribute.name, attribute.namespace));
88 }
89 }
90
91 #[inline]
93 pub fn key(&self) -> Option<&str> {
94 self.key.as_deref()
95 }
96
97 #[inline]
99 pub fn dynamic_node_values(&self) -> &[DynamicNode] {
100 &self.dynamic_nodes
101 }
102
103 #[inline]
105 pub fn dynamic_attr_values(&self) -> &[Box<[Attribute]>] {
106 &self.dynamic_attrs
107 }
108}
109
110pub(crate) struct VNodeInner {
112 pub template: Template,
114
115 pub view: DynamicValues,
117}
118
119impl Debug for VNodeInner {
120 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
121 f.debug_struct("VNodeInner").finish_non_exhaustive()
122 }
123}
124
125impl Deref for VNodeInner {
126 type Target = DynamicValues;
127
128 fn deref(&self) -> &Self::Target {
129 &self.view
130 }
131}
132
133#[derive(Clone)]
138pub struct VNode {
139 vnode: Rc<VNodeInner>,
140}
141
142impl Debug for VNode {
143 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
144 f.debug_struct("VNode").finish_non_exhaustive()
145 }
146}
147
148impl Default for VNode {
149 fn default() -> Self {
150 Self::placeholder()
151 }
152}
153
154impl PartialEq for VNode {
155 fn eq(&self, other: &Self) -> bool {
156 Rc::ptr_eq(&self.vnode, &other.vnode)
157 }
158}
159
160impl VNode {
161 pub fn template(&self) -> &Template {
163 &self.vnode.template
164 }
165
166 pub fn dynamic_values(&self) -> &DynamicValues {
168 &self.vnode.view
169 }
170
171 pub fn dynamic_node_values(&self) -> &[DynamicNode] {
173 self.dynamic_values().dynamic_node_values()
174 }
175
176 pub fn dynamic_attr_values(&self) -> &[Box<[Attribute]>] {
178 self.dynamic_values().dynamic_attr_values()
179 }
180
181 pub fn key(&self) -> Option<&str> {
183 self.dynamic_values().key()
184 }
185
186 pub fn empty() -> Element {
188 Ok(Self::default())
189 }
190
191 pub fn placeholder() -> Self {
193 use std::cell::OnceCell;
194 thread_local! {
196 static EMPTY_VNODE: OnceCell<VNode> = const { OnceCell::new() };
197 }
198 EMPTY_VNODE.with(|cell| {
199 cell.get_or_init(move || crate::view::fragment().into_vnode())
200 .clone()
201 })
202 }
203
204 pub fn new(template: Template, mut values: DynamicValues) -> Self {
206 values.normalize();
207
208 debug_assert!(
209 values.dynamic_nodes.len()
210 == template
211 .anchors()
212 .iter()
213 .map(|anchor| anchor.nodes().end)
214 .max()
215 .unwrap_or_default(),
216 "bad dynamic node count"
217 );
218 debug_assert!(
219 values.dynamic_attrs.len()
220 == template
221 .anchors()
222 .iter()
223 .map(|anchor| anchor.attributes().end)
224 .max()
225 .unwrap_or_default(),
226 "bad dynamic attribute count"
227 );
228
229 Self {
230 vnode: Rc::new(VNodeInner {
231 template,
232 view: values,
233 }),
234 }
235 }
236}
237
238#[derive(Clone, Copy, Debug)]
239pub struct MountedVNode<'a> {
241 vnode: &'a VNode,
242 mount: MountId,
243}
244
245impl<'a> MountedVNode<'a> {
246 pub(crate) const fn new(vnode: &'a VNode, mount: MountId) -> Self {
247 Self { vnode, mount }
248 }
249
250 pub(crate) const fn mount(self) -> MountId {
251 self.mount
252 }
253
254 pub const fn vnode(self) -> &'a VNode {
256 self.vnode
257 }
258
259 pub fn mounted_dynamic_node(
261 self,
262 slot: DynamicNodeSlot<'a>,
263 dom: &VirtualDom,
264 ) -> Option<ElementId> {
265 let dynamic_node_idx = slot.index();
266 match &self.vnode.dynamic_node_values()[dynamic_node_idx] {
267 DynamicNode::Text(_) => dom
268 .mounted_dynamic_text_node(self.mount, dynamic_node_idx)
269 .map(|id| id.element_id()),
270 _ => None,
271 }
272 }
273
274 pub fn mounted_anchor_node(
276 self,
277 anchor: DynamicAnchor<'a>,
278 dom: &VirtualDom,
279 ) -> Option<ElementId> {
280 dom.mounted_anchor_node(self.mount, anchor.anchor_index())
281 .map(|id| id.element_id())
282 }
283
284 pub fn mounted_static_anchor(self, anchor_idx: usize, dom: &VirtualDom) -> Option<ElementId> {
286 dom.mounted_anchor_node(self.mount, anchor_idx)
287 .map(|id| id.element_id())
288 }
289
290 pub fn mounted_fragment_children(
292 self,
293 slot: DynamicNodeSlot<'a>,
294 dom: &VirtualDom,
295 ) -> Vec<MountedVNode<'a>> {
296 let dynamic_node_idx = slot.index();
297 let DynamicNode::Fragment(children) = &self.vnode.dynamic_node_values()[dynamic_node_idx]
298 else {
299 return Vec::new();
300 };
301
302 children
303 .iter()
304 .zip(dom.mounted_fragment_children(self.mount, dynamic_node_idx, children.len()))
305 .map(|(vnode, mount)| MountedVNode::new(vnode, mount))
306 .collect()
307 }
308}
309
310impl Deref for MountedVNode<'_> {
311 type Target = VNode;
312
313 fn deref(&self) -> &Self::Target {
314 self.vnode
315 }
316}
317
318#[derive(Debug, Clone)]
322pub enum DynamicNode {
323 Component(VComponent),
331
332 Text(VText),
334
335 Fragment(Vec<VNode>),
340}
341
342impl DynamicNode {
343 pub fn make_node<'c, I>(into: impl IntoDynNode<I> + 'c) -> DynamicNode {
345 into.into_dyn_node()
346 }
347}
348
349impl Default for DynamicNode {
350 fn default() -> Self {
351 Self::Fragment(Vec::new())
352 }
353}
354
355pub struct VComponent {
357 pub name: &'static str,
359
360 pub(crate) render_fn: usize,
362
363 pub(crate) driver: Rc<dyn crate::render_driver::RenderDriver>,
365
366 pub(crate) props: BoxedAnyProps,
368}
369
370impl Clone for VComponent {
371 fn clone(&self) -> Self {
372 Self {
373 name: self.name,
374 render_fn: self.render_fn,
375 driver: self.driver.clone(),
376 props: self.props.duplicate(),
377 }
378 }
379}
380
381impl VComponent {
382 pub fn new<P, M: 'static>(
384 component: impl ComponentFunction<P, M>,
385 props: P,
386 fn_name: &'static str,
387 ) -> Self
388 where
389 P: Properties + 'static,
390 {
391 let render_fn = component.fn_ptr();
392 let props = Box::new(VProps::new(
393 component,
394 <P as Properties>::memoize,
395 props,
396 fn_name,
397 ));
398 Self::new_with_driver(
399 fn_name,
400 render_fn,
401 Rc::new(crate::render_driver::BodyDriver),
402 props,
403 )
404 }
405
406 pub(crate) fn new_with_driver(
408 fn_name: &'static str,
409 render_fn: usize,
410 driver: Rc<dyn crate::render_driver::RenderDriver>,
411 props: BoxedAnyProps,
412 ) -> Self {
413 VComponent {
414 name: fn_name,
415 render_fn,
416 driver,
417 props,
418 }
419 }
420
421 pub fn mounted_scope_id(
427 &self,
428 slot: DynamicNodeSlot<'_>,
429 vnode: MountedVNode<'_>,
430 dom: &VirtualDom,
431 ) -> Option<ScopeId> {
432 dom.mounted_dynamic_component_scope(vnode.mount(), slot.index())
433 }
434
435 pub fn mounted_scope<'a>(
441 &self,
442 slot: DynamicNodeSlot<'_>,
443 vnode: MountedVNode<'_>,
444 dom: &'a VirtualDom,
445 ) -> Option<&'a ScopeState> {
446 let scope_id = dom.mounted_dynamic_component_scope(vnode.mount(), slot.index())?;
447
448 dom.scopes.get(scope_id.index())
449 }
450}
451
452impl std::fmt::Debug for VComponent {
453 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
454 f.debug_struct("VComponent")
455 .field("name", &self.name)
456 .finish()
457 }
458}
459
460#[derive(Clone, Debug)]
462pub struct VText {
463 pub value: String,
465}
466
467impl VText {
468 #[inline]
470 pub fn new(value: impl ToString) -> Self {
471 Self {
472 value: value.to_string(),
473 }
474 }
475}
476
477impl From<Arguments<'_>> for VText {
478 fn from(args: Arguments) -> Self {
479 Self::new(args.to_string())
480 }
481}
482
483#[derive(Debug, Clone, PartialEq)]
485pub struct Attribute {
486 pub name: &'static str,
488
489 pub value: AttributeValue,
491
492 pub namespace: Option<&'static str>,
496
497 pub volatile: bool,
499}
500
501impl Attribute {
502 pub fn new<T>(
507 name: &'static str,
508 value: impl IntoAttributeValue<T>,
509 namespace: Option<&'static str>,
510 volatile: bool,
511 ) -> Attribute {
512 Attribute {
513 name,
514 namespace,
515 volatile,
516 value: value.into_value(),
517 }
518 }
519}
520
521#[derive(Clone)]
526pub enum AttributeValue {
527 Text(String),
529
530 Float(f64),
532
533 Int(i64),
535
536 Bool(bool),
538
539 Listener(ListenerCallback),
541
542 Any(Rc<dyn AnyValue>),
544
545 None,
547}
548
549impl AttributeValue {
550 pub fn listener<T: 'static>(callback: impl FnMut(Event<T>) + 'static) -> AttributeValue {
554 AttributeValue::Listener(ListenerCallback::new(callback).erase())
555 }
556
557 pub fn any_value<T: AnyValue>(value: T) -> AttributeValue {
559 AttributeValue::Any(Rc::new(value))
560 }
561}
562
563impl std::fmt::Debug for AttributeValue {
564 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
565 match self {
566 Self::Text(arg0) => f.debug_tuple("Text").field(arg0).finish(),
567 Self::Float(arg0) => f.debug_tuple("Float").field(arg0).finish(),
568 Self::Int(arg0) => f.debug_tuple("Int").field(arg0).finish(),
569 Self::Bool(arg0) => f.debug_tuple("Bool").field(arg0).finish(),
570 Self::Listener(_) => f.debug_tuple("Listener").finish(),
571 Self::Any(_) => f.debug_tuple("Any").finish(),
572 Self::None => write!(f, "None"),
573 }
574 }
575}
576
577impl PartialEq for AttributeValue {
578 fn eq(&self, other: &Self) -> bool {
579 match (self, other) {
580 (Self::Text(l0), Self::Text(r0)) => l0 == r0,
581 (Self::Float(l0), Self::Float(r0)) => l0 == r0,
582 (Self::Int(l0), Self::Int(r0)) => l0 == r0,
583 (Self::Bool(l0), Self::Bool(r0)) => l0 == r0,
584 (Self::Listener(l0), Self::Listener(r0)) => l0 == r0,
585 (Self::Any(l0), Self::Any(r0)) => l0.as_ref().any_cmp(r0.as_ref()),
586 (Self::None, Self::None) => true,
587 _ => false,
588 }
589 }
590}
591
592#[doc(hidden)]
593pub trait AnyValue: 'static {
594 fn any_cmp(&self, other: &dyn AnyValue) -> bool;
596
597 fn as_any(&self) -> &dyn Any;
599
600 fn type_id(&self) -> TypeId {
602 self.as_any().type_id()
603 }
604}
605
606impl<T: Any + PartialEq + 'static> AnyValue for T {
607 fn any_cmp(&self, other: &dyn AnyValue) -> bool {
608 if let Some(other) = other.as_any().downcast_ref() {
609 self == other
610 } else {
611 false
612 }
613 }
614
615 fn as_any(&self) -> &dyn Any {
616 self
617 }
618}
619
620pub trait IntoDynNode<A = ()> {
622 fn into_dyn_node(self) -> DynamicNode;
624}
625
626impl IntoDynNode for () {
627 #[inline]
628 fn into_dyn_node(self) -> DynamicNode {
629 DynamicNode::default()
630 }
631}
632impl IntoDynNode for VNode {
633 #[inline]
634 fn into_dyn_node(self) -> DynamicNode {
635 DynamicNode::Fragment(vec![self])
636 }
637}
638impl IntoDynNode for DynamicNode {
639 #[inline]
640 fn into_dyn_node(self) -> DynamicNode {
641 self
642 }
643}
644impl<T: IntoDynNode> IntoDynNode for Option<T> {
645 #[inline]
646 fn into_dyn_node(self) -> DynamicNode {
647 match self {
648 Some(val) => val.into_dyn_node(),
649 None => DynamicNode::default(),
650 }
651 }
652}
653impl IntoDynNode for &Element {
654 #[inline]
655 fn into_dyn_node(self) -> DynamicNode {
656 match self.as_ref() {
657 Ok(val) => val.into_dyn_node(),
658 _ => DynamicNode::default(),
659 }
660 }
661}
662impl IntoDynNode for Element {
663 #[inline]
664 fn into_dyn_node(self) -> DynamicNode {
665 match self {
666 Ok(val) => val.into_dyn_node(),
667 _ => DynamicNode::default(),
668 }
669 }
670}
671impl IntoDynNode for &Option<VNode> {
672 #[inline]
673 fn into_dyn_node(self) -> DynamicNode {
674 match self.as_ref() {
675 Some(val) => val.clone().into_dyn_node(),
676 _ => DynamicNode::default(),
677 }
678 }
679}
680impl IntoDynNode for &str {
681 #[inline]
682 fn into_dyn_node(self) -> DynamicNode {
683 DynamicNode::Text(VText {
684 value: self.to_string(),
685 })
686 }
687}
688impl IntoDynNode for String {
689 #[inline]
690 fn into_dyn_node(self) -> DynamicNode {
691 DynamicNode::Text(VText { value: self })
692 }
693}
694impl IntoDynNode for Arguments<'_> {
695 #[inline]
696 fn into_dyn_node(self) -> DynamicNode {
697 DynamicNode::Text(VText {
698 value: self.to_string(),
699 })
700 }
701}
702impl IntoDynNode for &VNode {
703 #[inline]
704 fn into_dyn_node(self) -> DynamicNode {
705 DynamicNode::Fragment(vec![self.clone()])
706 }
707}
708
709pub trait IntoVNode {
711 fn into_vnode(self) -> VNode;
713}
714impl IntoVNode for VNode {
715 #[inline]
716 fn into_vnode(self) -> VNode {
717 self
718 }
719}
720impl IntoVNode for &VNode {
721 #[inline]
722 fn into_vnode(self) -> VNode {
723 self.clone()
724 }
725}
726impl IntoVNode for Element {
727 #[inline]
728 fn into_vnode(self) -> VNode {
729 match self {
730 Ok(val) => val.into_vnode(),
731 _ => VNode::default(),
732 }
733 }
734}
735impl IntoVNode for &Element {
736 #[inline]
737 fn into_vnode(self) -> VNode {
738 match self {
739 Ok(val) => val.into_vnode(),
740 _ => VNode::default(),
741 }
742 }
743}
744impl IntoVNode for Option<VNode> {
745 #[inline]
746 fn into_vnode(self) -> VNode {
747 match self {
748 Some(val) => val.into_vnode(),
749 _ => VNode::default(),
750 }
751 }
752}
753impl IntoVNode for &Option<VNode> {
754 #[inline]
755 fn into_vnode(self) -> VNode {
756 match self.as_ref() {
757 Some(val) => val.clone().into_vnode(),
758 _ => VNode::default(),
759 }
760 }
761}
762impl IntoVNode for Option<Element> {
763 #[inline]
764 fn into_vnode(self) -> VNode {
765 match self {
766 Some(val) => val.into_vnode(),
767 _ => VNode::default(),
768 }
769 }
770}
771impl IntoVNode for &Option<Element> {
772 #[inline]
773 fn into_vnode(self) -> VNode {
774 match self.as_ref() {
775 Some(val) => val.clone().into_vnode(),
776 _ => VNode::default(),
777 }
778 }
779}
780
781pub struct FromNodeIterator;
783impl<T, I> IntoDynNode<FromNodeIterator> for T
784where
785 T: Iterator<Item = I>,
786 I: IntoVNode,
787{
788 #[inline]
789 fn into_dyn_node(self) -> DynamicNode {
790 DynamicNode::Fragment(self.into_iter().map(|node| node.into_vnode()).collect())
791 }
792}
793
794pub trait IntoAttributeValue<T = ()> {
796 fn into_value(self) -> AttributeValue;
798}
799
800impl IntoAttributeValue for AttributeValue {
801 fn into_value(self) -> AttributeValue {
802 self
803 }
804}
805
806impl IntoAttributeValue for &str {
807 fn into_value(self) -> AttributeValue {
808 AttributeValue::Text(self.to_string())
809 }
810}
811
812impl IntoAttributeValue for String {
813 fn into_value(self) -> AttributeValue {
814 AttributeValue::Text(self)
815 }
816}
817
818macro_rules! impl_float_attribute_value {
819 ($($ty:ty),* $(,)?) => {
820 $(
821 impl IntoAttributeValue for $ty {
822 fn into_value(self) -> AttributeValue {
823 AttributeValue::Float(self as _)
824 }
825 }
826 )*
827 };
828}
829
830macro_rules! impl_int_attribute_value {
831 ($($ty:ty),* $(,)?) => {
832 $(
833 impl IntoAttributeValue for $ty {
834 fn into_value(self) -> AttributeValue {
835 AttributeValue::Int(self as _)
836 }
837 }
838 )*
839 };
840}
841
842impl_float_attribute_value!(f32, f64);
843impl_int_attribute_value!(i8, i16, i32, i64, isize, i128);
844impl_int_attribute_value!(u8, u16, u32, u64, usize, u128);
845
846impl IntoAttributeValue for bool {
847 fn into_value(self) -> AttributeValue {
848 AttributeValue::Bool(self)
849 }
850}
851
852impl IntoAttributeValue for Arguments<'_> {
853 fn into_value(self) -> AttributeValue {
854 AttributeValue::Text(self.to_string())
855 }
856}
857
858impl IntoAttributeValue for Rc<dyn AnyValue> {
859 fn into_value(self) -> AttributeValue {
860 AttributeValue::Any(self)
861 }
862}
863
864impl<T> IntoAttributeValue for ListenerCallback<T> {
865 fn into_value(self) -> AttributeValue {
866 AttributeValue::Listener(self.erase())
867 }
868}
869
870impl<T: IntoAttributeValue> IntoAttributeValue for Option<T> {
871 fn into_value(self) -> AttributeValue {
872 match self {
873 Some(val) => val.into_value(),
874 None => AttributeValue::None,
875 }
876 }
877}
878
879impl<T: ToOwned<Owned = R>, R: IntoAttributeValue> IntoAttributeValue for &T {
880 fn into_value(self) -> AttributeValue {
881 self.to_owned().into_value()
882 }
883}
884
885#[doc(hidden)]
886pub struct AnyFmtMarker;
887impl<T> IntoAttributeValue<AnyFmtMarker> for T
888where
889 T: DioxusFormattable,
890{
891 fn into_value(self) -> AttributeValue {
892 AttributeValue::Text(self.format().to_string())
893 }
894}
895
896pub trait HasAttributes {
898 fn push_attribute<T>(
900 self,
901 name: &'static str,
902 ns: Option<&'static str>,
903 attr: impl IntoAttributeValue<T>,
904 volatile: bool,
905 ) -> Self;
906}