lewp_css/domain/at_rules/document/
url_matching_function.rs1use {
5 super::Document,
6 crate::{
7 domain::SpecifiedUrl,
8 parsers::{Parse, ParserContext},
9 CustomParseError,
10 },
11 cssparser::{
12 serialize_string,
13 BasicParseError,
14 BasicParseErrorKind,
15 ParseError,
16 Parser,
17 ToCss,
18 Token,
19 },
20 std::fmt,
21};
22
23#[derive(Clone, Debug)]
25pub enum UrlMatchingFunction {
26 Url(SpecifiedUrl),
29
30 UrlPrefix(String),
34
35 Domain(String),
38
39 RegExp(String),
42}
43
44macro_rules! parse_quoted_or_unquoted_string {
45 ($input:ident, $url_matching_function:expr) => {
46 $input.parse_nested_block(|input| {
47 let start = input.position();
48 input
49 .parse_entirely(|input| match input.next() {
50 Ok(&Token::QuotedString(ref value)) => {
51 Ok($url_matching_function(value.as_ref().to_owned()))
52 }
53 Ok(t) => Err(ParseError::from(BasicParseError {
54 kind: BasicParseErrorKind::UnexpectedToken(t.clone()),
55 location: input.state().source_location(),
56 })),
57 Err(e) => Err(e.into()),
58 })
59 .or_else(|_: ParseError<'i, CustomParseError<'i>>| {
60 while let Ok(_) = input.next() {}
61
62 Ok($url_matching_function(
63 input.slice_from(start).to_string(),
64 ))
65 })
66 })
67 };
68}
69
70impl ToCss for UrlMatchingFunction {
71 fn to_css<W: fmt::Write>(&self, dest: &mut W) -> fmt::Result {
72 use self::UrlMatchingFunction::*;
73
74 match *self {
75 Url(ref url) => url.to_css(dest),
76
77 UrlPrefix(ref url_prefix) => {
78 dest.write_str("url-prefix(")?;
79 serialize_string(url_prefix, dest)?;
80 dest.write_char(')')
81 }
82
83 Domain(ref domain) => {
84 dest.write_str("domain(")?;
85 serialize_string(domain, dest)?;
86 dest.write_char(')')
87 }
88
89 RegExp(ref regex) => {
90 dest.write_str("regexp(")?;
91 serialize_string(regex, dest)?;
92 dest.write_char(')')
93 }
94 }
95 }
96}
97
98impl UrlMatchingFunction {
99 pub(crate) fn parse<'i, 't>(
101 context: &ParserContext,
102 input: &mut Parser<'i, 't>,
103 ) -> Result<UrlMatchingFunction, ParseError<'i, CustomParseError<'i>>> {
104 if input
105 .r#try(|input| input.expect_function_matching("url-prefix"))
106 .is_ok()
107 {
108 parse_quoted_or_unquoted_string!(
109 input,
110 UrlMatchingFunction::UrlPrefix
111 )
112 } else if input
113 .r#try(|input| input.expect_function_matching("domain"))
114 .is_ok()
115 {
116 parse_quoted_or_unquoted_string!(input, UrlMatchingFunction::Domain)
117 } else if input
118 .r#try(|input| input.expect_function_matching("regexp"))
119 .is_ok()
120 {
121 input.parse_nested_block(|input| {
122 Ok(UrlMatchingFunction::RegExp(
123 input.expect_string()?.as_ref().to_owned(),
124 ))
125 })
126 } else if let Ok(url) =
127 input.r#try(|input| SpecifiedUrl::parse(context, input))
128 {
129 Ok(UrlMatchingFunction::Url(url))
130 } else {
131 Err(ParseError::from(
132 CustomParseError::DocumentAtRuleUrlMatchingFunctionWasInvalid,
133 ))
134 }
135 }
136
137 pub fn evaluate<D: Document>(&self, document: &D) -> bool {
139 document.documentMatchesUrl(self)
140 }
141}