dynamic_template_context.rs 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. use std::{marker::PhantomData, ops::Deref};
  2. use once_cell::sync::Lazy;
  3. use crate::{
  4. template::{TemplateNodeId, TextTemplateSegment},
  5. AttributeValue, Listener, VNode,
  6. };
  7. /// A lazily initailized vector
  8. #[derive(Debug, Clone, Copy)]
  9. pub struct LazyStaticVec<T: 'static>(pub &'static Lazy<Vec<T>>);
  10. impl<T: 'static> AsRef<[T]> for LazyStaticVec<T> {
  11. fn as_ref(&self) -> &[T] {
  12. let v: &Vec<_> = self.0.deref();
  13. v.as_ref()
  14. }
  15. }
  16. impl<T> PartialEq for LazyStaticVec<T> {
  17. fn eq(&self, other: &Self) -> bool {
  18. std::ptr::eq(self.0, other.0)
  19. }
  20. }
  21. /// Stores what nodes depend on specific dynamic parts of the template to allow the diffing algorithm to jump to that part of the template instead of travering it
  22. /// This makes adding constant template nodes add no additional cost to diffing.
  23. #[derive(Debug, Clone, Copy, PartialEq)]
  24. #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
  25. pub struct DynamicNodeMapping<
  26. Nodes,
  27. TextOuter,
  28. TextInner,
  29. AttributesOuter,
  30. AttributesInner,
  31. Volatile,
  32. Listeners,
  33. > where
  34. Nodes: AsRef<[Option<TemplateNodeId>]>,
  35. TextOuter: AsRef<[TextInner]>,
  36. TextInner: AsRef<[TemplateNodeId]>,
  37. AttributesOuter: AsRef<[AttributesInner]>,
  38. AttributesInner: AsRef<[(TemplateNodeId, usize)]>,
  39. Volatile: AsRef<[(TemplateNodeId, usize)]>,
  40. Listeners: AsRef<[TemplateNodeId]>,
  41. {
  42. /// The node that depend on each node in the dynamic template
  43. pub nodes: Nodes,
  44. text_inner: PhantomData<TextInner>,
  45. /// The text nodes that depend on each text segment of the dynamic template
  46. pub text: TextOuter,
  47. /// The attributes along with the attribute index in the template that depend on each attribute of the dynamic template
  48. pub attributes: AttributesOuter,
  49. attributes_inner: PhantomData<AttributesInner>,
  50. /// The attributes that are marked as volatile in the template
  51. pub volatile_attributes: Volatile,
  52. /// The listeners that depend on each listener of the dynamic template
  53. pub nodes_with_listeners: Listeners,
  54. }
  55. impl<Nodes, TextOuter, TextInner, AttributesOuter, AttributesInner, Volatile, Listeners>
  56. DynamicNodeMapping<
  57. Nodes,
  58. TextOuter,
  59. TextInner,
  60. AttributesOuter,
  61. AttributesInner,
  62. Volatile,
  63. Listeners,
  64. >
  65. where
  66. Nodes: AsRef<[Option<TemplateNodeId>]>,
  67. TextOuter: AsRef<[TextInner]>,
  68. TextInner: AsRef<[TemplateNodeId]>,
  69. AttributesOuter: AsRef<[AttributesInner]>,
  70. AttributesInner: AsRef<[(TemplateNodeId, usize)]>,
  71. Volatile: AsRef<[(TemplateNodeId, usize)]>,
  72. Listeners: AsRef<[TemplateNodeId]>,
  73. {
  74. /// Creates a new dynamic node mapping
  75. pub const fn new(
  76. nodes: Nodes,
  77. text: TextOuter,
  78. attributes: AttributesOuter,
  79. volatile_attributes: Volatile,
  80. listeners: Listeners,
  81. ) -> Self {
  82. DynamicNodeMapping {
  83. nodes,
  84. text_inner: PhantomData,
  85. text,
  86. attributes,
  87. attributes_inner: PhantomData,
  88. volatile_attributes,
  89. nodes_with_listeners: listeners,
  90. }
  91. }
  92. pub(crate) fn all_dynamic<'a>(&'a self) -> impl Iterator<Item = TemplateNodeId> + 'a {
  93. self.nodes
  94. .as_ref()
  95. .iter()
  96. .filter_map(|o| o.as_ref())
  97. .chain(
  98. self.text
  99. .as_ref()
  100. .iter()
  101. .map(|ids| ids.as_ref().iter())
  102. .flatten(),
  103. )
  104. .copied()
  105. .chain(
  106. self.attributes
  107. .as_ref()
  108. .iter()
  109. .map(|ids| ids.as_ref().iter())
  110. .flatten()
  111. .map(|dynamic| dynamic.0),
  112. )
  113. .chain(self.nodes_with_listeners.as_ref().iter().copied())
  114. }
  115. }
  116. /// A dynamic node mapping that is stack allocated
  117. pub type StaticDynamicNodeMapping = DynamicNodeMapping<
  118. &'static [Option<TemplateNodeId>],
  119. &'static [&'static [TemplateNodeId]],
  120. &'static [TemplateNodeId],
  121. &'static [&'static [(TemplateNodeId, usize)]],
  122. &'static [(TemplateNodeId, usize)],
  123. // volatile attribute information is available at compile time, but there is no way for the macro to generate it, so we initialize it lazily instead
  124. LazyStaticVec<(TemplateNodeId, usize)>,
  125. &'static [TemplateNodeId],
  126. >;
  127. #[cfg(any(feature = "hot-reload", debug_assertions))]
  128. /// A dynamic node mapping that is heap allocated
  129. pub type OwnedDynamicNodeMapping = DynamicNodeMapping<
  130. Vec<Option<TemplateNodeId>>,
  131. Vec<Vec<TemplateNodeId>>,
  132. Vec<TemplateNodeId>,
  133. Vec<Vec<(TemplateNodeId, usize)>>,
  134. Vec<(TemplateNodeId, usize)>,
  135. Vec<(TemplateNodeId, usize)>,
  136. Vec<TemplateNodeId>,
  137. >;
  138. /// The dynamic parts used to saturate a template durring runtime
  139. pub struct TemplateContext<'b> {
  140. /// The dynamic nodes
  141. pub nodes: &'b [VNode<'b>],
  142. /// The dynamic text
  143. pub text_segments: &'b [&'b str],
  144. /// The dynamic attributes
  145. pub attributes: &'b [AttributeValue<'b>],
  146. /// The dynamic attributes
  147. // The listeners must not change during the lifetime of the context, use a dynamic node if the listeners change
  148. pub listeners: &'b [Listener<'b>],
  149. /// A optional key for diffing
  150. pub key: Option<&'b str>,
  151. }
  152. impl<'b> TemplateContext<'b> {
  153. /// Resolve text segments to a string
  154. pub fn resolve_text<TextSegments, Text>(&self, text: &TextSegments) -> String
  155. where
  156. TextSegments: AsRef<[TextTemplateSegment<Text>]>,
  157. Text: AsRef<str>,
  158. {
  159. let mut result = String::new();
  160. for seg in text.as_ref() {
  161. match seg {
  162. TextTemplateSegment::Static(s) => result += s.as_ref(),
  163. TextTemplateSegment::Dynamic(idx) => result += self.text_segments[*idx],
  164. }
  165. }
  166. result
  167. }
  168. /// Resolve an attribute value
  169. pub fn resolve_attribute(&self, idx: usize) -> &'b AttributeValue<'b> {
  170. &self.attributes[idx]
  171. }
  172. /// Resolve a listener
  173. pub fn resolve_listener(&self, idx: usize) -> &'b Listener<'b> {
  174. &self.listeners[idx]
  175. }
  176. /// Resolve a node
  177. pub fn resolve_node(&self, idx: usize) -> &'b VNode<'b> {
  178. &self.nodes[idx]
  179. }
  180. }