1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
// This file is part of rss.
//
// Copyright © 2015-2017 The rust-syndication Developers
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the MIT License and/or Apache 2.0 License.

use std::io::{BufRead, Write};

use quick_xml::errors::Error as XmlError;
use quick_xml::events::{Event, BytesStart, BytesEnd, BytesText};
use quick_xml::events::attributes::Attributes;
use quick_xml::reader::Reader;
use quick_xml::writer::Writer;

use error::Error;
use fromxml::FromXml;
use toxml::ToXml;
use util::element_text;

/// Represents a category in an RSS feed.
#[derive(Debug, Default, Clone, PartialEq, Builder)]
#[builder(setter(into), default)]
pub struct Category {
    /// The name of the category.
    name: String,
    /// The domain for the category.
    domain: Option<String>,
}

impl Category {
    /// Return the name of this category.
    ///
    /// # Examples
    ///
    /// ```
    /// use rss::Category;
    ///
    /// let mut category = Category::default();
    /// category.set_name("Technology");
    /// assert_eq!(category.name(), "Technology");
    /// ```
    pub fn name(&self) -> &str {
        self.name.as_str()
    }

    /// Set the name of this category.
    ///
    /// # Examples
    ///
    /// ```
    /// use rss::Category;
    ///
    /// let mut category = Category::default();
    /// category.set_name("Technology");
    /// ```
    pub fn set_name<V>(&mut self, name: V)
    where
        V: Into<String>,
    {
        self.name = name.into();
    }

    /// Return the domain of this category.
    ///
    /// # Examples
    ///
    /// ```
    /// use rss::Category;
    ///
    /// let mut category = Category::default();
    /// category.set_domain("http://example.com".to_string());
    /// assert_eq!(category.domain(), Some("http://example.com"));
    /// ```
    pub fn domain(&self) -> Option<&str> {
        self.domain.as_ref().map(|s| s.as_str())
    }

    /// Set the domain of this category.
    ///
    /// # Examples
    ///
    /// ```
    /// use rss::Category;
    ///
    /// let mut category = Category::default();
    /// category.set_domain("http://example.com".to_string());
    /// ```
    pub fn set_domain<V>(&mut self, domain: V)
    where
        V: Into<Option<String>>,
    {
        self.domain = domain.into();
    }
}

impl FromXml for Category {
    fn from_xml<R: BufRead>(reader: &mut Reader<R>, mut atts: Attributes) -> Result<Self, Error> {
        let mut category = Category::default();

        for attr in atts.with_checks(false) {
            if let Ok(attr) = attr {
                if attr.key == b"domain" {
                    category.domain = Some(attr.unescape_and_decode_value(reader)?);
                    break;
                }
            }
        }

        category.name = element_text(reader)?.unwrap_or_default();
        Ok(category)
    }
}

impl ToXml for Category {
    fn to_xml<W: Write>(&self, writer: &mut Writer<W>) -> Result<(), XmlError> {
        let name = b"category";
        let mut element = BytesStart::borrowed(name, name.len());
        if let Some(ref domain) = self.domain {
            element.push_attribute(("domain", &**domain));
        }
        writer.write_event(Event::Start(element))?;
        writer
            .write_event(Event::Text(BytesText::borrowed(self.name.as_bytes())))?;
        writer.write_event(Event::End(BytesEnd::borrowed(name)))?;
        Ok(())
    }
}