validator/validation/
urls.rs1use std::{
2    borrow::Cow,
3    rc::Rc,
4    sync::Arc,
5    cell::{Ref, RefMut},
6};
7use url::Url;
8
9pub trait ValidateUrl {
11    fn validate_url(&self) -> bool {
12        if let Some(u) = self.as_url_string() {
13            Url::parse(&u).is_ok()
14        } else {
15            true
16        }
17    }
18
19    fn as_url_string(&self) -> Option<Cow<str>>;
20}
21
22macro_rules! validate_type_that_derefs {
23    ($type_:ty) => {
24        impl<T> ValidateUrl for $type_
25        where T: ValidateUrl {
26            fn as_url_string(&self) -> Option<Cow<str>> {
27                T::as_url_string(self)
28            }
29        }
30    };
31}
32
33validate_type_that_derefs!(&T);
34validate_type_that_derefs!(Arc<T>);
35validate_type_that_derefs!(Box<T>);
36validate_type_that_derefs!(Rc<T>);
37validate_type_that_derefs!(Ref<'_, T>);
38validate_type_that_derefs!(RefMut<'_, T>);
39
40macro_rules! validate_type_of_str {
41    ($type_:ty) => {
42        impl ValidateUrl for $type_ {
43            fn as_url_string(&self) -> Option<Cow<str>> {
44                Some(Cow::Borrowed(self))
45            }
46        }
47    };
48}
49
50validate_type_of_str!(str);
51validate_type_of_str!(&str);
52validate_type_of_str!(String);
53
54impl<T> ValidateUrl for Option<T>
55    where T: ValidateUrl {
56    fn as_url_string(&self) -> Option<Cow<str>> {
57        let Some(u) = self else {
58            return None;
59        };
60
61        T::as_url_string(u)
62    }
63}
64
65impl ValidateUrl for Cow<'_, str> {
66    fn as_url_string(&self) -> Option<Cow<'_, str>> {
67        <str as ValidateUrl>::as_url_string(self)
68    }
69}
70
71#[cfg(test)]
72mod tests {
73    use std::borrow::Cow;
74
75    use super::ValidateUrl;
76
77    #[test]
78    fn test_validate_url() {
79        let tests = vec![
80            ("http", false),
81            ("https://google.com", true),
82            ("http://localhost:80", true),
83            ("ftp://localhost:80", true),
84        ];
85
86        for (url, expected) in tests {
87            assert_eq!(url.validate_url(), expected);
88        }
89    }
90
91    #[test]
92    fn test_validate_url_cow() {
93        let test: Cow<'static, str> = "http://localhost:80".into();
94        assert!(test.validate_url());
95        let test: Cow<'static, str> = String::from("http://localhost:80").into();
96        assert!(test.validate_url());
97        let test: Cow<'static, str> = "http".into();
98        assert!(!test.validate_url());
99        let test: Cow<'static, str> = String::from("http").into();
100        assert!(!test.validate_url());
101    }
102}