Skip to main content

css_parse/
comparison.rs

1use std::fmt;
2
3use crate::{Diagnostic, Parse, Parser, Peek, Result, SemanticEq, T, ToCursors};
4use css_lexer::{Span, ToSpan};
5
6/// This enum represents a set of comparison operators, used in Ranged Media Features (see
7/// [RangedFeature][crate::RangedFeature]), and could be used in other parts of a CSS-alike language. This isn't a
8/// strictly standard part of CSS, but is provided for convenience.
9///
10/// [Comparison] is defined as:
11///
12/// ```md
13/// <comparison>
14///  │├──╮─ "="  ─╭──┤│
15///      ├─ "<"  ─┤
16///      ├─ "<=" ─┤
17///      ├─ ">"  ─┤
18///      ╰─ ">=" ─╯
19/// ```
20///
21#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
22#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
23pub enum Comparison {
24	LessThan(T![<]),
25	GreaterThan(T![>]),
26	GreaterThanEqual(T![>=]),
27	LessThanEqual(T![<=]),
28	Equal(T![=]),
29}
30
31impl<'a> Parse<'a> for Comparison {
32	fn parse<I>(p: &mut Parser<'a, I>) -> Result<Comparison>
33	where
34		I: Iterator<Item = crate::Cursor> + Clone,
35	{
36		let c = p.peek_n(1);
37		match c.token().char() {
38			Some('=') => p.parse::<T![=]>().map(Comparison::Equal),
39			Some('>') => {
40				if <T![>=]>::peek(p, c) {
41					p.parse::<T![>=]>().map(Comparison::GreaterThanEqual)
42				} else {
43					p.parse::<T![>]>().map(Comparison::GreaterThan)
44				}
45			}
46			Some('<') => {
47				if <T![<=]>::peek(p, c) {
48					p.parse::<T![<=]>().map(Comparison::LessThanEqual)
49				} else {
50					p.parse::<T![<]>().map(Comparison::LessThan)
51				}
52			}
53			Some(_) => Err(Diagnostic::new(p.next(), Diagnostic::unexpected_delim))?,
54			_ => Err(Diagnostic::new(p.next(), Diagnostic::unexpected))?,
55		}
56	}
57}
58
59impl ToCursors for Comparison {
60	fn to_cursors(&self, s: &mut impl crate::CursorSink) {
61		match self {
62			Self::LessThan(c) => ToCursors::to_cursors(c, s),
63			Self::GreaterThan(c) => ToCursors::to_cursors(c, s),
64			Self::GreaterThanEqual(c) => ToCursors::to_cursors(c, s),
65			Self::LessThanEqual(c) => ToCursors::to_cursors(c, s),
66			Self::Equal(c) => ToCursors::to_cursors(c, s),
67		}
68	}
69}
70
71impl fmt::Display for Comparison {
72	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
73		f.write_str(match self {
74			Self::LessThan(_) => "<",
75			Self::GreaterThan(_) => ">",
76			Self::GreaterThanEqual(_) => ">=",
77			Self::LessThanEqual(_) => "<=",
78			Self::Equal(_) => "=",
79		})
80	}
81}
82
83impl ToSpan for Comparison {
84	fn to_span(&self) -> Span {
85		match self {
86			Self::LessThan(c) => c.to_span(),
87			Self::GreaterThan(c) => c.to_span(),
88			Self::GreaterThanEqual(c) => c.to_span(),
89			Self::LessThanEqual(c) => c.to_span(),
90			Self::Equal(c) => c.to_span(),
91		}
92	}
93}
94
95impl SemanticEq for Comparison {
96	fn semantic_eq(&self, other: &Self) -> bool {
97		match (self, other) {
98			(Self::LessThan(a), Self::LessThan(b)) => a.semantic_eq(b),
99			(Self::GreaterThan(a), Self::GreaterThan(b)) => a.semantic_eq(b),
100			(Self::GreaterThanEqual(a), Self::GreaterThanEqual(b)) => a.semantic_eq(b),
101			(Self::LessThanEqual(a), Self::LessThanEqual(b)) => a.semantic_eq(b),
102			(Self::Equal(a), Self::Equal(b)) => a.semantic_eq(b),
103			_ => false,
104		}
105	}
106}