node_ref.rs 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. use dioxus_core::*;
  2. use crate::{
  3. real_dom::{NodeData, NodeType, OwnedAttributeView},
  4. state::union_ordered_iter,
  5. };
  6. /// A view into a [VNode] with limited access.
  7. #[derive(Debug)]
  8. pub struct NodeView<'a> {
  9. inner: &'a NodeData,
  10. mask: NodeMask,
  11. }
  12. impl<'a> NodeView<'a> {
  13. /// Create a new NodeView from a VNode, and mask.
  14. pub fn new(node: &'a NodeData, view: NodeMask) -> Self {
  15. Self {
  16. inner: node,
  17. mask: view,
  18. }
  19. }
  20. /// Get the id of the node
  21. pub fn id(&self) -> GlobalNodeId {
  22. self.inner.id
  23. }
  24. /// Get the tag of the node if the tag is enabled in the mask
  25. pub fn tag(&self) -> Option<&'a str> {
  26. self.mask
  27. .tag
  28. .then(|| match &self.inner.node_type {
  29. NodeType::Element { tag, .. } => Some(&**tag),
  30. _ => None,
  31. })
  32. .flatten()
  33. }
  34. /// Get the tag of the node if the namespace is enabled in the mask
  35. pub fn namespace(&self) -> Option<&'a str> {
  36. self.mask
  37. .namespace
  38. .then(|| match &self.inner.node_type {
  39. NodeType::Element { namespace, .. } => namespace.map(|s| &*s),
  40. _ => None,
  41. })
  42. .flatten()
  43. }
  44. /// Get any attributes that are enabled in the mask
  45. pub fn attributes<'b>(&'b self) -> Option<impl Iterator<Item = OwnedAttributeView<'a>> + 'b> {
  46. match &self.inner.node_type {
  47. NodeType::Element { attributes, .. } => Some(
  48. attributes
  49. .iter()
  50. .filter(move |(attr, _)| self.mask.attritutes.contains_attribute(&attr.name))
  51. .map(|(attr, val)| OwnedAttributeView {
  52. attribute: attr,
  53. value: val,
  54. }),
  55. ),
  56. _ => None,
  57. }
  58. }
  59. /// Get the text if it is enabled in the mask
  60. pub fn text(&self) -> Option<&str> {
  61. self.mask
  62. .text
  63. .then(|| match &self.inner.node_type {
  64. NodeType::Text { text } => Some(&**text),
  65. _ => None,
  66. })
  67. .flatten()
  68. }
  69. /// Get the listeners if it is enabled in the mask
  70. pub fn listeners(&self) -> Option<impl Iterator<Item = &'a str> + '_> {
  71. if self.mask.listeners {
  72. match &self.inner.node_type {
  73. NodeType::Element { listeners, .. } => Some(listeners.iter().map(|l| &**l)),
  74. _ => None,
  75. }
  76. } else {
  77. None
  78. }
  79. }
  80. }
  81. /// A mask that contains a list of attributes that are visible.
  82. #[derive(PartialEq, Eq, Clone, Debug)]
  83. pub enum AttributeMask {
  84. All,
  85. /// A list of attribute names that are visible, this list must be sorted
  86. Dynamic(Vec<&'static str>),
  87. /// A list of attribute names that are visible, this list must be sorted
  88. Static(&'static [&'static str]),
  89. }
  90. impl AttributeMask {
  91. /// A empty attribute mask
  92. pub const NONE: Self = Self::Static(&[]);
  93. fn contains_attribute(&self, attr: &str) -> bool {
  94. match self {
  95. AttributeMask::All => true,
  96. AttributeMask::Dynamic(l) => l.binary_search(&attr).is_ok(),
  97. AttributeMask::Static(l) => l.binary_search(&attr).is_ok(),
  98. }
  99. }
  100. /// Create a new dynamic attribute mask with a single attribute
  101. pub fn single(new: &'static str) -> Self {
  102. Self::Dynamic(vec![new])
  103. }
  104. /// Ensure the attribute list is sorted.
  105. pub fn verify(&self) {
  106. match &self {
  107. AttributeMask::Static(attrs) => debug_assert!(
  108. attrs.windows(2).all(|w| w[0] < w[1]),
  109. "attritutes must be increasing"
  110. ),
  111. AttributeMask::Dynamic(attrs) => debug_assert!(
  112. attrs.windows(2).all(|w| w[0] < w[1]),
  113. "attritutes must be increasing"
  114. ),
  115. _ => (),
  116. }
  117. }
  118. /// Combine two attribute masks
  119. pub fn union(&self, other: &Self) -> Self {
  120. let new = match (self, other) {
  121. (AttributeMask::Dynamic(s), AttributeMask::Dynamic(o)) => AttributeMask::Dynamic(
  122. union_ordered_iter(s.iter().copied(), o.iter().copied(), s.len() + o.len()),
  123. ),
  124. (AttributeMask::Static(s), AttributeMask::Dynamic(o)) => AttributeMask::Dynamic(
  125. union_ordered_iter(s.iter().copied(), o.iter().copied(), s.len() + o.len()),
  126. ),
  127. (AttributeMask::Dynamic(s), AttributeMask::Static(o)) => AttributeMask::Dynamic(
  128. union_ordered_iter(s.iter().copied(), o.iter().copied(), s.len() + o.len()),
  129. ),
  130. (AttributeMask::Static(s), AttributeMask::Static(o)) => AttributeMask::Dynamic(
  131. union_ordered_iter(s.iter().copied(), o.iter().copied(), s.len() + o.len()),
  132. ),
  133. _ => AttributeMask::All,
  134. };
  135. new.verify();
  136. new
  137. }
  138. /// Check if two attribute masks overlap
  139. fn overlaps(&self, other: &Self) -> bool {
  140. fn overlaps_iter(
  141. self_iter: impl Iterator<Item = &'static str>,
  142. mut other_iter: impl Iterator<Item = &'static str>,
  143. ) -> bool {
  144. if let Some(mut other_attr) = other_iter.next() {
  145. for self_attr in self_iter {
  146. while other_attr < self_attr {
  147. if let Some(attr) = other_iter.next() {
  148. other_attr = attr;
  149. } else {
  150. return false;
  151. }
  152. }
  153. if other_attr == self_attr {
  154. return true;
  155. }
  156. }
  157. }
  158. false
  159. }
  160. match (self, other) {
  161. (AttributeMask::All, AttributeMask::All) => true,
  162. (AttributeMask::All, AttributeMask::Dynamic(v)) => !v.is_empty(),
  163. (AttributeMask::All, AttributeMask::Static(s)) => !s.is_empty(),
  164. (AttributeMask::Dynamic(v), AttributeMask::All) => !v.is_empty(),
  165. (AttributeMask::Static(s), AttributeMask::All) => !s.is_empty(),
  166. (AttributeMask::Dynamic(v1), AttributeMask::Dynamic(v2)) => {
  167. overlaps_iter(v1.iter().copied(), v2.iter().copied())
  168. }
  169. (AttributeMask::Dynamic(v), AttributeMask::Static(s)) => {
  170. overlaps_iter(v.iter().copied(), s.iter().copied())
  171. }
  172. (AttributeMask::Static(s), AttributeMask::Dynamic(v)) => {
  173. overlaps_iter(v.iter().copied(), s.iter().copied())
  174. }
  175. (AttributeMask::Static(s1), AttributeMask::Static(s2)) => {
  176. overlaps_iter(s1.iter().copied(), s2.iter().copied())
  177. }
  178. }
  179. }
  180. }
  181. impl Default for AttributeMask {
  182. fn default() -> Self {
  183. AttributeMask::Static(&[])
  184. }
  185. }
  186. /// A mask that limits what parts of a node a dependency can see.
  187. #[derive(Default, PartialEq, Eq, Clone, Debug)]
  188. pub struct NodeMask {
  189. attritutes: AttributeMask,
  190. tag: bool,
  191. namespace: bool,
  192. text: bool,
  193. listeners: bool,
  194. }
  195. impl NodeMask {
  196. /// A node mask with no parts visible.
  197. pub const NONE: Self = Self::new();
  198. /// A node mask with every part visible.
  199. pub const ALL: Self = Self::new_with_attrs(AttributeMask::All)
  200. .with_text()
  201. .with_element()
  202. .with_listeners();
  203. /// Check if two masks overlap
  204. pub fn overlaps(&self, other: &Self) -> bool {
  205. (self.tag && other.tag)
  206. || (self.namespace && other.namespace)
  207. || self.attritutes.overlaps(&other.attritutes)
  208. || (self.text && other.text)
  209. || (self.listeners && other.listeners)
  210. }
  211. /// Combine two node masks
  212. pub fn union(&self, other: &Self) -> Self {
  213. Self {
  214. attritutes: self.attritutes.union(&other.attritutes),
  215. tag: self.tag | other.tag,
  216. namespace: self.namespace | other.namespace,
  217. text: self.text | other.text,
  218. listeners: self.listeners | other.listeners,
  219. }
  220. }
  221. /// Create a new node mask with the given attributes
  222. pub const fn new_with_attrs(attritutes: AttributeMask) -> Self {
  223. Self {
  224. attritutes,
  225. tag: false,
  226. namespace: false,
  227. text: false,
  228. listeners: false,
  229. }
  230. }
  231. /// Create a empty node mask
  232. pub const fn new() -> Self {
  233. Self::new_with_attrs(AttributeMask::NONE)
  234. }
  235. /// Allow the mask to view the tag
  236. pub const fn with_tag(mut self) -> Self {
  237. self.tag = true;
  238. self
  239. }
  240. /// Allow the mask to view the namespace
  241. pub const fn with_namespace(mut self) -> Self {
  242. self.namespace = true;
  243. self
  244. }
  245. /// Allow the mask to view the namespace and tag
  246. pub const fn with_element(self) -> Self {
  247. self.with_namespace().with_tag()
  248. }
  249. /// Allow the mask to view the text
  250. pub const fn with_text(mut self) -> Self {
  251. self.text = true;
  252. self
  253. }
  254. /// Allow the mask to view the listeners
  255. pub const fn with_listeners(mut self) -> Self {
  256. self.listeners = true;
  257. self
  258. }
  259. }