css_ast/units/
time.rs

1use css_parse::{Build, Cursor, Parser, Peek, T, ToNumberValue};
2use csskit_derives::{IntoCursor, ToCursors, Visitable};
3
4// https://drafts.csswg.org/css-values/#resolution
5#[derive(IntoCursor, ToCursors, Visitable, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
6#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
7#[visit(self)]
8pub enum Time {
9	Zero(T![Number]),
10	Ms(T![Dimension::Ms]),
11	S(T![Dimension::S]),
12}
13
14impl From<Time> for f32 {
15	fn from(val: Time) -> Self {
16		match val {
17			Time::Zero(_) => 0.0,
18			Time::Ms(f) => f.into(),
19			Time::S(f) => f.into(),
20		}
21	}
22}
23
24impl ToNumberValue for Time {
25	fn to_number_value(&self) -> Option<f32> {
26		Some((*self).into())
27	}
28}
29
30impl<'a> Peek<'a> for Time {
31	fn peek(p: &Parser<'a>, c: Cursor) -> bool {
32		(<T![Number]>::peek(p, c) && c.token().value() == 0.0)
33			|| <T![Dimension::Ms]>::peek(p, c)
34			|| <T![Dimension::S]>::peek(p, c)
35	}
36}
37
38impl<'a> Build<'a> for Time {
39	fn build(p: &Parser<'a>, c: Cursor) -> Self {
40		if <T![Number]>::peek(p, c) && c.token().value() == 0.0 {
41			Self::Zero(<T![Number]>::build(p, c))
42		} else if <T![Dimension::S]>::peek(p, c) {
43			Self::S(<T![Dimension::S]>::build(p, c))
44		} else {
45			Self::Ms(<T![Dimension::Ms]>::build(p, c))
46		}
47	}
48}
49
50#[cfg(test)]
51mod tests {
52	use super::*;
53	use css_parse::{assert_parse, assert_parse_error};
54
55	#[test]
56	fn size_test() {
57		assert_eq!(std::mem::size_of::<Time>(), 16);
58	}
59
60	#[test]
61	fn test_writes() {
62		assert_parse!(Time, "0");
63		assert_parse!(Time, "0s");
64		assert_parse!(Time, "0ms");
65	}
66
67	#[test]
68	fn test_errors() {
69		assert_parse_error!(Time, "1");
70		assert_parse_error!(Time, "foo");
71	}
72}