Skip to main content

atom_syndication/
link.rs

1use std::borrow::Cow;
2use std::io::{BufRead, Write};
3
4use quick_xml::events::{BytesStart, Event};
5use quick_xml::Reader;
6use quick_xml::Writer;
7
8use crate::error::{Error, XmlError};
9use crate::toxml::ToXml;
10use crate::util::{attr_value, decode};
11
12/// Represents a link in an Atom feed
13#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
14#[derive(Debug, Clone, PartialEq)]
15#[cfg_attr(feature = "builders", derive(Builder))]
16#[cfg_attr(
17    feature = "builders",
18    builder(
19        setter(into),
20        default,
21        build_fn(name = "build_impl", private, error = "never::Never")
22    )
23)]
24pub struct Link {
25    /// The URI of the referenced resource.
26    pub href: String,
27    /// The link relationship type.
28    pub rel: String,
29    /// The language of the resource.
30    pub hreflang: Option<String>,
31    /// The MIME type of the resource.
32    pub mime_type: Option<String>,
33    /// Human-readable information about the link.
34    pub title: Option<String>,
35    /// The length of the resource, in bytes.
36    pub length: Option<String>,
37}
38
39impl Default for Link {
40    fn default() -> Self {
41        Link {
42            href: Default::default(),
43            rel: "alternate".into(),
44            hreflang: Default::default(),
45            mime_type: Default::default(),
46            title: Default::default(),
47            length: Default::default(),
48        }
49    }
50}
51
52impl Link {
53    /// Return the URI the referenced resource.
54    ///
55    /// # Examples
56    ///
57    /// ```
58    /// use atom_syndication::Link;
59    ///
60    /// let mut link = Link::default();
61    /// link.set_href("http://example.com");
62    /// assert_eq!(link.href(), "http://example.com");
63    /// ```
64    pub fn href(&self) -> &str {
65        self.href.as_str()
66    }
67
68    /// Set the URI of the referenced resource.
69    ///
70    /// # Examples
71    ///
72    /// ```
73    /// use atom_syndication::Link;
74    ///
75    /// let mut link = Link::default();
76    /// link.set_href("http://example.com");
77    /// ```
78    pub fn set_href<V>(&mut self, href: V)
79    where
80        V: Into<String>,
81    {
82        self.href = href.into()
83    }
84
85    /// Return the relation type of this link.
86    ///
87    /// # Examples
88    ///
89    /// ```
90    /// use atom_syndication::Link;
91    ///
92    /// let mut link = Link::default();
93    /// link.set_rel("alternate");
94    /// assert_eq!(link.rel(), "alternate");
95    /// ```
96    pub fn rel(&self) -> &str {
97        self.rel.as_str()
98    }
99
100    /// Set the relation type of this link.
101    ///
102    /// # Examples
103    ///
104    /// ```
105    /// use atom_syndication::Link;
106    ///
107    /// let mut link = Link::default();
108    /// link.set_rel("alternate");
109    /// ```
110    pub fn set_rel<V>(&mut self, rel: V)
111    where
112        V: Into<String>,
113    {
114        self.rel = rel.into()
115    }
116
117    /// Return the language of the referenced resource.
118    ///
119    /// # Examples
120    ///
121    /// ```
122    /// use atom_syndication::Link;
123    ///
124    /// let mut link = Link::default();
125    /// link.set_hreflang("en".to_string());
126    /// assert_eq!(link.hreflang(), Some("en"));
127    /// ```
128    pub fn hreflang(&self) -> Option<&str> {
129        self.hreflang.as_deref()
130    }
131
132    /// Set the language of the referenced resource.
133    ///
134    /// # Examples
135    ///
136    /// ```
137    /// use atom_syndication::Link;
138    ///
139    /// let mut link = Link::default();
140    /// link.set_hreflang("en".to_string());
141    /// ```
142    pub fn set_hreflang<V>(&mut self, hreflang: V)
143    where
144        V: Into<Option<String>>,
145    {
146        self.hreflang = hreflang.into()
147    }
148
149    /// Return the MIME type of the referenced resource.
150    ///
151    /// # Examples
152    ///
153    /// ```
154    /// use atom_syndication::Link;
155    ///
156    /// let mut link = Link::default();
157    /// link.set_mime_type("text/html".to_string());
158    /// assert_eq!(link.mime_type(), Some("text/html"));
159    /// ```
160    pub fn mime_type(&self) -> Option<&str> {
161        self.mime_type.as_deref()
162    }
163
164    /// Set the MIME type of the referenced resource.
165    ///
166    /// # Examples
167    ///
168    /// ```
169    /// use atom_syndication::Link;
170    ///
171    /// let mut link = Link::default();
172    /// link.set_mime_type("text/html".to_string());
173    /// ```
174    pub fn set_mime_type<V>(&mut self, mime_type: V)
175    where
176        V: Into<Option<String>>,
177    {
178        self.mime_type = mime_type.into()
179    }
180
181    /// Return the title of the referenced resource.
182    ///
183    /// # Examples
184    ///
185    /// ```
186    /// use atom_syndication::Link;
187    ///
188    /// let mut link = Link::default();
189    /// link.set_title("Article Title".to_string());
190    /// assert_eq!(link.title(), Some("Article Title"));
191    /// ```
192    pub fn title(&self) -> Option<&str> {
193        self.title.as_deref()
194    }
195
196    /// Set the title of the referenced resource.
197    ///
198    /// # Examples
199    ///
200    /// ```
201    /// use atom_syndication::Link;
202    ///
203    /// let mut link = Link::default();
204    /// link.set_title("Article Title".to_string());
205    /// ```
206    pub fn set_title<V>(&mut self, title: V)
207    where
208        V: Into<Option<String>>,
209    {
210        self.title = title.into()
211    }
212
213    /// Return the content length of the referenced resource in bytes.
214    ///
215    /// # Examples
216    ///
217    /// ```
218    /// use atom_syndication::Link;
219    ///
220    /// let mut link = Link::default();
221    /// link.set_length("1000".to_string());
222    /// assert_eq!(link.length(), Some("1000"));
223    /// ```
224    pub fn length(&self) -> Option<&str> {
225        self.length.as_deref()
226    }
227
228    /// Set the content length of the referenced resource in bytes.
229    ///
230    /// # Examples
231    ///
232    /// ```
233    /// use atom_syndication::Link;
234    ///
235    /// let mut link = Link::default();
236    /// link.set_length("1000".to_string());
237    /// ```
238    pub fn set_length<V>(&mut self, length: V)
239    where
240        V: Into<Option<String>>,
241    {
242        self.length = length.into()
243    }
244}
245
246impl Link {
247    pub(crate) fn from_xml<'s, B: BufRead>(
248        reader: &mut Reader<B>,
249        element: &'s BytesStart<'s>,
250    ) -> Result<Self, Error> {
251        let mut link = Link::default();
252
253        for att in element.attributes().with_checks(false).flatten() {
254            match decode(att.key.as_ref(), reader)? {
255                Cow::Borrowed("href") => link.href = attr_value(&att, reader)?.to_string(),
256                Cow::Borrowed("rel") => link.rel = attr_value(&att, reader)?.to_string(),
257                Cow::Borrowed("hreflang") => {
258                    link.hreflang = Some(attr_value(&att, reader)?.to_string())
259                }
260                Cow::Borrowed("type") => {
261                    link.mime_type = Some(attr_value(&att, reader)?.to_string())
262                }
263                Cow::Borrowed("title") => link.title = Some(attr_value(&att, reader)?.to_string()),
264                Cow::Borrowed("length") => {
265                    link.length = Some(attr_value(&att, reader)?.to_string())
266                }
267                _ => {}
268            }
269        }
270
271        Ok(link)
272    }
273}
274
275impl ToXml for Link {
276    fn to_xml<W: Write>(&self, writer: &mut Writer<W>) -> Result<(), XmlError> {
277        let mut element = BytesStart::new("link");
278        element.push_attribute(("href", &*self.href));
279        element.push_attribute(("rel", &*self.rel));
280
281        if let Some(ref hreflang) = self.hreflang {
282            element.push_attribute(("hreflang", &**hreflang));
283        }
284
285        if let Some(ref mime_type) = self.mime_type {
286            element.push_attribute(("type", &**mime_type));
287        }
288
289        if let Some(ref title) = self.title {
290            element.push_attribute(("title", &**title));
291        }
292
293        if let Some(ref length) = self.length {
294            element.push_attribute(("length", &**length));
295        }
296
297        writer
298            .write_event(Event::Empty(element))
299            .map_err(XmlError::new)?;
300
301        Ok(())
302    }
303}
304
305#[cfg(feature = "builders")]
306impl LinkBuilder {
307    /// Builds a new `Link`.
308    pub fn build(&self) -> Link {
309        self.build_impl().unwrap()
310    }
311}