1use css_parse::{Build, Cursor, Parse, Parser, Peek, Result as ParserResult, T, function_set};
2use csskit_derives::{ToCursors, ToSpan, Visitable};
3
4#[derive(ToCursors, ToSpan, Visitable, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
12#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
13#[visit(self)]
14pub enum Url {
15 Url(T![Url]),
16 UrlFunction(T![Function], T![String], T![')']),
17 SrcFunction(T![Function], T![String], T![')']),
18}
19
20function_set!(
21 pub enum UrlFunctionKeywords {
22 Url: "url",
23 Src: "src"
24 }
25);
26
27impl<'a> Peek<'a> for Url {
28 fn peek(p: &Parser<'a>, c: Cursor) -> bool {
29 <T![Url]>::peek(p, c) || <UrlFunctionKeywords>::peek(p, c)
30 }
31}
32
33impl<'a> Parse<'a> for Url {
34 fn parse(p: &mut Parser<'a>) -> ParserResult<Self> {
35 if let Some(url) = p.parse_if_peek::<T![Url]>()? {
36 return Ok(Self::Url(url));
37 }
38 let keyword = p.parse::<UrlFunctionKeywords>()?;
39 let c: Cursor = keyword.into();
40 let function = <T![Function]>::build(p, c);
41 match keyword {
42 UrlFunctionKeywords::Url(_) => {
43 let string = p.parse::<T![String]>()?;
44 let close = p.parse::<T![')']>()?;
45 Ok(Self::SrcFunction(function, string, close))
46 }
47 UrlFunctionKeywords::Src(_) => {
48 let string = p.parse::<T![String]>()?;
49 let close = p.parse::<T![')']>()?;
50 Ok(Self::SrcFunction(function, string, close))
51 }
52 }
53 }
54}
55
56#[cfg(test)]
57mod tests {
58 use super::*;
59 use css_parse::assert_parse;
60
61 #[test]
62 fn size_test() {
63 assert_eq!(std::mem::size_of::<Url>(), 40);
64 }
65
66 #[test]
67 fn test_writes() {
68 assert_parse!(Url, "url('foo')");
69 assert_parse!(Url, "url(\"foo\")");
70 assert_parse!(Url, "url(foo)");
71 }
72}