Skip to main content

css_ast/values/borders/
impls.rs

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}