web_url/parse/path_plus/
query.rs

1use crate::parse::Error;
2use crate::Query;
3
4/// Parses the optional query from the prefix of `s`.
5///
6/// Returns `Ok(optional_query, rest_of_s)`.
7/// Returns `Ok(None)` if `s` does not start with a `?`.
8/// Returns `Err(InvalidQuery)` if the query is invalid.
9#[allow(clippy::type_complexity)]
10pub fn parse_query(s: &str) -> Result<(Option<Query<'_>>, &str), Error> {
11    if !s.is_empty() && s.as_bytes()[0] == b'?' {
12        if let Some(hash) = s.as_bytes().iter().position(|c| *c == b'#') {
13            let (query, fragment) = s.split_at(hash);
14            let query: Query = Query::try_from(query)?;
15            Ok((Some(query), fragment))
16        } else {
17            let query: Query = Query::try_from(s)?;
18            Ok((Some(query), ""))
19        }
20    } else {
21        Ok((None, s))
22    }
23}
24
25#[cfg(test)]
26mod tests {
27    use crate::parse::path_plus::parse_query;
28    use crate::parse::Error;
29    use crate::Query;
30
31    #[test]
32    #[allow(clippy::type_complexity)]
33    fn fn_parse_query() {
34        let test_cases: &[(&str, Result<(Option<Query>, &str), Error>)] = &[
35            ("", Ok((None, ""))),
36            ("no&start=q", Ok((None, "no&start=q"))),
37            ("?", Ok((Some(unsafe { Query::new("?") }), ""))),
38            (
39                "?the&url=query",
40                Ok((Some(unsafe { Query::new("?the&url=query") }), "")),
41            ),
42            ("#fragment", Ok((None, "#fragment"))),
43            (
44                "?#fragment",
45                Ok((Some(unsafe { Query::new("?") }), "#fragment")),
46            ),
47            (
48                "?the&url=query#fragment",
49                Ok((Some(unsafe { Query::new("?the&url=query") }), "#fragment")),
50            ),
51        ];
52        for (s, expected) in test_cases {
53            let result: Result<(Option<Query>, &str), Error> = parse_query(s);
54            assert_eq!(result, *expected, "s={}", *s);
55        }
56    }
57}