Skip to main content

leyline/core/
into_url.rs

1use url::Url;
2
3use crate::core::error::{Error, Kind, Result};
4
5mod sealed {
6    pub trait Sealed {}
7}
8
9pub trait IntoUrl: sealed::Sealed {
10    fn into_url(self) -> Result<Url>;
11
12    #[doc(hidden)]
13    fn into_url_with_base(self, base: Option<&Url>) -> Result<Url>
14    where
15        Self: Sized,
16    {
17        let _ = base;
18        self.into_url()
19    }
20}
21
22fn parse_with_base(raw: &str, base: Option<&Url>) -> Result<Url> {
23    match (Url::parse(raw), base) {
24        (Err(url::ParseError::RelativeUrlWithoutBase), Some(base))
25            if !raw.chars().any(|c| c.is_ascii_control()) =>
26        {
27            base.join(raw).map_err(Error::from_url_parse)
28        }
29        _ => raw.into_url(),
30    }
31}
32
33impl sealed::Sealed for &str {}
34impl IntoUrl for &str {
35    fn into_url(self) -> Result<Url> {
36        if self.chars().any(|c| c.is_ascii_control()) {
37            return Err(Error::new(Kind::Url).with_message("URL contains a control character"));
38        }
39        Url::parse(self).map_err(Error::from_url_parse)
40    }
41
42    fn into_url_with_base(self, base: Option<&Url>) -> Result<Url> {
43        parse_with_base(self, base)
44    }
45}
46
47impl sealed::Sealed for String {}
48impl IntoUrl for String {
49    fn into_url(self) -> Result<Url> {
50        self.as_str().into_url()
51    }
52
53    fn into_url_with_base(self, base: Option<&Url>) -> Result<Url> {
54        parse_with_base(&self, base)
55    }
56}
57
58impl sealed::Sealed for &String {}
59impl IntoUrl for &String {
60    fn into_url(self) -> Result<Url> {
61        self.as_str().into_url()
62    }
63
64    fn into_url_with_base(self, base: Option<&Url>) -> Result<Url> {
65        parse_with_base(self, base)
66    }
67}
68
69impl sealed::Sealed for Url {}
70impl IntoUrl for Url {
71    fn into_url(self) -> Result<Url> {
72        Ok(self)
73    }
74}
75
76impl sealed::Sealed for &Url {}
77impl IntoUrl for &Url {
78    fn into_url(self) -> Result<Url> {
79        Ok(self.clone())
80    }
81}