Skip to main content

css_parse/syntax/
attribute_operator.rs

1use super::prelude::*;
2
3/// The operator of an attribute selector, e.g. the `^=` of `[href^="https"]`.
4///
5/// <https://drafts.csswg.org/selectors/#attribute-selectors>
6#[node]
7#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
8#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
9pub enum AttributeOperator {
10	Exact(T![=]),
11	SpaceList(T![~=]),
12	LangPrefix(T![|=]),
13	Prefix(T![^=]),
14	Suffix(T!["$="]),
15	Contains(T![*=]),
16}
17
18impl<M: NodeMetadata> NodeWithMetadata<M> for AttributeOperator {
19	fn metadata(&self) -> M {
20		M::default()
21	}
22}
23
24impl<'a> Peek<'a> for AttributeOperator {
25	const PEEK_KINDSET: KindSet = KindSet::new(&[Kind::Delim]);
26}
27
28impl<'a> Parse<'a> for AttributeOperator {
29	fn parse<I>(p: &mut Parser<'a, I>) -> Result<Self>
30	where
31		I: Iterator<Item = Cursor> + Clone,
32	{
33		if p.peek::<T![~=]>() {
34			p.parse::<T![~=]>().map(Self::SpaceList)
35		} else if p.peek::<T![|=]>() {
36			p.parse::<T![|=]>().map(Self::LangPrefix)
37		} else if p.peek::<T![^=]>() {
38			p.parse::<T![^=]>().map(Self::Prefix)
39		} else if p.peek::<T!["$="]>() {
40			p.parse::<T!["$="]>().map(Self::Suffix)
41		} else if p.peek::<T![*=]>() {
42			p.parse::<T![*=]>().map(Self::Contains)
43		} else {
44			p.parse::<T![=]>().map(Self::Exact)
45		}
46	}
47}
48
49impl ToCursors for AttributeOperator {
50	fn to_cursors(&self, s: &mut impl CursorSink) {
51		match self {
52			Self::Exact(t) => t.to_cursors(s),
53			Self::SpaceList(t) => t.to_cursors(s),
54			Self::LangPrefix(t) => t.to_cursors(s),
55			Self::Prefix(t) => t.to_cursors(s),
56			Self::Suffix(t) => t.to_cursors(s),
57			Self::Contains(t) => t.to_cursors(s),
58		}
59	}
60}
61
62impl ToSpan for AttributeOperator {
63	fn to_span(&self) -> Span {
64		match self {
65			Self::Exact(t) => t.to_span(),
66			Self::SpaceList(t) => t.to_span(),
67			Self::LangPrefix(t) => t.to_span(),
68			Self::Prefix(t) => t.to_span(),
69			Self::Suffix(t) => t.to_span(),
70			Self::Contains(t) => t.to_span(),
71		}
72	}
73}
74
75impl SemanticEq for AttributeOperator {
76	fn semantic_eq(&self, other: &Self, _source_text: &str) -> bool {
77		std::mem::discriminant(self) == std::mem::discriminant(other)
78	}
79}
80
81#[cfg(test)]
82mod tests {
83	use super::*;
84	use crate::{EmptyAtomSet, assert_parse};
85
86	#[test]
87	fn test_writes() {
88		assert_parse!(EmptyAtomSet::ATOMS, AttributeOperator, "=");
89		assert_parse!(EmptyAtomSet::ATOMS, AttributeOperator, "~=");
90		assert_parse!(EmptyAtomSet::ATOMS, AttributeOperator, "|=");
91		assert_parse!(EmptyAtomSet::ATOMS, AttributeOperator, "^=");
92		assert_parse!(EmptyAtomSet::ATOMS, AttributeOperator, "$=");
93		assert_parse!(EmptyAtomSet::ATOMS, AttributeOperator, "*=");
94	}
95}