node_ref.rs 8.1 KB

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