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