Skip to main content

idkollen_client/models/
url.rs

1use fmt::Display;
2use serde::{Deserialize, Deserializer, Serialize, Serializer};
3use std::fmt;
4use thiserror::Error;
5
6/// A validated URL.
7///
8/// Constructed via [`Url::parse`]; serializes/deserializes as a plain JSON string.
9#[derive(Debug, Clone, PartialEq, Eq, Hash)]
10pub struct Url(String);
11
12#[derive(Debug, Error)]
13#[error("invalid URL: {0}")]
14pub struct UrlError(#[from] url::ParseError);
15
16impl Url {
17    pub fn parse(s: &str) -> Result<Self, UrlError> {
18        url::Url::parse(s)?;
19
20        Ok(Self(s.to_owned()))
21    }
22
23    #[inline]
24    #[must_use]
25    pub fn as_str(&self) -> &str {
26        &self.0
27    }
28}
29
30impl From<Url> for String {
31    #[inline]
32    fn from(u: Url) -> String {
33        u.0
34    }
35}
36
37impl AsRef<str> for Url {
38    #[inline]
39    fn as_ref(&self) -> &str {
40        &self.0
41    }
42}
43
44impl Display for Url {
45    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46        f.write_str(&self.0)
47    }
48}
49
50impl Serialize for Url {
51    fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
52        self.0.serialize(s)
53    }
54}
55
56impl<'de> Deserialize<'de> for Url {
57    fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
58        let s = String::deserialize(d)?;
59        Url::parse(&s).map_err(serde::de::Error::custom)
60    }
61}