web_url/parse/pre_path/
scheme.rs

1use crate::parse::Error;
2use crate::parse::Error::InvalidScheme;
3use crate::Scheme;
4
5/// Parses the scheme length from the prefix of `s`.
6///
7/// The scheme will be valid but may have uppercase chars.
8///
9/// Returns `Ok(scheme_len, rest_of_s)`. The `rest_of_s` starts after the `://`.
10/// Returns `Err(InvalidScheme)` if the scheme or `://` postfix is invalid.
11pub fn parse_scheme_len(s: &str) -> Result<(usize, &str), Error> {
12    if let Some(colon) = s.as_bytes().iter().position(|c| *c == b':') {
13        if Scheme::is_valid(&s[..colon], true) {
14            let s: &str = &s[colon + 1..];
15            if s.len() < 2 || s.as_bytes()[0] != b'/' || s.as_bytes()[1] != b'/' {
16                Err(InvalidScheme)
17            } else {
18                Ok((colon, &s[2..]))
19            }
20        } else {
21            Err(InvalidScheme)
22        }
23    } else {
24        Err(InvalidScheme)
25    }
26}
27
28#[cfg(test)]
29mod tests {
30    use crate::parse::pre_path::parse_scheme_len;
31
32    #[test]
33    fn fn_get_scheme_len() {
34        let test_cases: &[(&str, Option<(usize, &str)>)] = &[
35            ("", None),
36            ("s:", None),
37            ("s:/", None),
38            ("s:/x", None),
39            ("s:x/", None),
40            ("!://", None),
41            ("://", None),
42            ("s://", Some((1, ""))),
43            ("s://rest", Some((1, "rest"))),
44        ];
45        for (s, expected) in test_cases {
46            let result: Option<(usize, &str)> = parse_scheme_len(s).ok();
47            assert_eq!(result, *expected);
48        }
49    }
50}