nodes.rs 22 KB

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