better_url/better_url/domain_impl/segments/
subdomain.rs

1//! Implementing subdomain segment stuff for [`BetterUrl`].
2
3use super::*;
4
5/// The enum of errors [`BetterUrl::set_subdomain_segment`] can return.
6#[derive(Debug, Error)]
7pub enum SetSubdomainSegmentError {
8    /// Returned when the URL doesn't have a subdomain.
9    #[error("The URL does not have a subdomain.")]
10    UrlDoesNotHaveSubdomain,
11    /// Returned when the segment isn't found.
12    #[error("The segment wasn't found.")]
13    SegmentNotFound,
14    /// Returned when a [`SetSubdomainError`] is encountered.
15    #[error(transparent)]
16    SetSubdomainError(#[from] SetSubdomainError)
17}
18
19/// The enum of errors [`BetterUrl::insert_subdomain_segment`] can return.
20#[derive(Debug, Error)]
21pub enum InsertSubdomainSegmentError {
22    /// Returned when the URL doesn't have a subdomain.
23    #[error("The URL does not have a subdomain.")]
24    UrlDoesNotHaveSubdomain,
25    /// Returned when the segment isn't found.
26    #[error("The segment wasn't found.")]
27    SegmentNotFound,
28    /// Returned when a [`SetSubdomainError`] is encountered.
29    #[error(transparent)]
30    SetSubdomainError(#[from] SetSubdomainError)
31}
32
33impl BetterUrl {
34    /// # Examples
35    /// ```
36    /// use better_url::*;
37    ///
38    /// let url = BetterUrl::parse("https://abc.def.example.co.uk").unwrap();
39    ///
40    /// assert_eq!(url.subdomain_segment(-3), None              );
41    /// assert_eq!(url.subdomain_segment(-2), Some("abc".into()));
42    /// assert_eq!(url.subdomain_segment(-1), Some("def".into()));
43    ///
44    /// assert_eq!(url.subdomain_segment( 0), Some("abc".into()));
45    /// assert_eq!(url.subdomain_segment( 1), Some("def".into()));
46    /// assert_eq!(url.subdomain_segment( 2), None              );
47    /// ```
48    pub fn subdomain_segment(&self, index: isize) -> Option<&str> {
49        match index {
50            0.. => self.subdomain()?.split('.').nth(index as usize),
51            #[allow(clippy::arithmetic_side_effects, reason = "Can't happen.")]
52            ..0 => self.subdomain()?.split('.').nth_back((-index - 1) as usize)
53        }
54    }
55
56    /// Sets the specified subdomain segment.
57    /// # Errors
58    /// If the URL doesn't have a domain, returns the error [`SetSubdomainSegmentError::UrlDoesNotHaveSubdomain`].
59    ///
60    /// If the segment isn't found, returns the error [`SetSubdomainSegmentError::SegmentNotFound`].
61    ///
62    /// If the call to [`Self::set_subdomain`] returns an error, that error is returned.
63    /// # Examples
64    /// ```
65    /// use better_url::*;
66    ///
67    /// let mut url = BetterUrl::parse("https://abc.def.example.co.uk").unwrap();
68    ///
69    /// url.set_subdomain_segment(-3, Some("n3")).unwrap_err(); assert_eq!(url.host_str(), Some("abc.def.example.co.uk"));
70    /// url.set_subdomain_segment(-2, Some("n2")).unwrap    (); assert_eq!(url.host_str(), Some("n2.def.example.co.uk"));
71    /// url.set_subdomain_segment(-1, Some("n1")).unwrap    (); assert_eq!(url.host_str(), Some("n2.n1.example.co.uk"));
72    ///
73    /// url.set_subdomain_segment( 0, Some("p0")).unwrap    (); assert_eq!(url.host_str(), Some("p0.n1.example.co.uk"));
74    /// url.set_subdomain_segment( 1, Some("p1")).unwrap    (); assert_eq!(url.host_str(), Some("p0.p1.example.co.uk"));
75    /// url.set_subdomain_segment( 2, Some("p2")).unwrap_err(); assert_eq!(url.host_str(), Some("p0.p1.example.co.uk"));
76    ///
77    ///
78    ///
79    /// url.set_subdomain_segment( 0, None).unwrap(); assert_eq!(url.host_str(), Some("p1.example.co.uk"));
80    /// url.set_subdomain_segment(-1, None).unwrap(); assert_eq!(url.host_str(), Some("example.co.uk"));
81    /// ```
82    pub fn set_subdomain_segment(&mut self, index: isize, value: Option<&str>) -> Result<(), SetSubdomainSegmentError> {
83        self.set_subdomain(set_segment(
84            self.subdomain().ok_or(SetSubdomainSegmentError::UrlDoesNotHaveSubdomain)?,
85            ".", index, value, SetSubdomainSegmentError::SegmentNotFound
86        )?.as_deref())?;
87        Ok(())
88    }
89
90    /// Inserts a new subdomain segment at the specified index.
91    /// # Errors
92    /// If the URL doesn't have a domain, returns the error [`InsertSubdomainSegmentError::UrlDoesNotHaveSubdomain`].
93    ///
94    /// If the segment isn't found, returns the error [`InsertSubdomainSegmentError::SegmentNotFound`].
95    ///
96    /// If the call to [`Self::set_subdomain`] returns an error, that error is returned.
97    pub fn insert_subdomain_segment(&mut self, index: isize, value: &str) -> Result<(), InsertSubdomainSegmentError> {
98        self.set_subdomain(Some(&insert_segment(
99            self.subdomain().ok_or(InsertSubdomainSegmentError::UrlDoesNotHaveSubdomain)?,
100            ".", index, value, InsertSubdomainSegmentError::SegmentNotFound
101        )?))?;
102        Ok(())
103    }
104}