nodes.rs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850
  1. use crate::any_props::{BoxedAnyProps, VProps};
  2. use crate::innerlude::{ElementRef, EventHandler};
  3. use crate::Properties;
  4. use crate::{arena::ElementId, Element, Event, ScopeId};
  5. use std::cell::RefCell;
  6. use std::ops::Deref;
  7. use std::rc::Rc;
  8. use std::vec;
  9. use std::{
  10. any::{Any, TypeId},
  11. cell::Cell,
  12. fmt::{Arguments, Debug},
  13. };
  14. pub type TemplateId = &'static str;
  15. /// The actual state of the component's most recent computation
  16. ///
  17. /// Because Dioxus accepts components in the form of `async fn(Scope) -> Result<VNode>`, we need to support both
  18. /// sync and async versions.
  19. ///
  20. /// Dioxus will do its best to immediately resolve any async components into a regular Element, but as an implementor
  21. /// you might need to handle the case where there's no node immediately ready.
  22. #[derive(Clone)]
  23. pub enum RenderReturn {
  24. /// A currently-available element
  25. Ready(VNode),
  26. /// The component aborted rendering early. It might've thrown an error.
  27. ///
  28. /// In its place we've produced a placeholder to locate its spot in the dom when it recovers.
  29. Aborted(VNode),
  30. }
  31. impl Default for RenderReturn {
  32. fn default() -> Self {
  33. RenderReturn::Aborted(VNode::placeholder())
  34. }
  35. }
  36. impl Deref for RenderReturn {
  37. type Target = VNode;
  38. fn deref(&self) -> &Self::Target {
  39. match self {
  40. RenderReturn::Ready(node) | RenderReturn::Aborted(node) => node,
  41. }
  42. }
  43. }
  44. /// The information about the
  45. #[derive(Debug)]
  46. pub(crate) struct VNodeMount {
  47. /// The parent of this node
  48. pub parent: Option<ElementRef>,
  49. /// The IDs for the roots of this template - to be used when moving the template around and removing it from
  50. /// the actual Dom
  51. pub root_ids: Box<[ElementId]>,
  52. /// The element in the DOM that each attribute is mounted to
  53. pub(crate) mounted_attributes: Box<[ElementId]>,
  54. /// For components: This is the ScopeId the component is mounted to
  55. /// For other dynamic nodes: This is element in the DOM that each dynamic node is mounted to
  56. pub(crate) mounted_dynamic_nodes: Box<[usize]>,
  57. }
  58. /// A reference to a template along with any context needed to hydrate it
  59. ///
  60. /// The dynamic parts of the template are stored separately from the static parts. This allows faster diffing by skipping
  61. /// static parts of the template.
  62. #[derive(Debug)]
  63. pub struct VNodeInner {
  64. /// The key given to the root of this template.
  65. ///
  66. /// In fragments, this is the key of the first child. In other cases, it is the key of the root.
  67. pub key: Option<String>,
  68. /// The static nodes and static descriptor of the template
  69. pub template: Cell<Template>,
  70. /// The dynamic parts of the template
  71. pub dynamic_nodes: Box<[DynamicNode]>,
  72. /// The dynamic parts of the template
  73. pub dynamic_attrs: Box<[Attribute]>,
  74. }
  75. /// A reference to a template along with any context needed to hydrate it
  76. ///
  77. /// The dynamic parts of the template are stored separately from the static parts. This allows faster diffing by skipping
  78. /// static parts of the template.
  79. #[derive(Debug)]
  80. pub struct VNode {
  81. vnode: Rc<VNodeInner>,
  82. /// The mount information for this template
  83. pub(crate) mount: Rc<RefCell<Option<VNodeMount>>>,
  84. }
  85. impl Clone for VNode {
  86. fn clone(&self) -> Self {
  87. Self {
  88. vnode: self.vnode.clone(),
  89. mount: Default::default(),
  90. }
  91. }
  92. }
  93. impl PartialEq for VNode {
  94. fn eq(&self, other: &Self) -> bool {
  95. Rc::ptr_eq(&self.vnode, &other.vnode)
  96. }
  97. }
  98. impl Deref for VNode {
  99. type Target = VNodeInner;
  100. fn deref(&self) -> &Self::Target {
  101. &self.vnode
  102. }
  103. }
  104. impl VNode {
  105. /// Clone the element while retaining the mounted parent of the node
  106. pub(crate) fn clone_with_parent(&self) -> Self {
  107. Self {
  108. vnode: self.vnode.clone(),
  109. mount: self.mount.clone(),
  110. }
  111. }
  112. /// Try to get the parent of this node
  113. ///
  114. /// This will fail if the VNode is not mounted
  115. pub(crate) fn parent(&self) -> Option<ElementRef> {
  116. self.mount.borrow().as_ref()?.parent.clone()
  117. }
  118. /// Create a template with no nodes that will be skipped over during diffing
  119. pub fn empty() -> Element {
  120. Some(Self {
  121. vnode: Rc::new(VNodeInner {
  122. key: None,
  123. dynamic_nodes: Box::new([]),
  124. dynamic_attrs: Box::new([]),
  125. template: Cell::new(Template {
  126. name: "dioxus-empty",
  127. roots: &[],
  128. node_paths: &[],
  129. attr_paths: &[],
  130. }),
  131. }),
  132. mount: Default::default(),
  133. })
  134. }
  135. /// Create a template with a single placeholder node
  136. pub fn placeholder() -> Self {
  137. Self {
  138. vnode: Rc::new(VNodeInner {
  139. key: None,
  140. dynamic_nodes: Box::new([DynamicNode::Placeholder(Default::default())]),
  141. dynamic_attrs: Box::new([]),
  142. template: Cell::new(Template {
  143. name: "dioxus-placeholder",
  144. roots: &[TemplateNode::Dynamic { id: 0 }],
  145. node_paths: &[&[]],
  146. attr_paths: &[],
  147. }),
  148. }),
  149. mount: Default::default(),
  150. }
  151. }
  152. /// Create a new VNode
  153. pub fn new(
  154. key: Option<String>,
  155. template: Template,
  156. dynamic_nodes: Box<[DynamicNode]>,
  157. dynamic_attrs: Box<[Attribute]>,
  158. ) -> Self {
  159. Self {
  160. vnode: Rc::new(VNodeInner {
  161. key,
  162. template: Cell::new(template),
  163. dynamic_nodes,
  164. dynamic_attrs,
  165. }),
  166. mount: Default::default(),
  167. }
  168. }
  169. /// Load a dynamic root at the given index
  170. ///
  171. /// Returns [`None`] if the root is actually a static node (Element/Text)
  172. pub fn dynamic_root(&self, idx: usize) -> Option<&DynamicNode> {
  173. match &self.template.get().roots[idx] {
  174. TemplateNode::Element { .. } | TemplateNode::Text { text: _ } => None,
  175. TemplateNode::Dynamic { id } | TemplateNode::DynamicText { id } => {
  176. Some(&self.dynamic_nodes[*id])
  177. }
  178. }
  179. }
  180. }
  181. /// A static layout of a UI tree that describes a set of dynamic and static nodes.
  182. ///
  183. /// This is the core innovation in Dioxus. Most UIs are made of static nodes, yet participate in diffing like any
  184. /// dynamic node. This struct can be created at compile time. It promises that its name is unique, allow Dioxus to use
  185. /// its static description of the UI to skip immediately to the dynamic nodes during diffing.
  186. ///
  187. /// For this to work properly, the [`Template::name`] *must* be unique across your entire project. This can be done via variety of
  188. /// ways, with the suggested approach being the unique code location (file, line, col, etc).
  189. #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
  190. #[derive(Debug, Clone, Copy, PartialEq, Hash, Eq, PartialOrd, Ord)]
  191. pub struct Template {
  192. /// The name of the template. This must be unique across your entire program for template diffing to work properly
  193. ///
  194. /// If two templates have the same name, it's likely that Dioxus will panic when diffing.
  195. #[cfg_attr(
  196. feature = "serialize",
  197. serde(deserialize_with = "deserialize_string_leaky")
  198. )]
  199. pub name: &'static str,
  200. /// The list of template nodes that make up the template
  201. ///
  202. /// Unlike react, calls to `rsx!` can have multiple roots. This list supports that paradigm.
  203. #[cfg_attr(feature = "serialize", serde(deserialize_with = "deserialize_leaky"))]
  204. pub roots: &'static [TemplateNode],
  205. /// The paths of each node relative to the root of the template.
  206. ///
  207. /// These will be one segment shorter than the path sent to the renderer since those paths are relative to the
  208. /// topmost element, not the `roots` field.
  209. #[cfg_attr(
  210. feature = "serialize",
  211. serde(deserialize_with = "deserialize_bytes_leaky")
  212. )]
  213. pub node_paths: &'static [&'static [u8]],
  214. /// The paths of each dynamic attribute relative to the root of the template
  215. ///
  216. /// These will be one segment shorter than the path sent to the renderer since those paths are relative to the
  217. /// topmost element, not the `roots` field.
  218. #[cfg_attr(
  219. feature = "serialize",
  220. serde(deserialize_with = "deserialize_bytes_leaky")
  221. )]
  222. pub attr_paths: &'static [&'static [u8]],
  223. }
  224. #[cfg(feature = "serialize")]
  225. fn deserialize_string_leaky<'a, 'de, D>(deserializer: D) -> Result<&'a str, D::Error>
  226. where
  227. D: serde::Deserializer<'de>,
  228. {
  229. use serde::Deserialize;
  230. let deserialized = String::deserialize(deserializer)?;
  231. Ok(&*Box::leak(deserialized.into_boxed_str()))
  232. }
  233. #[cfg(feature = "serialize")]
  234. fn deserialize_bytes_leaky<'a, 'de, D>(deserializer: D) -> Result<&'a [&'a [u8]], D::Error>
  235. where
  236. D: serde::Deserializer<'de>,
  237. {
  238. use serde::Deserialize;
  239. let deserialized = Vec::<Vec<u8>>::deserialize(deserializer)?;
  240. let deserialized = deserialized
  241. .into_iter()
  242. .map(|v| &*Box::leak(v.into_boxed_slice()))
  243. .collect::<Vec<_>>();
  244. Ok(&*Box::leak(deserialized.into_boxed_slice()))
  245. }
  246. #[cfg(feature = "serialize")]
  247. fn deserialize_leaky<'a, 'de, T: serde::Deserialize<'de>, D>(
  248. deserializer: D,
  249. ) -> Result<&'a [T], D::Error>
  250. where
  251. T: serde::Deserialize<'de>,
  252. D: serde::Deserializer<'de>,
  253. {
  254. use serde::Deserialize;
  255. let deserialized = Box::<[T]>::deserialize(deserializer)?;
  256. Ok(&*Box::leak(deserialized))
  257. }
  258. #[cfg(feature = "serialize")]
  259. fn deserialize_option_leaky<'a, 'de, D>(deserializer: D) -> Result<Option<&'static str>, D::Error>
  260. where
  261. D: serde::Deserializer<'de>,
  262. {
  263. use serde::Deserialize;
  264. let deserialized = Option::<String>::deserialize(deserializer)?;
  265. Ok(deserialized.map(|deserialized| &*Box::leak(deserialized.into_boxed_str())))
  266. }
  267. impl Template {
  268. /// Is this template worth caching at all, since it's completely runtime?
  269. ///
  270. /// There's no point in saving templates that are completely dynamic, since they'll be recreated every time anyway.
  271. pub fn is_completely_dynamic(&self) -> bool {
  272. use TemplateNode::*;
  273. self.roots
  274. .iter()
  275. .all(|root| matches!(root, Dynamic { .. } | DynamicText { .. }))
  276. }
  277. }
  278. /// A statically known node in a layout.
  279. ///
  280. /// This can be created at compile time, saving the VirtualDom time when diffing the tree
  281. #[derive(Debug, Clone, Copy, PartialEq, Hash, Eq, PartialOrd, Ord)]
  282. #[cfg_attr(
  283. feature = "serialize",
  284. derive(serde::Serialize, serde::Deserialize),
  285. serde(tag = "type")
  286. )]
  287. pub enum TemplateNode {
  288. /// An statically known element in the dom.
  289. ///
  290. /// In HTML this would be something like `<div id="123"> </div>`
  291. Element {
  292. /// The name of the element
  293. ///
  294. /// IE for a div, it would be the string "div"
  295. tag: &'static str,
  296. /// The namespace of the element
  297. ///
  298. /// In HTML, this would be a valid URI that defines a namespace for all elements below it
  299. /// SVG is an example of this namespace
  300. #[cfg_attr(
  301. feature = "serialize",
  302. serde(deserialize_with = "deserialize_option_leaky")
  303. )]
  304. namespace: Option<&'static str>,
  305. /// A list of possibly dynamic attributes for this element
  306. ///
  307. /// An attribute on a DOM node, such as `id="my-thing"` or `href="https://example.com"`.
  308. #[cfg_attr(feature = "serialize", serde(deserialize_with = "deserialize_leaky"))]
  309. attrs: &'static [TemplateAttribute],
  310. /// A list of template nodes that define another set of template nodes
  311. #[cfg_attr(feature = "serialize", serde(deserialize_with = "deserialize_leaky"))]
  312. children: &'static [TemplateNode],
  313. },
  314. /// This template node is just a piece of static text
  315. Text {
  316. /// The actual text
  317. text: &'static str,
  318. },
  319. /// This template node is unknown, and needs to be created at runtime.
  320. Dynamic {
  321. /// The index of the dynamic node in the VNode's dynamic_nodes list
  322. id: usize,
  323. },
  324. /// This template node is known to be some text, but needs to be created at runtime
  325. ///
  326. /// This is separate from the pure Dynamic variant for various optimizations
  327. DynamicText {
  328. /// The index of the dynamic node in the VNode's dynamic_nodes list
  329. id: usize,
  330. },
  331. }
  332. impl TemplateNode {
  333. /// Try to load the dynamic node at the given index
  334. pub fn dynamic_id(&self) -> Option<usize> {
  335. use TemplateNode::*;
  336. match self {
  337. Dynamic { id } | DynamicText { id } => Some(*id),
  338. _ => None,
  339. }
  340. }
  341. }
  342. /// A node created at runtime
  343. ///
  344. /// This node's index in the DynamicNode list on VNode should match its repsective `Dynamic` index
  345. #[derive(Debug)]
  346. pub enum DynamicNode {
  347. /// A component node
  348. ///
  349. /// Most of the time, Dioxus will actually know which component this is as compile time, but the props and
  350. /// assigned scope are dynamic.
  351. ///
  352. /// The actual VComponent can be dynamic between two VNodes, though, allowing implementations to swap
  353. /// the render function at runtime
  354. Component(VComponent),
  355. /// A text node
  356. Text(VText),
  357. /// A placeholder
  358. ///
  359. /// Used by suspense when a node isn't ready and by fragments that don't render anything
  360. ///
  361. /// In code, this is just an ElementId whose initial value is set to 0 upon creation
  362. Placeholder(VPlaceholder),
  363. /// A list of VNodes.
  364. ///
  365. /// Note that this is not a list of dynamic nodes. These must be VNodes and created through conditional rendering
  366. /// or iterators.
  367. Fragment(Vec<VNode>),
  368. }
  369. impl DynamicNode {
  370. /// Convert any item that implements [`IntoDynNode`] into a [`DynamicNode`]
  371. pub fn make_node<'c, I>(into: impl IntoDynNode<I> + 'c) -> DynamicNode {
  372. into.into_dyn_node()
  373. }
  374. }
  375. impl Default for DynamicNode {
  376. fn default() -> Self {
  377. Self::Placeholder(Default::default())
  378. }
  379. }
  380. #[derive(Clone)]
  381. /// An instance of a child component
  382. pub struct VComponent {
  383. /// The name of this component
  384. pub name: &'static str,
  385. /// The function pointer of the component, known at compile time
  386. ///
  387. /// It is possible that components get folded at compile time, so these shouldn't be really used as a key
  388. pub(crate) render_fn: *const (),
  389. pub(crate) props: BoxedAnyProps,
  390. }
  391. impl VComponent {
  392. /// Create a new [`VComponent`] variant
  393. ///
  394. ///
  395. /// The given component can be any of four signatures. Remember that an [`Element`] is really a [`Result<VNode>`].
  396. ///
  397. /// ```rust, ignore
  398. /// // Without explicit props
  399. /// fn(Scope) -> Element;
  400. /// async fn(Scope<'_>) -> Element;
  401. ///
  402. /// // With explicit props
  403. /// fn(Scope<Props>) -> Element;
  404. /// async fn(Scope<Props<'_>>) -> Element;
  405. /// ```
  406. pub fn new<P>(component: fn(P) -> Element, props: P, fn_name: &'static str) -> Self
  407. where
  408. // The properties must be valid until the next bump frame
  409. P: Properties,
  410. {
  411. let vcomp = VProps::new(component, P::memoize, props, fn_name);
  412. VComponent {
  413. name: fn_name,
  414. render_fn: component as *const (),
  415. props: BoxedAnyProps::new(vcomp),
  416. }
  417. }
  418. }
  419. impl std::fmt::Debug for VComponent {
  420. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  421. f.debug_struct("VComponent")
  422. .field("name", &self.name)
  423. .finish()
  424. }
  425. }
  426. /// A text node
  427. #[derive(Clone, Debug)]
  428. pub struct VText {
  429. /// The actual text itself
  430. pub value: String,
  431. }
  432. impl VText {
  433. /// Create a new VText
  434. pub fn new(value: String) -> Self {
  435. Self { value }
  436. }
  437. }
  438. impl From<Arguments<'_>> for VText {
  439. fn from(args: Arguments) -> Self {
  440. Self::new(args.to_string())
  441. }
  442. }
  443. /// A placeholder node, used by suspense and fragments
  444. #[derive(Clone, Debug, Default)]
  445. #[non_exhaustive]
  446. pub struct VPlaceholder {}
  447. /// An attribute of the TemplateNode, created at compile time
  448. #[derive(Debug, PartialEq, Hash, Eq, PartialOrd, Ord)]
  449. #[cfg_attr(
  450. feature = "serialize",
  451. derive(serde::Serialize, serde::Deserialize),
  452. serde(tag = "type")
  453. )]
  454. pub enum TemplateAttribute {
  455. /// This attribute is entirely known at compile time, enabling
  456. Static {
  457. /// The name of this attribute.
  458. ///
  459. /// For example, the `href` attribute in `href="https://example.com"`, would have the name "href"
  460. name: &'static str,
  461. /// The value of this attribute, known at compile time
  462. ///
  463. /// Currently this only accepts &str, so values, even if they're known at compile time, are not known
  464. value: &'static str,
  465. /// The namespace of this attribute. Does not exist in the HTML spec
  466. namespace: Option<&'static str>,
  467. },
  468. /// The attribute in this position is actually determined dynamically at runtime
  469. ///
  470. /// This is the index into the dynamic_attributes field on the container VNode
  471. Dynamic {
  472. /// The index
  473. id: usize,
  474. },
  475. }
  476. /// An attribute on a DOM node, such as `id="my-thing"` or `href="https://example.com"`
  477. #[derive(Debug)]
  478. pub struct Attribute {
  479. /// The name of the attribute.
  480. pub name: &'static str,
  481. /// The value of the attribute
  482. pub value: AttributeValue,
  483. /// The namespace of the attribute.
  484. ///
  485. /// Doesn’t exist in the html spec. Used in Dioxus to denote “style” tags and other attribute groups.
  486. pub namespace: Option<&'static str>,
  487. /// An indication of we should always try and set the attribute. Used in controlled components to ensure changes are propagated
  488. pub volatile: bool,
  489. }
  490. impl Attribute {
  491. /// Create a new [`Attribute`] from a name, value, namespace, and volatile bool
  492. ///
  493. /// "Volatile" referes to whether or not Dioxus should always override the value. This helps prevent the UI in
  494. /// some renderers stay in sync with the VirtualDom's understanding of the world
  495. pub fn new(
  496. name: &'static str,
  497. value: impl IntoAttributeValue,
  498. namespace: Option<&'static str>,
  499. volatile: bool,
  500. ) -> Attribute {
  501. Attribute {
  502. name,
  503. namespace,
  504. volatile,
  505. value: value.into_value(),
  506. }
  507. }
  508. }
  509. /// Any of the built-in values that the Dioxus VirtualDom supports as dynamic attributes on elements
  510. ///
  511. /// These are built-in to be faster during the diffing process. To use a custom value, use the [`AttributeValue::Any`]
  512. /// variant.
  513. pub enum AttributeValue {
  514. /// Text attribute
  515. Text(String),
  516. /// A float
  517. Float(f64),
  518. /// Signed integer
  519. Int(i64),
  520. /// Boolean
  521. Bool(bool),
  522. /// A listener, like "onclick"
  523. Listener(ListenerCb),
  524. /// An arbitrary value that implements PartialEq and is static
  525. Any(Box<dyn AnyValue>),
  526. /// A "none" value, resulting in the removal of an attribute from the dom
  527. None,
  528. }
  529. impl AttributeValue {
  530. /// Create a new [`AttributeValue`] with the listener variant from a callback
  531. ///
  532. /// The callback must be confined to the lifetime of the ScopeState
  533. pub fn listener<T: 'static>(mut callback: impl FnMut(Event<T>) + 'static) -> AttributeValue {
  534. AttributeValue::Listener(EventHandler::new(move |event: Event<dyn Any>| {
  535. if let Ok(data) = event.data.downcast::<T>() {
  536. callback(Event {
  537. propagates: event.propagates,
  538. data,
  539. });
  540. }
  541. }))
  542. }
  543. /// Create a new [`AttributeValue`] with a value that implements [`AnyValue`]
  544. pub fn any_value<T: AnyValue>(&self, value: T) -> AttributeValue {
  545. AttributeValue::Any(Box::new(value))
  546. }
  547. }
  548. pub type ListenerCb = EventHandler<Event<dyn Any>>;
  549. impl std::fmt::Debug for AttributeValue {
  550. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  551. match self {
  552. Self::Text(arg0) => f.debug_tuple("Text").field(arg0).finish(),
  553. Self::Float(arg0) => f.debug_tuple("Float").field(arg0).finish(),
  554. Self::Int(arg0) => f.debug_tuple("Int").field(arg0).finish(),
  555. Self::Bool(arg0) => f.debug_tuple("Bool").field(arg0).finish(),
  556. Self::Listener(_) => f.debug_tuple("Listener").finish(),
  557. Self::Any(_) => f.debug_tuple("Any").finish(),
  558. Self::None => write!(f, "None"),
  559. }
  560. }
  561. }
  562. impl PartialEq for AttributeValue {
  563. fn eq(&self, other: &Self) -> bool {
  564. match (self, other) {
  565. (Self::Text(l0), Self::Text(r0)) => l0 == r0,
  566. (Self::Float(l0), Self::Float(r0)) => l0 == r0,
  567. (Self::Int(l0), Self::Int(r0)) => l0 == r0,
  568. (Self::Bool(l0), Self::Bool(r0)) => l0 == r0,
  569. (Self::Listener(_), Self::Listener(_)) => true,
  570. (Self::Any(l0), Self::Any(r0)) => l0.as_ref().any_cmp(r0.as_ref()),
  571. _ => false,
  572. }
  573. }
  574. }
  575. #[doc(hidden)]
  576. pub trait AnyValue: 'static {
  577. fn any_cmp(&self, other: &dyn AnyValue) -> bool;
  578. fn as_any(&self) -> &dyn Any;
  579. fn type_id(&self) -> TypeId {
  580. self.as_any().type_id()
  581. }
  582. }
  583. impl<T: Any + PartialEq + 'static> AnyValue for T {
  584. fn any_cmp(&self, other: &dyn AnyValue) -> bool {
  585. if let Some(other) = other.as_any().downcast_ref() {
  586. self == other
  587. } else {
  588. false
  589. }
  590. }
  591. fn as_any(&self) -> &dyn Any {
  592. self
  593. }
  594. }
  595. /// A trait that allows various items to be converted into a dynamic node for the rsx macro
  596. pub trait IntoDynNode<A = ()> {
  597. /// Consume this item along with a scopestate and produce a DynamicNode
  598. ///
  599. /// You can use the bump alloactor of the scopestate to creat the dynamic node
  600. fn into_dyn_node(self) -> DynamicNode;
  601. }
  602. impl IntoDynNode for () {
  603. fn into_dyn_node(self) -> DynamicNode {
  604. DynamicNode::default()
  605. }
  606. }
  607. impl IntoDynNode for VNode {
  608. fn into_dyn_node(self) -> DynamicNode {
  609. DynamicNode::Fragment(vec![self])
  610. }
  611. }
  612. impl IntoDynNode for DynamicNode {
  613. fn into_dyn_node(self) -> DynamicNode {
  614. self
  615. }
  616. }
  617. impl<T: IntoDynNode> IntoDynNode for Option<T> {
  618. fn into_dyn_node(self) -> DynamicNode {
  619. match self {
  620. Some(val) => val.into_dyn_node(),
  621. None => DynamicNode::default(),
  622. }
  623. }
  624. }
  625. impl IntoDynNode for &Element {
  626. fn into_dyn_node(self) -> DynamicNode {
  627. match self.as_ref() {
  628. Some(val) => val.clone().into_dyn_node(),
  629. _ => DynamicNode::default(),
  630. }
  631. }
  632. }
  633. impl IntoDynNode for &str {
  634. fn into_dyn_node(self) -> DynamicNode {
  635. DynamicNode::Text(VText {
  636. value: self.to_string(),
  637. })
  638. }
  639. }
  640. impl IntoDynNode for String {
  641. fn into_dyn_node(self) -> DynamicNode {
  642. DynamicNode::Text(VText { value: self })
  643. }
  644. }
  645. impl IntoDynNode for Arguments<'_> {
  646. fn into_dyn_node(self) -> DynamicNode {
  647. DynamicNode::Text(VText {
  648. value: self.to_string(),
  649. })
  650. }
  651. }
  652. impl IntoDynNode for &VNode {
  653. fn into_dyn_node(self) -> DynamicNode {
  654. DynamicNode::Fragment(vec![self.clone()])
  655. }
  656. }
  657. pub trait IntoVNode {
  658. fn into_vnode(self) -> VNode;
  659. }
  660. impl IntoVNode for VNode {
  661. fn into_vnode(self) -> VNode {
  662. self
  663. }
  664. }
  665. impl IntoVNode for Element {
  666. fn into_vnode(self) -> VNode {
  667. match self {
  668. Some(val) => val.into_vnode(),
  669. _ => VNode::empty().unwrap(),
  670. }
  671. }
  672. }
  673. // Note that we're using the E as a generic but this is never crafted anyways.
  674. pub struct FromNodeIterator;
  675. impl<T, I> IntoDynNode<FromNodeIterator> for T
  676. where
  677. T: Iterator<Item = I>,
  678. I: IntoVNode,
  679. {
  680. fn into_dyn_node(self) -> DynamicNode {
  681. let children: Vec<_> = self.into_iter().map(|node| node.into_vnode()).collect();
  682. if children.is_empty() {
  683. DynamicNode::default()
  684. } else {
  685. DynamicNode::Fragment(children)
  686. }
  687. }
  688. }
  689. /// A value that can be converted into an attribute value
  690. pub trait IntoAttributeValue {
  691. /// Convert into an attribute value
  692. fn into_value(self) -> AttributeValue;
  693. }
  694. impl IntoAttributeValue for AttributeValue {
  695. fn into_value(self) -> AttributeValue {
  696. self
  697. }
  698. }
  699. impl IntoAttributeValue for &str {
  700. fn into_value(self) -> AttributeValue {
  701. AttributeValue::Text(self.to_string())
  702. }
  703. }
  704. impl IntoAttributeValue for String {
  705. fn into_value(self) -> AttributeValue {
  706. AttributeValue::Text(self)
  707. }
  708. }
  709. impl IntoAttributeValue for f64 {
  710. fn into_value(self) -> AttributeValue {
  711. AttributeValue::Float(self)
  712. }
  713. }
  714. impl IntoAttributeValue for i64 {
  715. fn into_value(self) -> AttributeValue {
  716. AttributeValue::Int(self)
  717. }
  718. }
  719. impl IntoAttributeValue for bool {
  720. fn into_value(self) -> AttributeValue {
  721. AttributeValue::Bool(self)
  722. }
  723. }
  724. impl IntoAttributeValue for Arguments<'_> {
  725. fn into_value(self) -> AttributeValue {
  726. AttributeValue::Text(self.to_string())
  727. }
  728. }
  729. impl IntoAttributeValue for Box<dyn AnyValue> {
  730. fn into_value(self) -> AttributeValue {
  731. AttributeValue::Any(self)
  732. }
  733. }
  734. impl<T: IntoAttributeValue> IntoAttributeValue for Option<T> {
  735. fn into_value(self) -> AttributeValue {
  736. match self {
  737. Some(val) => val.into_value(),
  738. None => AttributeValue::None,
  739. }
  740. }
  741. }