validator_async/validation/
urls.rs

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