css_ast/types/
opacity_value.rs1use css_parse::{Build, Cursor, Parser, Peek, T};
2use csskit_derives::{IntoCursor, ToCursors, Visitable};
3
4#[derive(IntoCursor, ToCursors, Visitable, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5#[cfg_attr(feature = "serde", derive(serde::Serialize))]
6#[visit(self)]
7pub enum OpacityValue {
8 Number(T![Number]),
9 Percent(T![Dimension::%]),
10}
11
12impl OpacityValue {
13 #[allow(non_upper_case_globals)]
14 pub const Zero: OpacityValue = OpacityValue::Number(<T![Number]>::NUMBER_ZERO);
15}
16
17impl From<OpacityValue> for i32 {
18 fn from(value: OpacityValue) -> Self {
19 match value {
20 OpacityValue::Number(t) => t.into(),
21 OpacityValue::Percent(t) => t.into(),
22 }
23 }
24}
25
26impl From<OpacityValue> for f32 {
27 fn from(value: OpacityValue) -> Self {
28 match value {
29 OpacityValue::Number(t) => t.into(),
30 OpacityValue::Percent(t) => t.into(),
31 }
32 }
33}
34
35impl<'a> Peek<'a> for OpacityValue {
36 fn peek(p: &Parser<'a>, c: Cursor) -> bool {
37 (<T![Number]>::peek(p, c) && (0.0..=1.0).contains(&c.token().value()))
38 || (<T![Dimension::%]>::peek(p, c) && (0.0..=100.0).contains(&c.token().value()))
39 }
40}
41
42impl<'a> Build<'a> for OpacityValue {
43 fn build(p: &Parser<'a>, c: Cursor) -> Self {
44 if <T![Number]>::peek(p, c) {
45 Self::Number(<T![Number]>::build(p, c))
46 } else {
47 Self::Percent(<T![Dimension::%]>::build(p, c))
48 }
49 }
50}
51
52#[cfg(test)]
53mod tests {
54 use super::*;
55 use css_parse::{assert_parse, assert_parse_error};
56
57 #[test]
58 fn size_test() {
59 assert_eq!(std::mem::size_of::<OpacityValue>(), 16);
60 }
61
62 #[test]
63 fn test_writes() {
64 assert_parse!(OpacityValue, "0.1");
65 assert_parse!(OpacityValue, "1");
66 assert_parse!(OpacityValue, "50%");
67 }
68
69 #[test]
70 fn test_errors() {
71 assert_parse_error!(OpacityValue, "20");
72 assert_parse_error!(OpacityValue, "1000%");
73 }
74
75 }