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