use std::fmt::Display; use std::str::FromStr; use peanuts::element::{FromElement, IntoElement}; use peanuts::{DeserializeError, Element}; use thiserror::Error; use crate::stanza_error::Error as StanzaError; use crate::stanza_error::Text; use super::XMLNS; #[derive(Clone, Debug, Error)] pub struct Error { by: Option, r#type: ErrorType, // children (sequence) error: StanzaError, text: Option, } impl Display for Error { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}, {}", self.r#type, self.error)?; if let Some(text) = &self.text { if let Some(text) = &text.text { write!(f, ": {}", text)?; } } if let Some(by) = &self.by { write!(f, " (error returned by `{}`)", by)?; } Ok(()) } } impl FromElement for Error { fn from_element(mut element: peanuts::Element) -> peanuts::element::DeserializeResult { element.check_name("error")?; element.check_name(XMLNS)?; let by = element.attribute_opt("by")?; let r#type = element.attribute("type")?; let error = element.pop_child_one()?; let text = element.pop_child_opt()?; Ok(Error { by, r#type, error, text, }) } } impl IntoElement for Error { fn builder(&self) -> peanuts::element::ElementBuilder { Element::builder("error", Some(XMLNS)) .push_attribute_opt("by", self.by.clone()) .push_attribute("type", self.r#type) .push_child(self.error.clone()) .push_child_opt(self.text.clone()) } } #[derive(Copy, Clone, Debug)] pub enum ErrorType { Auth, Cancel, Continue, Modify, Wait, } impl Display for ErrorType { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { ErrorType::Auth => f.write_str("auth"), ErrorType::Cancel => f.write_str("cancel"), ErrorType::Continue => f.write_str("continue"), ErrorType::Modify => f.write_str("modify"), ErrorType::Wait => f.write_str("wait"), } } } impl FromStr for ErrorType { type Err = DeserializeError; fn from_str(s: &str) -> Result { match s { "auth" => Ok(ErrorType::Auth), "cancel" => Ok(ErrorType::Cancel), "continue" => Ok(ErrorType::Continue), "modify" => Ok(ErrorType::Modify), "wait" => Ok(ErrorType::Wait), _ => Err(DeserializeError::FromStr(s.to_string())), } } }