use std::collections::BTreeMap;
use std::fmt;
use std::io::Write;
use std::str::FromStr;
use quick_xml::Error as XmlError;
use quick_xml::Writer;
use crate::extension::Extension;
use crate::toxml::WriterExt;
pub const NAMESPACE: &str = "http://purl.org/rss/1.0/modules/syndication/";
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, PartialEq)]
pub enum UpdatePeriod {
Hourly,
Daily,
Weekly,
Monthly,
Yearly,
}
impl FromStr for UpdatePeriod {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"hourly" => Ok(UpdatePeriod::Hourly),
"daily" => Ok(UpdatePeriod::Daily),
"weekly" => Ok(UpdatePeriod::Weekly),
"monthly" => Ok(UpdatePeriod::Monthly),
"yearly" => Ok(UpdatePeriod::Yearly),
_ => Err(()),
}
}
}
impl fmt::Display for UpdatePeriod {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
UpdatePeriod::Hourly => write!(f, "hourly"),
UpdatePeriod::Daily => write!(f, "daily"),
UpdatePeriod::Weekly => write!(f, "weekly"),
UpdatePeriod::Monthly => write!(f, "monthly"),
UpdatePeriod::Yearly => write!(f, "yearly"),
}
}
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "builders", derive(Builder))]
#[cfg_attr(
feature = "builders",
builder(
setter(into),
default,
build_fn(name = "build_impl", private, error = "never::Never")
)
)]
pub struct SyndicationExtension {
pub period: UpdatePeriod,
pub frequency: u32,
pub base: String,
}
impl SyndicationExtension {
pub fn base(&self) -> &str {
&self.base
}
pub fn set_base(&mut self, base: &str) {
self.base = base.to_owned();
}
pub fn frequency(&self) -> u32 {
self.frequency
}
pub fn set_frequency(&mut self, frequency: u32) {
self.frequency = frequency;
}
pub fn period(&self) -> &UpdatePeriod {
&self.period
}
pub fn set_period(&mut self, period: UpdatePeriod) {
self.period = period;
}
pub fn to_xml<W: Write>(
&self,
namespaces: &BTreeMap<String, String>,
writer: &mut Writer<W>,
) -> Result<(), XmlError> {
for (prefix, namespace) in namespaces {
if NAMESPACE == namespace {
writer.write_text_element(
format!("{}:updatePeriod", prefix),
&self.period.to_string(),
)?;
writer.write_text_element(
format!("{}:updateFrequency", prefix),
&format!("{}", self.frequency),
)?;
writer.write_text_element(format!("{}:updateBase", prefix), &self.base)?;
}
}
Ok(())
}
}
impl Default for SyndicationExtension {
fn default() -> Self {
SyndicationExtension {
period: UpdatePeriod::Daily,
frequency: 1,
base: String::from("1970-01-01T00:00+00:00"),
}
}
}
fn with_first_ext_value<'a, F>(map: &'a BTreeMap<String, Vec<Extension>>, field: &str, f: F)
where
F: FnOnce(&'a str),
{
if let Some(extensions) = map.get(field) {
if !extensions.is_empty() {
if let Some(v) = extensions[0].value.as_ref() {
f(v);
}
}
}
}
impl SyndicationExtension {
pub fn from_map(map: BTreeMap<String, Vec<Extension>>) -> Self {
let mut syn = SyndicationExtension::default();
with_first_ext_value(&map, "updatePeriod", |value| {
if let Ok(update_period) = value.parse() {
syn.period = update_period
}
});
with_first_ext_value(&map, "updateFrequency", |value| {
if let Ok(frequency) = value.parse() {
syn.frequency = frequency
}
});
with_first_ext_value(&map, "updateBase", |value| syn.base = value.to_owned());
syn
}
}
#[cfg(feature = "builders")]
impl SyndicationExtensionBuilder {
pub fn build(&self) -> SyndicationExtension {
self.build_impl().unwrap()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[cfg(feature = "builders")]
fn test_builder() {
assert_eq!(
SyndicationExtensionBuilder::default()
.period(UpdatePeriod::Weekly)
.frequency(2_u32)
.base("2021-01-01T00:00+00:00")
.build(),
SyndicationExtension {
period: UpdatePeriod::Weekly,
frequency: 2,
base: "2021-01-01T00:00+00:00".to_string(),
}
);
}
}