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