nodes.rs 30 KB

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