css_ast/types/
bg_layer.rs1use super::prelude::*;
2use crate::{Attachment, BgClip, BgImage, BgPositionAndSize, Color, RepeatStyle, VisualBox};
3
4#[derive(ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
18#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
19#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
20#[derive(csskit_derives::NodeWithMetadata)]
21pub struct BgLayer<'a> {
22 pub image: Option<BgImage<'a>>,
23 pub position: Option<BgPositionAndSize>,
24 pub repeat: Option<RepeatStyle>,
25 pub attachment: Option<Attachment>,
26 pub origin: Option<VisualBox>,
27 pub clip: Option<BgClip>,
28 pub color: Option<Color<'a>>,
29}
30
31impl<'a> Peek<'a> for BgLayer<'a> {
32 const PEEK_KINDSET: KindSet = BgImage::PEEK_KINDSET
33 .combine(BgPositionAndSize::PEEK_KINDSET)
34 .combine(RepeatStyle::PEEK_KINDSET)
35 .combine(Attachment::PEEK_KINDSET)
36 .combine(VisualBox::PEEK_KINDSET)
37 .combine(BgClip::PEEK_KINDSET)
38 .combine(Color::PEEK_KINDSET);
39
40 #[inline(always)]
41 fn peek<I>(p: &Parser<'a, I>, c: Cursor) -> bool
42 where
43 I: Iterator<Item = Cursor> + Clone,
44 {
45 BgImage::peek(p, c)
46 || BgPositionAndSize::peek(p, c)
47 || RepeatStyle::peek(p, c)
48 || Attachment::peek(p, c)
49 || VisualBox::peek(p, c)
50 || BgClip::peek(p, c)
51 || Color::peek(p, c)
52 }
53}
54
55impl<'a> Parse<'a> for BgLayer<'a> {
56 fn parse<I>(p: &mut Parser<'a, I>) -> ParserResult<Self>
57 where
58 I: Iterator<Item = Cursor> + Clone,
59 {
60 let mut image: Option<BgImage<'a>> = None;
61 let mut position: Option<BgPositionAndSize> = None;
62 let mut repeat: Option<RepeatStyle> = None;
63 let mut attachment: Option<Attachment> = None;
64 let mut origin: Option<VisualBox> = None;
65 let mut clip: Option<BgClip> = None;
66 let mut color: Option<Color<'a>> = None;
67
68 let mut any = false;
69 loop {
70 if image.is_none()
71 && let Some(v) = p.parse_if_peek::<BgImage<'a>>()?
72 {
73 image = Some(v);
74 any = true;
75 continue;
76 }
77 if position.is_none()
78 && let Some(v) = p.parse_if_peek::<BgPositionAndSize>()?
79 {
80 position = Some(v);
81 any = true;
82 continue;
83 }
84 if repeat.is_none()
85 && let Some(v) = p.parse_if_peek::<RepeatStyle>()?
86 {
87 repeat = Some(v);
88 any = true;
89 continue;
90 }
91 if attachment.is_none()
92 && let Some(v) = p.parse_if_peek::<Attachment>()?
93 {
94 attachment = Some(v);
95 any = true;
96 continue;
97 }
98 if origin.is_none()
100 && clip.is_none()
101 && let Some(v) = p.parse_if_peek::<VisualBox>()?
102 {
103 origin = Some(v);
104 any = true;
105 continue;
106 }
107 if clip.is_none()
109 && let Some(v) = p.parse_if_peek::<BgClip>()?
110 {
111 clip = Some(v);
112 any = true;
113 continue;
114 }
115 if color.is_none()
117 && let Some(v) = p.parse_if_peek::<Color<'a>>()?
118 {
119 color = Some(v);
120 any = true;
121 continue;
122 }
123 break;
124 }
125
126 if !any {
127 Err(Diagnostic::new(p.next(), Diagnostic::unexpected))?
128 }
129
130 Ok(Self { image, position, repeat, attachment, origin, clip, color })
131 }
132}
133
134#[cfg(test)]
135mod tests {
136 use super::*;
137 use crate::CssAtomSet;
138 use css_parse::{assert_parse, assert_parse_error};
139
140 #[test]
141 fn size_test() {
142 assert_eq!(std::mem::size_of::<BgLayer>(), 256);
143 }
144
145 #[test]
146 fn test_writes() {
147 assert_parse!(CssAtomSet::ATOMS, BgLayer, "none");
148 assert_parse!(CssAtomSet::ATOMS, BgLayer, "url(foo.png)");
149 assert_parse!(CssAtomSet::ATOMS, BgLayer, "red");
150 assert_parse!(CssAtomSet::ATOMS, BgLayer, "#fff");
151 assert_parse!(CssAtomSet::ATOMS, BgLayer, "center");
152 assert_parse!(CssAtomSet::ATOMS, BgLayer, "0 0");
153 assert_parse!(CssAtomSet::ATOMS, BgLayer, "center / cover");
154 assert_parse!(CssAtomSet::ATOMS, BgLayer, "repeat-x");
155 assert_parse!(CssAtomSet::ATOMS, BgLayer, "no-repeat");
156 assert_parse!(CssAtomSet::ATOMS, BgLayer, "fixed");
157 assert_parse!(CssAtomSet::ATOMS, BgLayer, "url(bg.png) center no-repeat");
158 assert_parse!(CssAtomSet::ATOMS, BgLayer, "url(bg.png) 0 0 / cover no-repeat fixed");
159 assert_parse!(CssAtomSet::ATOMS, BgLayer, "url(bg.png) 0 0 / cover no-repeat fixed red");
160 }
161
162 #[test]
163 fn test_errors() {
164 assert_parse_error!(CssAtomSet::ATOMS, BgLayer, "");
165 }
166}