nodes.rs 28 KB

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