nodes.rs 28 KB

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