use std::str::FromStr;
use peanuts::{
element::{FromElement, IntoElement},
DeserializeError, Element,
};
pub const XMLNS: &str = "jabber:x:data";
#[derive(Debug, Clone)]
pub struct X {
pub r#type: XType,
pub instructions: Vec<Instructions>,
pub title: Option<Title>,
pub fields: Vec<Field>,
pub reported: Option<Reported>,
pub items: Vec<Item>,
}
impl FromElement for X {
fn from_element(mut element: Element) -> peanuts::element::DeserializeResult<Self> {
element.check_name("x")?;
element.check_namespace(XMLNS)?;
let r#type = element.attribute("type")?;
let instructions = element.pop_children()?;
let title = element.pop_child_opt()?;
let fields = element.pop_children()?;
let reported = element.pop_child_opt()?;
let items = element.pop_children()?;
Ok(Self {
r#type,
instructions,
title,
fields,
reported,
items,
})
}
}
impl IntoElement for X {
fn builder(&self) -> peanuts::element::ElementBuilder {
Element::builder("x", Some(XMLNS))
.push_attribute("type", self.r#type.clone())
.push_children(self.instructions.clone())
.push_child_opt(self.title.clone())
.push_children(self.fields.clone())
.push_child_opt(self.reported.clone())
.push_children(self.items.clone())
}
}
#[derive(Debug, Clone)]
pub enum XType {
Cancel,
Form,
Result,
Submit,
}
impl FromStr for XType {
type Err = DeserializeError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"cancel" => Ok(Self::Cancel),
"form" => Ok(Self::Form),
"result" => Ok(Self::Result),
"submit" => Ok(Self::Submit),
s => Err(DeserializeError::FromStr(s.to_string())),
}
}
}
impl ToString for XType {
fn to_string(&self) -> String {
match self {
XType::Cancel => "cancel",
XType::Form => "form",
XType::Result => "result",
XType::Submit => "submit",
}
.to_owned()
}
}
#[derive(Debug, Clone)]
pub struct Instructions(pub String);
impl FromElement for Instructions {
fn from_element(mut element: Element) -> peanuts::element::DeserializeResult<Self> {
element.check_name("instructions")?;
element.check_namespace(XMLNS)?;
Ok(Self(element.pop_value_opt()?.unwrap_or_default()))
}
}
impl IntoElement for Instructions {
fn builder(&self) -> peanuts::element::ElementBuilder {
Element::builder("instructions", Some(XMLNS)).push_text(self.0.clone())
}
}
#[derive(Debug, Clone)]
pub struct Title(pub String);
impl FromElement for Title {
fn from_element(mut element: Element) -> peanuts::element::DeserializeResult<Self> {
element.check_name("instructions")?;
element.check_namespace(XMLNS)?;
Ok(Self(element.pop_value_opt()?.unwrap_or_default()))
}
}
impl IntoElement for Title {
fn builder(&self) -> peanuts::element::ElementBuilder {
Element::builder("title", Some(XMLNS)).push_text(self.0.clone())
}
}
#[derive(Debug, Clone)]
pub struct Field {
pub label: Option<String>,
pub r#type: Option<FieldType>,
pub var: Option<String>,
pub desc: Option<Desc>,
pub required: bool,
pub values: Vec<Value>,
pub options: Vec<XOption>,
}
impl FromElement for Field {
fn from_element(mut element: Element) -> peanuts::element::DeserializeResult<Self> {
element.check_name("field")?;
element.check_namespace(XMLNS)?;
let label = element.attribute_opt("label")?;
let r#type = element.attribute_opt("type")?;
let var = element.attribute_opt("var")?;
let desc = element.pop_child_opt()?;
let required;
if let Some(_) = element.pop_child_opt::<Required>()? {
required = true;
} else {
required = false;
}
let values = element.pop_children()?;
let options = element.pop_children()?;
Ok(Self {
label,
r#type,
var,
desc,
required,
values,
options,
})
}
}
impl IntoElement for Field {
fn builder(&self) -> peanuts::element::ElementBuilder {
let mut builder = Element::builder("field", Some(XMLNS))
.push_attribute_opt("label", self.label.clone())
.push_attribute_opt("type", self.r#type.clone())
.push_attribute_opt("var", self.var.clone())
.push_child_opt(self.desc.clone());
if self.required {
builder = builder.push_child(Required)
}
builder
.push_children(self.values.clone())
.push_children(self.options.clone())
}
}
#[derive(Debug, Clone)]
pub enum FieldType {
Boolean,
Fixed,
Hidden,
JIDMulti,
JIDSingle,
ListMulti,
ListSingle,
TextMulti,
TextPrivate,
TextSingle,
}
impl FromStr for FieldType {
type Err = DeserializeError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"boolean" => Ok(Self::Boolean),
"fixed" => Ok(Self::Fixed),
"hidden" => Ok(Self::Hidden),
"jid-multi" => Ok(Self::JIDMulti),
"jid-single" => Ok(Self::JIDSingle),
"list-multi" => Ok(Self::ListMulti),
"list-single" => Ok(Self::ListSingle),
"text-multi" => Ok(Self::TextMulti),
"text-private" => Ok(Self::TextPrivate),
"text-single" => Ok(Self::TextSingle),
s => Err(DeserializeError::FromStr(s.to_string())),
}
}
}
impl ToString for FieldType {
fn to_string(&self) -> String {
match self {
FieldType::Boolean => "boolean",
FieldType::Fixed => "fixed",
FieldType::Hidden => "hidden",
FieldType::JIDMulti => "jid-multi",
FieldType::JIDSingle => "jid-single",
FieldType::ListMulti => "list-multi",
FieldType::ListSingle => "list-single",
FieldType::TextMulti => "text-multi",
FieldType::TextPrivate => "text-private",
FieldType::TextSingle => "text-single",
}
.to_owned()
}
}
#[derive(Debug, Clone)]
pub struct Desc(pub String);
impl FromElement for Desc {
fn from_element(mut element: Element) -> peanuts::element::DeserializeResult<Self> {
element.check_name("desc")?;
element.check_namespace(XMLNS)?;
Ok(Self(element.pop_value_opt()?.unwrap_or_default()))
}
}
impl IntoElement for Desc {
fn builder(&self) -> peanuts::element::ElementBuilder {
Element::builder("desc", Some(XMLNS)).push_text(self.0.clone())
}
}
#[derive(Debug, Clone)]
pub struct Required;
impl FromElement for Required {
fn from_element(element: Element) -> peanuts::element::DeserializeResult<Self> {
element.check_name("required")?;
element.check_namespace(XMLNS)?;
Ok(Self)
}
}
impl IntoElement for Required {
fn builder(&self) -> peanuts::element::ElementBuilder {
Element::builder("required", Some(XMLNS))
}
}
#[derive(Debug, Clone)]
pub struct XOption {
pub label: Option<String>,
pub value: Value,
}
impl FromElement for XOption {
fn from_element(mut element: Element) -> peanuts::element::DeserializeResult<Self> {
element.check_name("option")?;
element.check_namespace(XMLNS)?;
let label = element.attribute_opt("label")?;
let value = element.pop_child_one()?;
Ok(Self { label, value })
}
}
impl IntoElement for XOption {
fn builder(&self) -> peanuts::element::ElementBuilder {
Element::builder("option", Some(XMLNS))
.push_attribute_opt("label", self.label.clone())
.push_child(self.value.clone())
}
}
#[derive(Debug, Clone)]
pub struct Value(pub String);
impl FromElement for Value {
fn from_element(mut element: Element) -> peanuts::element::DeserializeResult<Self> {
element.check_name("value")?;
element.check_namespace(XMLNS)?;
Ok(Self(element.pop_value_opt()?.unwrap_or_default()))
}
}
impl IntoElement for Value {
fn builder(&self) -> peanuts::element::ElementBuilder {
Element::builder("value", Some(XMLNS)).push_text(self.0.clone())
}
}
#[derive(Debug, Clone)]
pub struct Reported {
/// fields SHOULD NOT contain value children
fields: Vec<Field>,
}
impl FromElement for Reported {
fn from_element(mut element: Element) -> peanuts::element::DeserializeResult<Self> {
element.check_name("reported")?;
element.check_namespace(XMLNS)?;
let fields = element.pop_children()?;
Ok(Self { fields })
}
}
impl IntoElement for Reported {
fn builder(&self) -> peanuts::element::ElementBuilder {
Element::builder("reported", Some(XMLNS)).push_children(self.fields.clone())
}
}
#[derive(Debug, Clone)]
pub struct Item {
fields: Vec<Field>,
}
impl FromElement for Item {
fn from_element(mut element: Element) -> peanuts::element::DeserializeResult<Self> {
element.check_name("item")?;
element.check_namespace(XMLNS)?;
let fields = element.pop_children()?;
Ok(Self { fields })
}
}
impl IntoElement for Item {
fn builder(&self) -> peanuts::element::ElementBuilder {
Element::builder("item", Some(XMLNS)).push_children(self.fields.clone())
}
}