Skip to main content

css_ast/functions/
calc_size_function.rs

1use super::prelude::*;
2use crate::{CalcSum, LengthPercentage};
3
4/// <https://drafts.csswg.org/css-values-5/#calc-size>
5///
6/// ```text,ignore
7/// <calc-size()> = calc-size( <calc-size-basis>, <calc-sum> )
8/// ```
9///
10/// The `<size-keyword>` production matches any sizing keywords allowed in the context.
11/// For example, in width, it matches auto, min-content, stretch, etc.
12///
13/// The trailing `<calc-sum>` may use the `size` keyword, which refers to the basis.
14#[node]
15#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
16#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
17#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
18#[derive(csskit_derives::NodeWithMetadata)]
19pub struct CalcSizeFunction<'a> {
20	#[atom(CssAtomSet::CalcSize)]
21	pub name: T![Function],
22	pub basis: CalcSizeBasis<'a>,
23	#[semantic_eq(skip)]
24	pub comma: T![,],
25	pub calculation: CalcSum<'a, CalcSizeOperand>,
26	#[semantic_eq(skip)]
27	pub close: T![')'],
28}
29
30/// <https://drafts.csswg.org/css-values-5/#typedef-calc-size-basis>
31///
32/// ```text,ignore
33/// <calc-size-basis> = [ <size-keyword> | <calc-size()> | any | <calc-sum> ]
34/// ```
35#[node]
36#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
37#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
38#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(children))]
39#[derive(csskit_derives::NodeWithMetadata)]
40pub enum CalcSizeBasis<'a> {
41	CalcSize(Box<'a, CalcSizeFunction<'a>>),
42	SizeKeyword(SizeKeyword),
43	#[atom(CssAtomSet::Any)]
44	Any(Ident),
45	Calculation(CalcSum<'a, LengthPercentage>),
46}
47
48/// The sizing keywords allowed as a `<calc-size-basis>`.
49///
50/// ```text,ignore
51/// <size-keyword> = auto | min-content | max-content | fit-content | stretch | contain
52/// ```
53#[node]
54#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
55#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
56#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(skip))]
57#[derive(csskit_derives::NodeWithMetadata)]
58pub enum SizeKeyword {
59	#[atom(CssAtomSet::Auto)]
60	Auto(Ident),
61	#[atom(CssAtomSet::MinContent)]
62	MinContent(Ident),
63	#[atom(CssAtomSet::MaxContent)]
64	MaxContent(Ident),
65	#[atom(CssAtomSet::FitContent)]
66	FitContent(Ident),
67	#[atom(CssAtomSet::Stretch)]
68	Stretch(Ident),
69	#[atom(CssAtomSet::Contain)]
70	Contain(Ident),
71	#[atom(CssAtomSet::_WebkitMinContent)]
72	WebkitMinContent(Ident),
73	#[atom(CssAtomSet::_WebkitMaxContent)]
74	WebkitMaxContent(Ident),
75	#[atom(CssAtomSet::_MozMinContent)]
76	MozMinContent(Ident),
77	#[atom(CssAtomSet::_MozMaxContent)]
78	MozMaxContent(Ident),
79}
80
81/// A `<calc-value>` inside the `<calc-sum>` of a `calc-size()`, which additionally allows the
82/// `size` keyword standing in for the function's basis.
83///
84/// <https://drafts.csswg.org/css-values-5/#calc-size>
85#[node]
86#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
87#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
88#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(children))]
89#[derive(csskit_derives::NodeWithMetadata)]
90pub enum CalcSizeOperand {
91	#[atom(CssAtomSet::Size)]
92	Size(Ident),
93	LengthPercentage(LengthPercentage),
94}
95
96#[cfg(test)]
97mod tests {
98	use super::*;
99	use css_parse::{assert_parse, assert_parse_error};
100
101	#[test]
102	fn test_writes() {
103		assert_parse!(CssAtomSet::ATOMS, CalcSizeFunction, "calc-size(any, size)");
104		assert_parse!(CssAtomSet::ATOMS, CalcSizeFunction, "calc-size(auto, size)");
105		assert_parse!(CssAtomSet::ATOMS, CalcSizeFunction, "calc-size(fit-content, size/2)");
106		assert_parse!(CssAtomSet::ATOMS, CalcSizeFunction, "calc-size(max-content, size + 20px)");
107		assert_parse!(CssAtomSet::ATOMS, CalcSizeFunction, "calc-size(100px, size*2)");
108		assert_parse!(CssAtomSet::ATOMS, CalcSizeFunction, "calc-size(50%, size)");
109		assert_parse!(CssAtomSet::ATOMS, CalcSizeFunction, "calc-size(calc-size(auto, size), size/2)");
110		assert_parse!(CssAtomSet::ATOMS, CalcSizeFunction, "calc-size(-webkit-min-content, size)");
111		assert_parse!(CssAtomSet::ATOMS, CalcSizeFunction, "calc-size(any, 100px)");
112		assert_parse!(CssAtomSet::ATOMS, CalcSizeFunction, "calc-size(var(--basis), size)");
113		assert_parse!(CssAtomSet::ATOMS, CalcSizeFunction, "calc-size(any, var(--x))");
114		assert_parse!(CssAtomSet::ATOMS, CalcSizeFunction, "calc-size(auto, size*var(--n))");
115		assert_parse!(CssAtomSet::ATOMS, CalcSizeFunction, "calc-size(auto, calc(size/2))");
116		assert_parse!(CssAtomSet::ATOMS, CalcSizeFunction, "calc-size(auto, min(size, 100px))");
117		assert_parse!(CssAtomSet::ATOMS, CalcSizeFunction, "calc-size(env(--basis), size)");
118	}
119
120	#[test]
121	fn test_errors() {
122		assert_parse_error!(CssAtomSet::ATOMS, CalcSizeFunction, "calc-size(auto)");
123		assert_parse_error!(CssAtomSet::ATOMS, CalcSizeFunction, "calc-size(nonsense, size)");
124		assert_parse_error!(CssAtomSet::ATOMS, CalcSizeFunction, "calc-size(size, size)");
125	}
126}