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}