Skip to main content

css_ast/visit/
visit_node.rs

1use css_lexer::Span;
2use css_parse::Cursor;
3
4use crate::{CssMetadata, PropertyKind};
5
6use super::NodeId;
7
8pub(crate) trait QueryNodeData {
9	/// Metadata for *this node only* (no subtree aggregation).
10	fn self_metadata(&self) -> CssMetadata;
11	/// Metadata for this node and its entire subtree.
12	fn subtree_metadata(&self) -> CssMetadata;
13	/// Returns a cursor for the given property kind, if the node has that property.
14	fn get_property(&self, kind: PropertyKind) -> Option<Cursor>;
15}
16
17/// Identity of one node within a parsed tree.
18///
19/// Keys remain valid while the tree lives. They are opaque and meaningful only among nodes from
20/// the same tree.
21#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
22pub struct NodeKey {
23	address: usize,
24	node_id: NodeId,
25}
26
27impl NodeKey {
28	fn of<T: ?Sized>(value: &T, node_id: NodeId) -> Self {
29		Self { address: (std::ptr::from_ref(value) as *const ()).addr(), node_id }
30	}
31}
32
33/// The single node view passed to every [`Visit`](super::Visit) callback.
34#[derive(Clone, Copy)]
35pub struct VisitNode<'n> {
36	pub span: Span,
37	pub node_id: Option<NodeId>,
38	source: Option<&'n dyn QueryNodeData>,
39}
40
41impl<'n> VisitNode<'n> {
42	/// Construct for a queryable node. For Nodes without `NodeId` or meta see [VisitNode::new_transparent].
43	#[inline]
44	pub(crate) fn new(span: Span, node_id: NodeId, source: &'n dyn QueryNodeData) -> Self {
45		Self { span, node_id: Some(node_id), source: Some(source) }
46	}
47
48	/// Construct for a "transparent node" (no `NodeId`, no meta).
49	#[inline]
50	pub fn new_transparent(span: Span) -> Self {
51		Self { span, node_id: None, source: None }
52	}
53
54	/// The identity of this queryable node, or `None` for a transparent node.
55	#[inline]
56	pub fn key(&self) -> Option<NodeKey> {
57		self.source.zip(self.node_id).map(|(source, node_id)| NodeKey::of(source, node_id))
58	}
59
60	/// Aggregated metadata for this node *and its entire subtree*.
61	#[inline]
62	pub fn subtree_metadata(&self) -> CssMetadata {
63		self.source.map(QueryNodeData::subtree_metadata).unwrap_or_default()
64	}
65
66	/// Metadata for *this node only* (no subtree aggregation).
67	#[inline]
68	pub fn self_metadata(&self) -> CssMetadata {
69		self.source.map(QueryNodeData::self_metadata).unwrap_or_default()
70	}
71
72	/// Retrieve a named property from this node, if present.
73	#[inline]
74	pub fn property(&self, kind: PropertyKind) -> Option<Cursor> {
75		self.source.and_then(|s| s.get_property(kind))
76	}
77}