css_lexer/
dimension_unit.rs

1use std::hash::Hash;
2
3/// Represents a [Kind::Dimension's][crate::Kind::Dimension] unit, if it is "known": defined by the CSS grammar.
4///
5/// In order to more efficiently lex CSS, the known dimension units are encoded into [Tokens][crate::Token]. This
6/// avoids the need for subsequent downstream passes to consult the underlying string data to establish what kind of
7/// dimension unit the [Kind::Dimension][crate::Kind::Dimension] represents.
8///
9/// This enum captures all known and defined units per the CSS specifications. Custom units (e.g. those beginning with a
10/// double dash (`--`)), unknown units, or units using escape characters will all be represented using the
11/// [DimensionUnit::Unknown] variant which means the underlying `&str` must be consulted.
12///
13/// # Example
14///
15/// ```
16/// use css_lexer::*;
17/// let mut lexer = Lexer::new("10px");
18/// {
19///     let token = lexer.advance();
20///     assert_eq!(token, Kind::Dimension);
21///     assert_eq!(token, DimensionUnit::Px);
22///     let unit = token.dimension_unit();
23///     let str: &'static str = unit.into();
24///     assert_eq!(str, "px");
25/// }
26/// ```
27#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
28#[cfg_attr(feature = "serde", derive(serde::Serialize), serde(rename_all = "lowercase"))]
29pub enum DimensionUnit {
30	#[default]
31	Unknown = 0,
32	Cap,
33	Ch,
34	Cm,
35	Cqb,
36	Cqh,
37	Cqi,
38	Cqmax,
39	Cqmin,
40	Cqw,
41	Db,
42	Deg,
43	Dpcm,
44	Dpi,
45	Dppx,
46	Dvb,
47	Dvh,
48	Dvi,
49	Dvmax,
50	Dvmin,
51	Dvw,
52	Em,
53	Ex,
54	Fr,
55	Grad,
56	Hz,
57	Ic,
58	In,
59	Khz,
60	Lh,
61	Lvb,
62	Lvh,
63	Lvi,
64	Lvmax,
65	Lvmin,
66	Lvw,
67	Mm,
68	Ms,
69	Pc,
70	#[cfg_attr(feature = "serde", serde(rename = "%"))]
71	Percent,
72	Pt,
73	Px,
74	Q,
75	Rad,
76	Rcap,
77	Rch,
78	Rem,
79	Rex,
80	Ric,
81	Rlh,
82	S,
83	Svb,
84	Svh,
85	Svi,
86	Svmax,
87	Svmin,
88	Svw,
89	Turn,
90	Vb,
91	Vh,
92	Vi,
93	Vmax,
94	Vmin,
95	Vw,
96	X,
97}
98
99impl DimensionUnit {
100	pub fn is_empty(&self) -> bool {
101		self == &Self::Unknown
102	}
103
104	pub const fn len(&self) -> u32 {
105		match self {
106			Self::Unknown => 0,
107			Self::Percent | Self::Q | Self::S | Self::X => 1,
108			Self::Db
109			| Self::Ch
110			| Self::Cm
111			| Self::Em
112			| Self::Ex
113			| Self::Fr
114			| Self::Hz
115			| Self::Ic
116			| Self::In
117			| Self::Lh
118			| Self::Mm
119			| Self::Ms
120			| Self::Pc
121			| Self::Pt
122			| Self::Px
123			| Self::Vb
124			| Self::Vh
125			| Self::Vi
126			| Self::Vw => 2,
127			Self::Cap
128			| Self::Cqb
129			| Self::Cqh
130			| Self::Cqi
131			| Self::Cqw
132			| Self::Deg
133			| Self::Dpi
134			| Self::Dvb
135			| Self::Dvi
136			| Self::Dvh
137			| Self::Dvw
138			| Self::Khz
139			| Self::Lvb
140			| Self::Lvi
141			| Self::Lvh
142			| Self::Lvw
143			| Self::Rad
144			| Self::Rch
145			| Self::Rem
146			| Self::Rex
147			| Self::Ric
148			| Self::Rlh
149			| Self::Svb
150			| Self::Svi
151			| Self::Svh
152			| Self::Svw => 3,
153			Self::Dpcm | Self::Dppx | Self::Grad | Self::Rcap | Self::Turn | Self::Vmax | Self::Vmin => 4,
154			Self::Dvmax
155			| Self::Dvmin
156			| Self::Lvmax
157			| Self::Lvmin
158			| Self::Svmax
159			| Self::Svmin
160			| Self::Cqmax
161			| Self::Cqmin => 5,
162		}
163	}
164
165	pub(crate) const fn from_u8(value: u8) -> Self {
166		let unit = match value {
167			1 => Self::Cap,
168			2 => Self::Ch,
169			3 => Self::Cm,
170			4 => Self::Cqb,
171			5 => Self::Cqh,
172			6 => Self::Cqi,
173			7 => Self::Cqmax,
174			8 => Self::Cqmin,
175			9 => Self::Cqw,
176			10 => Self::Db,
177			11 => Self::Deg,
178			12 => Self::Dpcm,
179			13 => Self::Dpi,
180			14 => Self::Dppx,
181			15 => Self::Dvb,
182			16 => Self::Dvh,
183			17 => Self::Dvi,
184			18 => Self::Dvmax,
185			19 => Self::Dvmin,
186			20 => Self::Dvw,
187			21 => Self::Em,
188			22 => Self::Ex,
189			23 => Self::Fr,
190			24 => Self::Grad,
191			25 => Self::Hz,
192			26 => Self::Ic,
193			27 => Self::In,
194			28 => Self::Khz,
195			29 => Self::Lh,
196			30 => Self::Lvb,
197			31 => Self::Lvh,
198			32 => Self::Lvi,
199			33 => Self::Lvmax,
200			34 => Self::Lvmin,
201			35 => Self::Lvw,
202			36 => Self::Mm,
203			37 => Self::Ms,
204			38 => Self::Pc,
205			39 => Self::Percent,
206			40 => Self::Pt,
207			41 => Self::Px,
208			42 => Self::Q,
209			43 => Self::Rad,
210			44 => Self::Rcap,
211			45 => Self::Rch,
212			46 => Self::Rem,
213			47 => Self::Rex,
214			48 => Self::Ric,
215			49 => Self::Rlh,
216			50 => Self::S,
217			51 => Self::Svb,
218			52 => Self::Svh,
219			53 => Self::Svi,
220			54 => Self::Svmax,
221			55 => Self::Svmin,
222			56 => Self::Svw,
223			57 => Self::Turn,
224			58 => Self::Vb,
225			59 => Self::Vh,
226			60 => Self::Vi,
227			61 => Self::Vmax,
228			62 => Self::Vmin,
229			63 => Self::Vw,
230			64 => Self::X,
231			_ => Self::Unknown,
232		};
233		debug_assert!(unit as u8 == value, "DimensionUnit::from_u8 failed as unit was not equal to value");
234		unit
235	}
236}
237
238impl From<u8> for DimensionUnit {
239	fn from(value: u8) -> Self {
240		Self::from_u8(value)
241	}
242}
243
244impl From<&str> for DimensionUnit {
245	fn from(value: &str) -> Self {
246		match value {
247			"cap" => Self::Cap,
248			"ch" => Self::Ch,
249			"cm" => Self::Cm,
250			"cqb" => Self::Cqb,
251			"cqh" => Self::Cqh,
252			"cqi" => Self::Cqi,
253			"cqmax" => Self::Cqmax,
254			"cqmin" => Self::Cqmin,
255			"cqw" => Self::Cqw,
256			"deg" => Self::Deg,
257			"dpcm" => Self::Dpcm,
258			"dpi" => Self::Dpi,
259			"dppx" => Self::Dppx,
260			"dvb" => Self::Dvb,
261			"dvh" => Self::Dvh,
262			"dvi" => Self::Dvi,
263			"dvmax" => Self::Dvmax,
264			"dvmin" => Self::Dvmin,
265			"dvw" => Self::Dvw,
266			"em" => Self::Em,
267			"ex" => Self::Ex,
268			"fr" => Self::Fr,
269			"grad" => Self::Grad,
270			"hz" => Self::Hz,
271			"ic" => Self::Ic,
272			"in" => Self::In,
273			"khz" => Self::Khz,
274			"lh" => Self::Lh,
275			"lvb" => Self::Lvb,
276			"lvh" => Self::Lvh,
277			"lvi" => Self::Lvi,
278			"lvmax" => Self::Lvmax,
279			"lvmin" => Self::Lvmin,
280			"lvw" => Self::Lvw,
281			"mm" => Self::Mm,
282			"ms" => Self::Ms,
283			"pc" => Self::Pc,
284			"percent" => Self::Percent,
285			"pt" => Self::Pt,
286			"px" => Self::Px,
287			"q" => Self::Q,
288			"rad" => Self::Rad,
289			"rcap" => Self::Rcap,
290			"rch" => Self::Rch,
291			"rem" => Self::Rem,
292			"rex" => Self::Rex,
293			"ric" => Self::Ric,
294			"rlh" => Self::Rlh,
295			"s" => Self::S,
296			"svb" => Self::Svb,
297			"svh" => Self::Svh,
298			"svi" => Self::Svi,
299			"svmax" => Self::Svmax,
300			"svmin" => Self::Svmin,
301			"svw" => Self::Svw,
302			"turn" => Self::Turn,
303			"vb" => Self::Vb,
304			"vh" => Self::Vh,
305			"vi" => Self::Vi,
306			"vmax" => Self::Vmax,
307			"vmin" => Self::Vmin,
308			"vw" => Self::Vw,
309			"x" => Self::X,
310			_ => Self::Unknown,
311		}
312	}
313}
314
315impl From<DimensionUnit> for &'static str {
316	fn from(value: DimensionUnit) -> &'static str {
317		match value {
318			DimensionUnit::Unknown => "",
319			DimensionUnit::Cap => "cap",
320			DimensionUnit::Ch => "ch",
321			DimensionUnit::Cm => "cm",
322			DimensionUnit::Cqb => "cqb",
323			DimensionUnit::Cqh => "cqh",
324			DimensionUnit::Cqi => "cqi",
325			DimensionUnit::Cqmax => "cqmax",
326			DimensionUnit::Cqmin => "cqmin",
327			DimensionUnit::Cqw => "cqw",
328			DimensionUnit::Db => "db",
329			DimensionUnit::Deg => "deg",
330			DimensionUnit::Dpcm => "dpcm",
331			DimensionUnit::Dpi => "dpi",
332			DimensionUnit::Dppx => "dppx",
333			DimensionUnit::Dvb => "dvb",
334			DimensionUnit::Dvh => "dvh",
335			DimensionUnit::Dvi => "dvi",
336			DimensionUnit::Dvmax => "dvmax",
337			DimensionUnit::Dvmin => "dvmin",
338			DimensionUnit::Dvw => "dvw",
339			DimensionUnit::Em => "em",
340			DimensionUnit::Ex => "ex",
341			DimensionUnit::Fr => "fr",
342			DimensionUnit::Grad => "grad",
343			DimensionUnit::Hz => "hz",
344			DimensionUnit::Ic => "ic",
345			DimensionUnit::In => "in",
346			DimensionUnit::Khz => "khz",
347			DimensionUnit::Lh => "lh",
348			DimensionUnit::Lvb => "lvb",
349			DimensionUnit::Lvh => "lvh",
350			DimensionUnit::Lvi => "lvi",
351			DimensionUnit::Lvmax => "lvmax",
352			DimensionUnit::Lvmin => "lvmin",
353			DimensionUnit::Lvw => "lvw",
354			DimensionUnit::Mm => "mm",
355			DimensionUnit::Ms => "ms",
356			DimensionUnit::Pc => "pc",
357			DimensionUnit::Percent => "%",
358			DimensionUnit::Pt => "pt",
359			DimensionUnit::Px => "px",
360			DimensionUnit::Q => "q",
361			DimensionUnit::Rad => "rad",
362			DimensionUnit::Rcap => "rcap",
363			DimensionUnit::Rch => "rch",
364			DimensionUnit::Rem => "rem",
365			DimensionUnit::Rex => "rex",
366			DimensionUnit::Ric => "ric",
367			DimensionUnit::Rlh => "rlh",
368			DimensionUnit::S => "s",
369			DimensionUnit::Svb => "svb",
370			DimensionUnit::Svh => "svh",
371			DimensionUnit::Svi => "svi",
372			DimensionUnit::Svmax => "svmin",
373			DimensionUnit::Svmin => "svmax",
374			DimensionUnit::Svw => "svw",
375			DimensionUnit::Turn => "turn",
376			DimensionUnit::Vb => "vb",
377			DimensionUnit::Vh => "vh",
378			DimensionUnit::Vi => "vi",
379			DimensionUnit::Vmax => "vmax",
380			DimensionUnit::Vmin => "vmin",
381			DimensionUnit::Vw => "vw",
382			DimensionUnit::X => "x",
383		}
384	}
385}
386
387#[test]
388fn size_test() {
389	assert_eq!(::std::mem::size_of::<DimensionUnit>(), 1);
390}