Skip to main content

css_ast/types/
single_transition.rs

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