use chrono::{DateTime, Utc}; use peanuts::{ element::{FromElement, IntoElement}, Element, XML_NS, }; pub const XMLNS: &str = "http://docs.oasis-open.org/ns/xri/xrd-1.0"; pub const SIGNATURE_XMLNS: &str = "http://www.w3.org/2000/09/xmldsig#"; #[derive(Debug, Clone)] pub struct XRD { pub id: Option, pub expires: Option, pub subject: Option, pub aliases: Vec, pub properties: Vec, pub links: Vec, pub signature: Vec, } impl FromElement for XRD { fn from_element(mut element: peanuts::Element) -> peanuts::element::DeserializeResult { element.check_name("XRD")?; element.check_namespace(XMLNS)?; let id = element.attribute_opt_namespaced("id", XML_NS)?; let expires = element.child_opt()?; let subject = element.child_opt()?; let aliases = element.children()?; let properties = element.children()?; let links = element.children()?; let signature = element.children()?; Ok(Self { id, expires, subject, aliases, properties, links, signature, }) } } impl IntoElement for XRD { fn builder(&self) -> peanuts::element::ElementBuilder { Element::builder("XRD", Some(XMLNS)) .push_attribute_opt_namespaced(XML_NS, "id", self.id.clone()) .push_child_opt(self.expires.clone()) .push_child_opt(self.subject.clone()) .push_children(self.aliases.clone()) .push_children(self.properties.clone()) .push_children(self.links.clone()) .push_children(self.signature.clone()) } } #[derive(Debug, Clone)] pub struct Expires(pub DateTime); impl FromElement for Expires { fn from_element(mut element: Element) -> peanuts::element::DeserializeResult { element.check_name("Expires")?; element.check_namespace(XMLNS)?; Ok(Self(element.pop_value()?)) } } impl IntoElement for Expires { fn builder(&self) -> peanuts::element::ElementBuilder { Element::builder("Expires", Some(XMLNS)) .push_text(self.0.format("%C%y-%m-%dT%H:%M:%S%.3f%:z")) } } // anyURI #[derive(Debug, Clone)] pub struct Subject(pub String); impl FromElement for Subject { fn from_element(mut element: Element) -> peanuts::element::DeserializeResult { element.check_name("Subject")?; element.check_namespace(XMLNS)?; Ok(Self(element.pop_value()?)) } } impl IntoElement for Subject { fn builder(&self) -> peanuts::element::ElementBuilder { Element::builder("Subject", Some(XMLNS)).push_text(self.0.clone()) } } // anyURI #[derive(Debug, Clone)] pub struct Alias(pub String); impl FromElement for Alias { fn from_element(mut element: Element) -> peanuts::element::DeserializeResult { element.check_name("Alias")?; element.check_namespace(XMLNS)?; Ok(Self(element.pop_value()?)) } } impl IntoElement for Alias { fn builder(&self) -> peanuts::element::ElementBuilder { Element::builder("Alias", Some(XMLNS)).push_text(self.0.clone()) } } #[derive(Debug, Clone)] pub struct Property { pub r#type: String, pub property: Option, } impl FromElement for Property { fn from_element(mut element: Element) -> peanuts::element::DeserializeResult { element.check_name("Property")?; element.check_name(XMLNS)?; let r#type = element.attribute("type")?; let property = element.pop_value_opt()?; Ok(Self { r#type, property }) } } impl IntoElement for Property { fn builder(&self) -> peanuts::element::ElementBuilder { Element::builder("Property", Some(XMLNS)) .push_attribute("type", self.r#type.clone()) .push_text_opt(self.property.clone()) } } #[derive(Debug, Clone)] pub struct Link { pub rel: Option, pub r#type: Option, pub href: Option, pub template: Option, pub titles: Vec, pub properties: Vec<Property>, } impl FromElement for Link { fn from_element(mut element: Element) -> peanuts::element::DeserializeResult<Self> { element.check_name("Link")?; element.check_namespace(XMLNS)?; let rel = element.attribute_opt("rel")?; let r#type = element.attribute_opt("type")?; let href = element.attribute_opt("href")?; let template = element.attribute_opt("template")?; let titles = element.children()?; let properties = element.children()?; Ok(Self { rel, r#type, href, template, titles, properties, }) } } impl IntoElement for Link { fn builder(&self) -> peanuts::element::ElementBuilder { Element::builder("Link", Some(XMLNS)) .push_attribute_opt("rel", self.rel.clone()) .push_attribute_opt("type", self.r#type.clone()) .push_attribute_opt("href", self.href.clone()) .push_attribute_opt("template", self.template.clone()) .push_children(self.titles.clone()) .push_children(self.properties.clone()) } } #[derive(Debug, Clone)] pub struct Title { pub lang: Option<String>, pub title: String, } impl FromElement for Title { fn from_element(mut element: Element) -> peanuts::element::DeserializeResult<Self> { element.check_name("Title")?; element.check_namespace(XMLNS)?; let lang = element.attribute_opt_namespaced("lang", XML_NS)?; let title = element.pop_value_opt()?.unwrap_or_default(); Ok(Self { lang, title }) } } impl IntoElement for Title { fn builder(&self) -> peanuts::element::ElementBuilder { Element::builder("Title", Some(XMLNS)) .push_attribute_opt_namespaced(XML_NS, "lang", self.lang.clone()) .push_text(self.title.clone()) } } #[derive(Debug, Clone, Copy)] pub struct Signature; impl FromElement for Signature { fn from_element(element: Element) -> peanuts::element::DeserializeResult<Self> { element.check_name("Signature")?; element.check_namespace(SIGNATURE_XMLNS)?; Ok(Self) } } impl IntoElement for Signature { fn builder(&self) -> peanuts::element::ElementBuilder { Element::builder("Signature", Some(SIGNATURE_XMLNS)) } }