mail_builder/headers/
url.rs

1/*
2 * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
3 *
4 * SPDX-License-Identifier: Apache-2.0 OR MIT
5 */
6
7use std::borrow::Cow;
8
9use super::Header;
10
11/// URL header, used mostly on List-* headers
12#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
13pub struct URL<'x> {
14    pub url: Vec<Cow<'x, str>>,
15}
16
17impl<'x> URL<'x> {
18    /// Create a new URL header
19    pub fn new(url: impl Into<Cow<'x, str>>) -> Self {
20        Self {
21            url: vec![url.into()],
22        }
23    }
24
25    /// Create a new multi-value URL header
26    pub fn new_list<T, U>(urls: T) -> Self
27    where
28        T: Iterator<Item = U>,
29        U: Into<Cow<'x, str>>,
30    {
31        Self {
32            url: urls.map(|s| s.into()).collect(),
33        }
34    }
35}
36
37impl<'x> From<&'x str> for URL<'x> {
38    fn from(value: &'x str) -> Self {
39        Self::new(value)
40    }
41}
42
43impl From<String> for URL<'_> {
44    fn from(value: String) -> Self {
45        Self::new(value)
46    }
47}
48
49impl<'x> From<&[&'x str]> for URL<'x> {
50    fn from(value: &[&'x str]) -> Self {
51        URL {
52            url: value.iter().map(|&s| s.into()).collect(),
53        }
54    }
55}
56
57impl<'x> From<&'x [String]> for URL<'x> {
58    fn from(value: &'x [String]) -> Self {
59        URL {
60            url: value.iter().map(|s| s.into()).collect(),
61        }
62    }
63}
64
65impl<'x, T> From<Vec<T>> for URL<'x>
66where
67    T: Into<Cow<'x, str>>,
68{
69    fn from(value: Vec<T>) -> Self {
70        URL {
71            url: value.into_iter().map(|s| s.into()).collect(),
72        }
73    }
74}
75
76impl Header for URL<'_> {
77    fn write_header(
78        &self,
79        mut output: impl std::io::Write,
80        mut bytes_written: usize,
81    ) -> std::io::Result<usize> {
82        for (pos, url) in self.url.iter().enumerate() {
83            if pos > 0 {
84                if bytes_written + url.len() + 2 >= 76 {
85                    output.write_all(b"\r\n\t")?;
86                    bytes_written = 1;
87                } else {
88                    output.write_all(b" ")?;
89                    bytes_written += 1;
90                }
91            }
92            output.write_all(b"<")?;
93            output.write_all(url.as_bytes())?;
94            if pos < self.url.len() - 1 {
95                output.write_all(b">,")?;
96                bytes_written += url.len() + 3;
97            } else {
98                output.write_all(b">")?;
99                bytes_written += url.len() + 2;
100            }
101        }
102
103        if bytes_written > 0 {
104            output.write_all(b"\r\n")?;
105        }
106
107        Ok(0)
108    }
109}