1use super::prelude::*;
2use crate::{Flex, Percentage};
3
4macro_rules! apply_lengths {
5 ($ident: ident) => {
6 $ident! {
7 Em,
9 Rem,
10 Ex,
11 Rex,
12 Cap,
13 Rcap,
14 Ch,
15 Rch,
16 Ic,
17 Ric,
18 Lh,
19 Rlh,
20
21 Vw,
23 Svw,
24 Lvw,
25 Dvw,
26 Vh,
27 Svh,
28 Lvh,
29 Dvh,
30 Vi,
31 Svi,
32 Lvi,
33 Dvi,
34 Vb,
35 Svb,
36 Lvb,
37 Dvb,
38 Vmin,
39 Svmin,
40 Lvmin,
41 Dvmin,
42 Vmax,
43 Svmax,
44 Lvmax,
45 Dvmax,
46
47 Cm,
49 Mm,
50 Q,
51 In,
52 Pc,
53 Pt,
54 Px,
55
56 Cqw,
58 Cqh,
59 Cqi,
60 Cqb,
61 Cqmin,
62 Cqmax,
63 }
64 };
65}
66
67macro_rules! define_length {
68 ( $($name: ident),+ $(,)* ) => {
69 #[derive(Parse, Peek, IntoCursor, ToCursors, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
70 #[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
71 #[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
72 pub enum Length {
73 Zero(#[in_range(0.0..0.0)] T![Number]),
74 $(
75 #[atom(CssAtomSet::$name)]
76 $name(T![Dimension]),
77 )+
78 }
79 }
80}
81apply_lengths!(define_length);
82
83impl Length {
84 const PX_CM: f32 = Self::PX_IN / 2.54;
85 const PX_MM: f32 = Self::PX_IN / 25.4;
86 const PX_Q: f32 = Self::PX_MM / 4.0;
87 const PX_IN: f32 = 96.0;
88 const PX_PC: f32 = Self::PX_IN / 6.0;
89 const PX_PT: f32 = Self::PX_IN / 72.0;
90
91 pub fn to_px(&self) -> Option<f32> {
92 match self {
93 Self::Zero(_) => Some(0.0),
94 Self::Cm(d) => Some(Into::<f32>::into(*d) * Self::PX_CM),
95 Self::Mm(d) => Some(Into::<f32>::into(*d) * Self::PX_MM),
96 Self::Q(d) => Some(Into::<f32>::into(*d) * Self::PX_Q),
97 Self::In(d) => Some(Into::<f32>::into(*d) * Self::PX_IN),
98 Self::Pc(d) => Some(Into::<f32>::into(*d) * Self::PX_PC),
99 Self::Pt(d) => Some(Into::<f32>::into(*d) * Self::PX_PT),
100 _ => None,
101 }
102 }
103}
104
105impl From<Length> for f32 {
106 fn from(val: Length) -> Self {
107 macro_rules! match_length {
108 ( $($name: ident),+ $(,)* ) => {
109 match val {
110 Length::Zero(_) => 0.0,
111 $(Length::$name(f) => f.into()),+
112 }
113 }
114 }
115 apply_lengths!(match_length)
116 }
117}
118
119impl PartialEq<f32> for Length {
120 fn eq(&self, other: &f32) -> bool {
121 let f: f32 = (*self).into();
122 f == *other
123 }
124}
125
126impl ToNumberValue for Length {
127 fn to_number_value(&self) -> Option<f32> {
128 Some((*self).into())
129 }
130}
131
132#[derive(Parse, Peek, IntoCursor, ToCursors, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
133#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
134#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
135pub enum LengthPercentage {
136 #[cfg_attr(feature = "visitable", visit(skip))]
137 Zero(#[in_range(0.0..0.0)] T![Number]),
138 Length(Length),
139 #[cfg_attr(feature = "visitable", visit(skip))]
140 Percent(Percentage),
141}
142
143impl From<LengthPercentage> for f32 {
144 fn from(val: LengthPercentage) -> Self {
145 match val {
146 LengthPercentage::Zero(_) => 0.0,
147 LengthPercentage::Percent(f) => f.into(),
148 LengthPercentage::Length(f) => f.into(),
149 }
150 }
151}
152
153impl ToNumberValue for LengthPercentage {
154 fn to_number_value(&self) -> Option<f32> {
155 Some((*self).into())
156 }
157}
158
159#[derive(Parse, Peek, IntoCursor, ToCursors, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
160#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
161#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(children))]
162pub enum LengthPercentageOrFlex {
163 Flex(Flex),
164 LengthPercentage(LengthPercentage),
165}
166
167#[derive(Parse, Peek, ToCursors, IntoCursor, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
168#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
169#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
170pub enum NumberLength {
171 #[cfg_attr(feature = "visitable", visit(skip))]
172 Number(T![Number]),
173 Length(Length),
174}
175
176impl From<NumberLength> for f32 {
177 fn from(val: NumberLength) -> Self {
178 match val {
179 NumberLength::Number(n) => n.into(),
180 NumberLength::Length(n) => n.into(),
181 }
182 }
183}
184
185impl ToNumberValue for NumberLength {
186 fn to_number_value(&self) -> Option<f32> {
187 Some((*self).into())
188 }
189}
190
191#[cfg(test)]
192mod tests {
193 use super::*;
194 use crate::CssAtomSet;
195 use css_parse::assert_parse;
196
197 #[test]
198 fn size_test() {
199 assert_eq!(std::mem::size_of::<Length>(), 16);
200 assert_eq!(std::mem::size_of::<LengthPercentage>(), 16);
201 assert_eq!(std::mem::size_of::<NumberLength>(), 16);
202 }
203
204 #[test]
205 fn test_writes() {
206 assert_parse!(CssAtomSet::ATOMS, Length, "10px");
207 assert_parse!(CssAtomSet::ATOMS, Length, "1.2345679px");
209 assert_parse!(CssAtomSet::ATOMS, Length, "-1px");
211 assert_parse!(CssAtomSet::ATOMS, LengthPercentage, "1%");
213 }
214}