1use super::prelude::*;
2use crate::{EasingFunction, NoneOr, SingleTransitionProperty, Time, TransitionBehaviorValue};
3use css_parse::parse_optionals;
4
5#[derive(ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
8#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
9#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
10pub struct SingleTransition<'a> {
11 #[cfg_attr(feature = "visitable", visit(skip))]
12 pub property: Option<NoneOr<SingleTransitionProperty>>,
13 pub duration: Option<Time>,
14 pub easing: Option<EasingFunction<'a>>,
15 pub delay: Option<Time>,
16 #[cfg_attr(feature = "visitable", visit(skip))]
17 pub behavior: Option<TransitionBehaviorValue>,
18}
19
20impl<'a> Peek<'a> for SingleTransition<'a> {
21 fn peek<I>(p: &Parser<'a, I>, c: Cursor) -> bool
22 where
23 I: Iterator<Item = Cursor> + Clone,
24 {
25 <NoneOr<SingleTransitionProperty>>::peek(p, c) || EasingFunction::peek(p, c) || Time::peek(p, c)
26 }
27}
28
29impl<'a> Parse<'a> for SingleTransition<'a> {
30 fn parse<I>(p: &mut Parser<'a, I>) -> ParserResult<Self>
31 where
32 I: Iterator<Item = Cursor> + Clone,
33 {
34 let (easing, property, duration, delay, behavior) = parse_optionals!(p, easing: EasingFunction, property: NoneOr<SingleTransitionProperty>, duration: Time, delay: Time, behavior: TransitionBehaviorValue);
35 Ok(Self { easing, property, duration, delay, behavior })
36 }
37}
38
39#[cfg(test)]
40mod tests {
41 use super::*;
42 use crate::CssAtomSet;
43 use css_parse::{assert_parse, assert_parse_error};
44
45 type NoneOrSingleTransitionProperty = NoneOr<SingleTransitionProperty>;
46
47 #[test]
48 fn size_test() {
49 assert_eq!(std::mem::size_of::<SingleTransition>(), 184);
50 }
51
52 #[test]
53 fn test_writes() {
54 assert_parse!(
55 CssAtomSet::ATOMS,
56 NoneOrSingleTransitionProperty,
57 "none",
58 NoneOrSingleTransitionProperty::None(_)
59 );
60 assert_parse!(
61 CssAtomSet::ATOMS,
62 NoneOrSingleTransitionProperty,
63 "all",
64 NoneOrSingleTransitionProperty::Some(_)
65 );
66
67 assert_parse!(CssAtomSet::ATOMS, SingleTransition, "none");
68 assert_parse!(CssAtomSet::ATOMS, SingleTransition, "opacity");
69 assert_parse!(CssAtomSet::ATOMS, SingleTransition, "opacity 1s");
70 assert_parse!(CssAtomSet::ATOMS, SingleTransition, "opacity 1s ease-in");
71 assert_parse!(CssAtomSet::ATOMS, SingleTransition, "opacity 1s ease-in 2s");
72 assert_parse!(CssAtomSet::ATOMS, SingleTransition, "2s ease-in");
73 assert_parse!(CssAtomSet::ATOMS, SingleTransition, "1s opacity");
74 assert_parse!(CssAtomSet::ATOMS, SingleTransition, "ease-in 1s opacity");
75 assert_parse!(CssAtomSet::ATOMS, SingleTransition, "1s 2s ease-in opacity");
76 assert_parse!(CssAtomSet::ATOMS, SingleTransition, "ease-in opacity 1s 2s");
77 assert_parse!(CssAtomSet::ATOMS, SingleTransition, "ease-in");
78 assert_parse!(CssAtomSet::ATOMS, SingleTransition, "1s");
79 assert_parse!(CssAtomSet::ATOMS, SingleTransition, "1s 2s");
80 assert_parse!(CssAtomSet::ATOMS, SingleTransition, "all 1s ease-in 2s");
81 assert_parse!(CssAtomSet::ATOMS, SingleTransition, "none 1s");
82 assert_parse!(CssAtomSet::ATOMS, SingleTransition, "none 1s normal");
83 assert_parse!(CssAtomSet::ATOMS, SingleTransition, "1s opacity allow-discrete");
84 }
85
86 #[test]
87 fn test_errors() {
88 assert_parse_error!(CssAtomSet::ATOMS, SingleTransition, "1deg");
89 assert_parse_error!(CssAtomSet::ATOMS, SingleTransition, "none none");
90 }
91
92 #[test]
93 #[cfg(feature = "visitable")]
94 fn test_visits() {
95 use crate::assert_visits;
96 assert_visits!("1s", SingleTransition, Time);
97 assert_visits!("ease-in", SingleTransition, EasingFunction);
98 assert_visits!("1s 2s", SingleTransition, Time, Time);
99 assert_visits!("1s ease-in 2s", SingleTransition, Time, EasingFunction, Time);
100 }
101}