Skip to main content

css_ast/values/transforms/
impls.rs

1use super::{RotateStyleValue, TransformOriginStyleValue};
2use crate::{Angle, CalcableValue, CssAtomSet, KeywordValue, Length, Number, NumericValue, PositionOne, PositionTwo};
3use css_parse::{Cursor, Diagnostic, Parse, Parser, Peek, Result as ParseResult, T};
4
5impl<'a> Parse<'a> for TransformOriginStyleValue<'a> {
6	fn parse<I>(p: &mut Parser<'a, I>) -> ParseResult<Self>
7	where
8		I: Iterator<Item = Cursor> + Clone,
9	{
10		let first = p.parse::<PositionOne>()?;
11		if !p.peek::<PositionOne>() {
12			return Ok(Self::PositionOne(crate::Value::Literal(first)));
13		}
14		let second_c = p.peek_n(1);
15		let second = p.parse::<PositionOne>()?;
16		let two = PositionTwo::from_two(p, first, second, second_c)?;
17		Ok(Self::PositionTwo(crate::Value::Literal(two), p.parse_if_peek::<CalcableValue<Length>>()?))
18	}
19}
20
21type Vector<'a> = (NumericValue<'a, Number>, NumericValue<'a, Number>, NumericValue<'a, Number>);
22
23impl<'a> Parse<'a> for RotateStyleValue<'a> {
24	fn parse<I>(p: &mut Parser<'a, I>) -> ParseResult<Self>
25	where
26		I: Iterator<Item = Cursor> + Clone,
27	{
28		let c = p.peek_n(1);
29		if <T![Ident]>::peek(p, c) {
30			if p.equals_atom(c, &CssAtomSet::None) {
31				return p.parse::<KeywordValue<'a, T![Ident]>>().map(Self::None);
32			}
33			let variant = match p.to_atom::<CssAtomSet>(c) {
34				CssAtomSet::X => RotateStyleValue::XAngle,
35				CssAtomSet::Y => RotateStyleValue::YAngle,
36				CssAtomSet::Z => RotateStyleValue::ZAngle,
37				_ => Err(Diagnostic::new(c, Diagnostic::unexpected))?,
38			};
39			let keyword = p.parse::<KeywordValue<'a, T![Ident]>>()?;
40			return Ok(variant(keyword, p.parse::<CalcableValue<'a, Angle>>()?));
41		}
42		if <T![Number]>::peek(p, c) {
43			let vector = p.parse::<Vector<'a>>()?;
44			return Ok(Self::NumberAngle(vector, p.parse::<CalcableValue<'a, Angle>>()?));
45		}
46		let angle = p.parse::<CalcableValue<'a, Angle>>()?;
47		let c = p.peek_n(1);
48		if <T![Ident]>::peek(p, c) {
49			let variant = match p.to_atom::<CssAtomSet>(c) {
50				CssAtomSet::X => RotateStyleValue::XAngle,
51				CssAtomSet::Y => RotateStyleValue::YAngle,
52				CssAtomSet::Z => RotateStyleValue::ZAngle,
53				_ => return Ok(Self::Angle(angle)),
54			};
55			let keyword = p.parse::<KeywordValue<'a, T![Ident]>>()?;
56			return Ok(variant(keyword, angle));
57		} else if <T![Number]>::peek(p, c) {
58			return Ok(Self::NumberAngle(p.parse::<Vector<'a>>()?, angle));
59		}
60		Ok(Self::Angle(angle))
61	}
62}
63
64#[cfg(test)]
65mod tests {
66	use super::super::*;
67	use crate::CssAtomSet;
68	use css_parse::{assert_parse, assert_parse_error, assert_peek_false};
69
70	#[test]
71	fn test_writes() {
72		assert_parse!(CssAtomSet::ATOMS, TransformStyleValue, "none");
73		assert_parse!(CssAtomSet::ATOMS, TransformStyleValue, "scale(1)");
74		assert_parse!(CssAtomSet::ATOMS, TransformBoxStyleValue, "fill-box");
75		assert_parse!(CssAtomSet::ATOMS, ScaleStyleValue, "none");
76		assert_parse!(CssAtomSet::ATOMS, ScaleStyleValue, "1%");
77		assert_parse!(CssAtomSet::ATOMS, ScaleStyleValue, "1 2 3");
78		assert_parse!(CssAtomSet::ATOMS, ScaleStyleValue, "1.7 50%");
79		assert_parse!(CssAtomSet::ATOMS, TransformStyleStyleValue, "flat");
80		assert_parse!(CssAtomSet::ATOMS, PerspectiveOriginStyleValue, "1px");
81		assert_parse!(CssAtomSet::ATOMS, BackfaceVisibilityStyleValue, "visible");
82	}
83
84	#[test]
85	fn test_errors() {
86		assert_peek_false!(CssAtomSet::ATOMS, TransformStyleValue, "auto");
87		assert_parse_error!(CssAtomSet::ATOMS, ScaleStyleValue, "none none");
88	}
89
90	#[test]
91	fn test_rotate() {
92		assert_parse!(CssAtomSet::ATOMS, RotateStyleValue, "none");
93		assert_parse!(CssAtomSet::ATOMS, RotateStyleValue, "45deg");
94		assert_parse!(CssAtomSet::ATOMS, RotateStyleValue, "x 45deg");
95		assert_parse!(CssAtomSet::ATOMS, RotateStyleValue, "y 45deg");
96		assert_parse!(CssAtomSet::ATOMS, RotateStyleValue, "z 45deg");
97		assert_parse!(CssAtomSet::ATOMS, RotateStyleValue, "45deg x");
98		assert_parse!(CssAtomSet::ATOMS, RotateStyleValue, "1 2 3 45deg");
99		assert_parse!(CssAtomSet::ATOMS, RotateStyleValue, "45deg 1 2 3");
100		assert_parse!(CssAtomSet::ATOMS, RotateStyleValue, "z calc(45deg * 2)");
101		assert_parse!(CssAtomSet::ATOMS, RotateStyleValue, "x var(--angle)");
102		assert_parse!(CssAtomSet::ATOMS, RotateStyleValue, "var(--angle) y");
103	}
104
105	#[test]
106	fn test_rotate_errors() {
107		assert_parse_error!(CssAtomSet::ATOMS, RotateStyleValue, "x");
108		assert_parse_error!(CssAtomSet::ATOMS, RotateStyleValue, "1 2 45deg");
109		assert_parse_error!(CssAtomSet::ATOMS, RotateStyleValue, "none 45deg");
110	}
111
112	#[test]
113	fn test_transform_origin() {
114		assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "left");
115		assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "center");
116		assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "right");
117		assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "top");
118		assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "bottom");
119		assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "50%");
120		assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "10px");
121		assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "0");
122		assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "left top");
123		assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "left center");
124		assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "left bottom");
125		assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "center top");
126		assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "center center");
127		assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "center bottom");
128		assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "right top");
129		assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "right center");
130		assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "right bottom");
131		assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "50% 50%");
132		assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "10px 20px");
133		assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "0 0");
134		assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "left 50%");
135		assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "right 25%");
136		assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "center 10px");
137		assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "50% top");
138		assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "75% bottom");
139		assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "10px center");
140		assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "left top 5px");
141		assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "center center 0px");
142		assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "50% 50% 10px");
143		assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "right bottom 100px");
144		assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "10px 20px 30px");
145		assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "top left");
146		assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "top center");
147		assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "top right");
148		assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "bottom left");
149		assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "bottom center");
150		assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "bottom right");
151		assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "top left 5px");
152		assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "bottom right 20px");
153		assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "top center 0px");
154	}
155
156	#[test]
157	fn test_transform_origin_errors() {
158		assert_peek_false!(CssAtomSet::ATOMS, TransformOriginStyleValue, "auto");
159		assert_parse_error!(CssAtomSet::ATOMS, TransformOriginStyleValue, "top top");
160		assert_parse_error!(CssAtomSet::ATOMS, TransformOriginStyleValue, "left left");
161		assert_parse_error!(CssAtomSet::ATOMS, TransformOriginStyleValue, "left top 50%");
162		assert_parse_error!(CssAtomSet::ATOMS, TransformOriginStyleValue, "left top 0px extra");
163	}
164}