1use super::{
2 BorderImageOutsetStyleValue, BorderImageRepeatStyleValue, BorderImageSliceStyleValue, BorderImageSourceStyleValue,
3 BorderImageStyleValue, BorderImageWidthStyleValue,
4};
5use css_parse::{Cursor, Diagnostic, Optionals3, Parse, Parser, Result as ParseResult, T};
6
7impl<'a> Parse<'a> for BorderImageStyleValue<'a> {
8 fn parse<I>(p: &mut Parser<'a, I>) -> ParseResult<Self>
9 where
10 I: Iterator<Item = Cursor> + Clone,
11 {
12 let mut source = None;
13 let mut slice = None;
14 let mut width = None;
15 let mut outset = None;
16 let mut repeat = None;
17 loop {
18 if source.is_none() && p.peek::<BorderImageSourceStyleValue>() {
19 source = Some(p.parse::<BorderImageSourceStyleValue>()?);
20 } else if slice.is_none() && p.peek::<BorderImageSliceStyleValue>() {
21 slice = Some(p.parse::<BorderImageSliceStyleValue>()?);
22 if p.peek::<T![/]>() {
23 let slash = p.parse::<T![/]>()?;
24 let first = p.parse_if_peek::<BorderImageWidthStyleValue>()?;
25 if p.peek::<T![/]>() {
26 let second_slash = p.parse::<T![/]>()?;
27 outset = Some((slash, first, second_slash, p.parse::<BorderImageOutsetStyleValue>()?));
28 } else if let Some(first) = first {
29 width = Some((slash, first));
30 } else {
31 Err(Diagnostic::new(p.peek_n(1), Diagnostic::unexpected))?
32 }
33 }
34 } else if repeat.is_none() && p.peek::<BorderImageRepeatStyleValue>() {
35 repeat = Some(p.parse::<BorderImageRepeatStyleValue>()?);
36 } else {
37 break;
38 }
39 }
40 if let Some(outset) = outset {
41 let slice = slice.expect("outset is only parsed after slice");
42 return Ok(Self::BorderImageSourceBorderImageSliceBorderImageOutsetBorderImageRepeat {
43 border_image_source: source,
44 border_image_slice_border_image_outset: Some((slice, outset)),
45 border_image_repeat: repeat,
46 });
47 }
48 if let Some(width) = width {
49 let slice = slice.expect("width is only parsed after slice");
50 return Ok(Self::BorderImageSourceBorderImageSliceBorderImageWidthBorderImageRepeat {
51 border_image_source: source,
52 border_image_slice_border_image_width: Some((slice, width)),
53 border_image_repeat: repeat,
54 });
55 }
56 if source.is_none() && slice.is_none() && repeat.is_none() {
57 Err(Diagnostic::new(p.peek_n(1), Diagnostic::unexpected))?
58 }
59 Ok(Self::BorderImageSourceBorderImageSliceBorderImageRepeat(Optionals3(source, slice, repeat)))
60 }
61}
62
63#[cfg(test)]
64mod tests {
65 use super::super::*;
66 use crate::CssAtomSet;
67 use css_parse::{assert_parse, assert_parse_error, assert_peek_false};
68
69 #[test]
70 fn test_box_shadow_offset() {
71 assert_parse!(CssAtomSet::ATOMS, BoxShadowOffsetStyleValue, "none");
72 assert_parse!(CssAtomSet::ATOMS, BoxShadowOffsetStyleValue, "10px");
73 assert_parse!(CssAtomSet::ATOMS, BoxShadowOffsetStyleValue, "10px 20px");
74 assert_parse!(CssAtomSet::ATOMS, BoxShadowOffsetStyleValue, "none,10px");
75 assert_parse!(CssAtomSet::ATOMS, BoxShadowOffsetStyleValue, "10px,20px 30px");
76 assert_peek_false!(CssAtomSet::ATOMS, BoxShadowOffsetStyleValue, "");
77 assert_peek_false!(CssAtomSet::ATOMS, BoxShadowOffsetStyleValue, "red");
78 }
79
80 #[test]
81 fn test_box_shadow() {
82 assert_parse!(CssAtomSet::ATOMS, BoxShadowStyleValue, "none");
83 assert_parse!(CssAtomSet::ATOMS, BoxShadowStyleValue, "0 0 0 .2rem rgba(0,123,255,.25)");
84 assert_parse!(CssAtomSet::ATOMS, BoxShadowStyleValue, "0 1px 1px rgba(0,0,0,.075)inset");
85 assert_parse!(CssAtomSet::ATOMS, BoxShadowStyleValue, "10px 20px 5px red");
86 assert_parse!(CssAtomSet::ATOMS, BoxShadowStyleValue, "10px 20px inset");
87 assert_parse!(CssAtomSet::ATOMS, BoxShadowStyleValue, "0 0 0 transparent,0 0 0 transparent");
88 assert_parse!(CssAtomSet::ATOMS, BoxShadowStyleValue, "0 1px 1px rgba(0,0,0,.075),0 0 6px rgba(0,0,0,.05)");
89 assert_peek_false!(CssAtomSet::ATOMS, BoxShadowStyleValue, "");
90 assert_parse_error!(CssAtomSet::ATOMS, BoxShadowStyleValue, "red");
91 }
92
93 #[test]
94 fn test_writes() {
95 assert_parse!(CssAtomSet::ATOMS, BorderTopColorStyleValue, "red");
96 assert_parse!(CssAtomSet::ATOMS, BorderClipStyleValue, "1fr");
97 assert_parse!(CssAtomSet::ATOMS, BorderClipStyleValue, "1fr 1fr 1fr");
98 assert_parse!(CssAtomSet::ATOMS, BorderClipStyleValue, "1fr 20px 2fr 40rem");
99 assert_parse!(CssAtomSet::ATOMS, BoxShadowPositionStyleValue, "outset");
100 assert_parse!(CssAtomSet::ATOMS, BoxShadowPositionStyleValue, "inset,inset");
101 assert_parse!(CssAtomSet::ATOMS, BoxShadowPositionStyleValue, "inset,inset,inset,outset,inset");
102 assert_parse!(CssAtomSet::ATOMS, BorderImageOutsetStyleValue, "10");
103 assert_parse!(CssAtomSet::ATOMS, BorderImageOutsetStyleValue, "10px");
104 assert_parse!(CssAtomSet::ATOMS, BorderImageOutsetStyleValue, "10px 10rem 10q 10em");
105 assert_parse!(CssAtomSet::ATOMS, BorderImageOutsetStyleValue, "10 1ric 10 10");
106 assert_parse!(CssAtomSet::ATOMS, BorderImageRepeatStyleValue, "stretch");
107 assert_parse!(CssAtomSet::ATOMS, BorderImageRepeatStyleValue, "stretch stretch");
108 }
109
110 #[test]
111 fn test_errors() {
112 assert_parse_error!(CssAtomSet::ATOMS, BorderImageOutsetStyleValue, "-10");
113 }
114
115 #[test]
116 fn test_border_color() {
117 assert_parse!(CssAtomSet::ATOMS, BorderColorStyleValue, "red");
118 assert_parse!(CssAtomSet::ATOMS, BorderColorStyleValue, "red blue");
119 assert_parse!(CssAtomSet::ATOMS, BorderColorStyleValue, "red blue green");
120 assert_parse!(CssAtomSet::ATOMS, BorderColorStyleValue, "red blue green yellow");
121 assert_parse!(CssAtomSet::ATOMS, BorderColorStyleValue, "stripes(red 1fr,blue 2fr)");
122 assert_parse!(CssAtomSet::ATOMS, BorderColorStyleValue, "red stripes(red 1fr,blue 2fr)");
123 assert_peek_false!(CssAtomSet::ATOMS, BorderColorStyleValue, "");
124 assert_peek_false!(CssAtomSet::ATOMS, BorderColorStyleValue, "auto");
125 assert_parse_error!(CssAtomSet::ATOMS, BorderColorStyleValue, "red blue green yellow purple");
126 }
127
128 #[test]
129 fn test_border_image_slice() {
130 assert_parse!(CssAtomSet::ATOMS, BorderImageSliceStyleValue, "0");
131 assert_parse!(CssAtomSet::ATOMS, BorderImageSliceStyleValue, "50%");
132 assert_parse!(CssAtomSet::ATOMS, BorderImageSliceStyleValue, "10 20");
133 assert_parse!(CssAtomSet::ATOMS, BorderImageSliceStyleValue, "10 20 30 40");
134 assert_parse!(CssAtomSet::ATOMS, BorderImageSliceStyleValue, "10% fill");
135 assert_parse!(CssAtomSet::ATOMS, BorderImageSliceStyleValue, "fill 10%");
136 assert_peek_false!(CssAtomSet::ATOMS, BorderImageSliceStyleValue, "");
137 assert_peek_false!(CssAtomSet::ATOMS, BorderImageSliceStyleValue, "auto");
138 }
139
140 #[test]
141 fn test_border_image_width() {
142 assert_parse!(CssAtomSet::ATOMS, BorderImageWidthStyleValue, "auto");
143 assert_parse!(CssAtomSet::ATOMS, BorderImageWidthStyleValue, "1");
144 assert_parse!(CssAtomSet::ATOMS, BorderImageWidthStyleValue, "10px");
145 assert_parse!(CssAtomSet::ATOMS, BorderImageWidthStyleValue, "50%");
146 assert_parse!(CssAtomSet::ATOMS, BorderImageWidthStyleValue, "1 2");
147 assert_parse!(CssAtomSet::ATOMS, BorderImageWidthStyleValue, "1 2 3 4");
148 assert_parse!(CssAtomSet::ATOMS, BorderImageWidthStyleValue, "auto 10px 1 50%");
149 assert_peek_false!(CssAtomSet::ATOMS, BorderImageWidthStyleValue, "");
150 assert_peek_false!(CssAtomSet::ATOMS, BorderImageWidthStyleValue, "none");
151 }
152
153 #[test]
154 fn test_border_image() {
155 assert_parse!(CssAtomSet::ATOMS, BorderImageStyleValue, "none");
156 assert_parse!(CssAtomSet::ATOMS, BorderImageStyleValue, "url(border.svg)");
157 assert_parse!(CssAtomSet::ATOMS, BorderImageStyleValue, "url(border.svg) 30");
158 assert_parse!(CssAtomSet::ATOMS, BorderImageStyleValue, "url(border.svg) 30 fill");
159 assert_parse!(CssAtomSet::ATOMS, BorderImageStyleValue, "url(border.svg) 30 / 10px");
160 assert_parse!(CssAtomSet::ATOMS, BorderImageStyleValue, "url(border.svg) 30 / 10px / 2");
161 assert_parse!(CssAtomSet::ATOMS, BorderImageStyleValue, "url(border.svg) 30 / / 2");
162 assert_parse!(CssAtomSet::ATOMS, BorderImageStyleValue, "url(border.svg) 30 round");
163 assert_parse!(CssAtomSet::ATOMS, BorderImageStyleValue, "url(border.svg) 30 / 10px repeat");
164 assert_parse!(CssAtomSet::ATOMS, BorderImageStyleValue, "stretch");
165 assert_peek_false!(CssAtomSet::ATOMS, BorderImageStyleValue, "");
166 assert_peek_false!(CssAtomSet::ATOMS, BorderImageStyleValue, "/ 10px");
167 assert_parse_error!(CssAtomSet::ATOMS, BorderImageStyleValue, "url(a.svg) url(b.svg)");
168 }
169
170 #[test]
171 fn test_border_shape() {
172 assert_parse!(CssAtomSet::ATOMS, BorderShapeStyleValue, "none");
173 assert_peek_false!(CssAtomSet::ATOMS, BorderShapeStyleValue, "");
174 assert_peek_false!(CssAtomSet::ATOMS, BorderShapeStyleValue, "auto");
175 }
176
177 #[test]
178 fn test_corner_shorthands() {
179 assert_parse!(CssAtomSet::ATOMS, CornerTopLeftStyleValue, "10px");
180 assert_parse!(CssAtomSet::ATOMS, CornerTopLeftStyleValue, "round");
181 assert_parse!(CssAtomSet::ATOMS, CornerTopLeftStyleValue, "10px round");
182 assert_parse!(CssAtomSet::ATOMS, CornerTopRightStyleValue, "5px squircle");
183 assert_parse!(CssAtomSet::ATOMS, CornerTopStyleValue, "10px");
184 assert_parse!(CssAtomSet::ATOMS, CornerTopStyleValue, "10px 20px");
185 assert_peek_false!(CssAtomSet::ATOMS, CornerTopLeftStyleValue, "");
186 assert_peek_false!(CssAtomSet::ATOMS, CornerTopLeftStyleValue, "red");
187 }
188}