1use super::prelude::*;
2
3#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
9#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
10#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(skip))]
11#[derive(csskit_derives::NodeWithMetadata)]
12pub enum VoiceAge {
13 #[atom(CssAtomSet::Child)]
14 Child(T![Ident]),
15 #[atom(CssAtomSet::Young)]
16 Young(T![Ident]),
17 #[atom(CssAtomSet::Old)]
18 Old(T![Ident]),
19}
20
21#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
27#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
28#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(skip))]
29#[derive(csskit_derives::NodeWithMetadata)]
30pub enum VoiceGender {
31 #[atom(CssAtomSet::Male)]
32 Male(T![Ident]),
33 #[atom(CssAtomSet::Female)]
34 Female(T![Ident]),
35 #[atom(CssAtomSet::Neutral)]
36 Neutral(T![Ident]),
37}
38
39#[derive(ToCursors, ToSpan, SemanticEq, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
45#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
46#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
47#[derive(csskit_derives::NodeWithMetadata)]
48pub struct GenericVoice {
49 pub age: Option<VoiceAge>,
50 pub gender: VoiceGender,
51 pub variant: Option<T![Number]>,
52}
53
54impl<'a> Peek<'a> for GenericVoice {
55 const PEEK_KINDSET: KindSet = VoiceAge::PEEK_KINDSET.combine(VoiceGender::PEEK_KINDSET);
56
57 #[inline(always)]
58 fn peek<I>(p: &Parser<'a, I>, c: Cursor) -> bool
59 where
60 I: Iterator<Item = Cursor> + Clone,
61 {
62 VoiceAge::peek(p, c) || VoiceGender::peek(p, c)
63 }
64}
65
66impl<'a> Parse<'a> for GenericVoice {
67 fn parse<I>(p: &mut Parser<'a, I>) -> ParserResult<Self>
68 where
69 I: Iterator<Item = Cursor> + Clone,
70 {
71 let age = p.parse_if_peek::<VoiceAge>()?;
72 let gender = p.parse::<VoiceGender>()?;
73 let variant = p.parse_if_peek::<T![Number]>()?;
74 Ok(Self { age, gender, variant })
75 }
76}
77
78#[cfg(test)]
79mod tests {
80 use super::*;
81 use crate::CssAtomSet;
82 use css_parse::{assert_parse, assert_parse_error};
83
84 #[test]
85 fn size_test() {
86 assert_eq!(std::mem::size_of::<VoiceAge>(), 16);
87 assert_eq!(std::mem::size_of::<VoiceGender>(), 16);
88 assert_eq!(std::mem::size_of::<GenericVoice>(), 48);
89 }
90
91 #[test]
92 fn test_parses() {
93 assert_parse!(CssAtomSet::ATOMS, GenericVoice, "male");
94 assert_parse!(CssAtomSet::ATOMS, GenericVoice, "female");
95 assert_parse!(CssAtomSet::ATOMS, GenericVoice, "neutral");
96 assert_parse!(CssAtomSet::ATOMS, GenericVoice, "child male");
97 assert_parse!(CssAtomSet::ATOMS, GenericVoice, "young female 2");
98 assert_parse!(CssAtomSet::ATOMS, GenericVoice, "old neutral 1");
99 }
100
101 #[test]
102 fn test_errors() {
103 assert_parse_error!(CssAtomSet::ATOMS, GenericVoice, "");
104 assert_parse_error!(CssAtomSet::ATOMS, GenericVoice, "child");
105 assert_parse_error!(CssAtomSet::ATOMS, GenericVoice, "auto");
106 }
107}