Skip to main content

css_ast/units/
angles.rs

1use super::prelude::*;
2
3/// <https://drafts.csswg.org/css-values/#angles>
4///
5/// ```text,ignore
6/// <angle> = <dimension-token>
7/// ```
8#[derive(IntoCursor, Parse, Peek, ToCursors, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
9#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
10#[cfg_attr(feature = "css_feature_data", derive(::csskit_derives::ToCSSFeature), css_feature("css.types.angle"))]
11#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
12#[derive(csskit_derives::NodeWithMetadata)]
13#[metadata(node_kinds = Dimension)]
14pub enum Angle {
15	#[atom(CssAtomSet::Grad)]
16	Grad(T![Dimension]),
17	#[atom(CssAtomSet::Rad)]
18	Rad(T![Dimension]),
19	#[atom(CssAtomSet::Turn)]
20	Turn(T![Dimension]),
21	#[atom(CssAtomSet::Deg)]
22	Deg(T![Dimension]),
23}
24
25impl From<Angle> for f32 {
26	fn from(val: Angle) -> Self {
27		match val {
28			Angle::Grad(f) => f.into(),
29			Angle::Rad(f) => f.into(),
30			Angle::Turn(f) => f.into(),
31			Angle::Deg(f) => f.into(),
32		}
33	}
34}
35
36impl ToNumberValue for Angle {
37	fn to_number_value(&self) -> Option<f32> {
38		Some((*self).into())
39	}
40}
41
42impl Angle {
43	const DEG_GRAD: f32 = 0.9;
44	const DEG_RAD: f32 = 57.295_78;
45	const DEG_TURN: f32 = 360.0;
46
47	pub fn as_degrees(&self) -> f32 {
48		match self {
49			Self::Grad(d) => Into::<f32>::into(*d) * Self::DEG_GRAD,
50			Self::Rad(d) => Into::<f32>::into(*d) * Self::DEG_RAD,
51			Self::Turn(d) => Into::<f32>::into(*d) * Self::DEG_TURN,
52			Self::Deg(d) => (*d).into(),
53		}
54	}
55}
56
57#[derive(IntoCursor, Parse, Peek, ToCursors, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
58#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
59#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(children))]
60#[derive(csskit_derives::NodeWithMetadata)]
61pub enum AngleOrZero {
62	Angle(Angle),
63	#[cfg_attr(feature = "visitable", visit(skip))]
64	Zero(Exact<T![Number], 0>),
65}
66
67#[derive(IntoCursor, Parse, Peek, ToCursors, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
68#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
69#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(children))]
70#[derive(csskit_derives::NodeWithMetadata)]
71pub enum AngleOrNumber {
72	Angle(Angle),
73	#[cfg_attr(feature = "visitable", visit(skip))]
74	Number(T![Number]),
75}
76
77impl From<AngleOrZero> for f32 {
78	fn from(val: AngleOrZero) -> Self {
79		match val {
80			AngleOrZero::Angle(f) => f.into(),
81			AngleOrZero::Zero(f) => f.0.into(),
82		}
83	}
84}
85
86#[cfg(test)]
87mod tests {
88	use super::*;
89	use crate::CssAtomSet;
90	use css_parse::assert_parse;
91
92	#[test]
93	fn size_test() {
94		assert_eq!(std::mem::size_of::<Angle>(), 16);
95	}
96
97	#[test]
98	fn test_writes() {
99		assert_parse!(CssAtomSet::ATOMS, Angle, "0grad");
100		assert_parse!(CssAtomSet::ATOMS, Angle, "0deg");
101		assert_parse!(CssAtomSet::ATOMS, AngleOrZero, "0", AngleOrZero::Zero(_));
102	}
103}