use std::num::{ParseFloatError, ParseIntError};
use std::string::FromUtf8Error;
use base64::DecodeError;
use quick_xml::Error as XmlError;
use serde::{Deserialize, Serialize};
use thiserror::Error as ThisError;
#[derive(ThisError, Debug)]
pub enum Error {
#[error("decoding error: {0}")]
DecodingError(#[from] DecodingError),
#[error("encoding error: {0}")]
EncodingError(#[from] EncodingError),
#[error("server fault: {0}")]
Fault(#[from] Fault),
}
impl serde::de::Error for Error {
fn custom<T>(msg: T) -> Self
where
T: std::fmt::Display,
{
DecodingError::SerdeError(msg.to_string()).into()
}
}
impl serde::ser::Error for Error {
fn custom<T>(msg: T) -> Self
where
T: std::fmt::Display,
{
EncodingError::SerdeError(msg.to_string()).into()
}
}
#[derive(ThisError, Debug)]
pub enum DecodingError {
#[error("malformed XML: {0}")]
XmlError(#[from] XmlError),
#[error("malformed XML: {0}")]
ParseIntError(#[from] ParseIntError),
#[error("malformed XML: {0}")]
ParseFloatError(#[from] ParseFloatError),
#[error("malformed XML: {0}")]
Base64DecodeError(#[from] DecodeError),
#[error("malformed XML: invalid boolean value: {0}")]
BooleanDecodeError(String),
#[error("malformed UTF-8: {0}")]
Utf8Error(#[from] FromUtf8Error),
#[error("unexpected tag: found {0}, expected {1}")]
UnexpectedTag(String, String),
#[error("unexpected error: {0}, expected tag {1}")]
UnexpectedError(anyhow::Error, String),
#[error("unexpected event: expected tag {0}")]
UnexpectedEvent(String),
#[error("unexpected EOF: expected tag {0}")]
UnexpectedEOF(String),
#[error("key must be convertable to a string")]
KeyMustBeString,
#[error("serde: {0}")]
SerdeError(String),
}
impl serde::de::Error for DecodingError {
fn custom<T>(msg: T) -> Self
where
T: std::fmt::Display,
{
DecodingError::SerdeError(msg.to_string())
}
}
#[allow(clippy::enum_variant_names)]
#[derive(ThisError, Debug)]
pub enum EncodingError {
#[error("io error: {0}")]
IoError(#[from] std::io::Error),
#[error("malformed UTF-8: {0}")]
Utf8Error(#[from] FromUtf8Error),
#[error("XML error: {0}")]
XmlError(#[from] XmlError),
#[error("invalid key type: key must be an {0}")]
InvalidKeyType(String),
#[error("serde: {0}")]
SerdeError(String),
}
impl serde::ser::Error for EncodingError {
fn custom<T>(msg: T) -> Self
where
T: std::fmt::Display,
{
EncodingError::SerdeError(msg.to_string())
}
}
pub type Result<T> = std::result::Result<T, Error>;
#[derive(ThisError, Deserialize, Serialize, Debug, PartialEq, Eq)]
#[error("{fault_string} ({fault_code})")]
#[serde(rename_all = "camelCase")]
pub struct Fault {
pub fault_code: i32,
pub fault_string: String,
}
#[cfg(test)]
mod tests {
use super::*;
use std::error;
use crate::Value;
#[test]
fn fault_roundtrip() {
let input = Fault {
fault_code: -123456,
fault_string: "The Bald Lazy House Jumps Over The Hyperactive Kitten".to_string(),
};
let value: Value = input.serialize(crate::value::Serializer::new()).unwrap();
let deserializer = crate::value::Deserializer::from_value(value);
let new_input: Fault = Fault::deserialize(deserializer).unwrap();
assert_eq!(new_input, input);
}
#[test]
fn error_impls_error() {
fn assert_error<T: error::Error>() {}
assert_error::<Error>();
}
#[test]
fn error_is_send_sync() {
fn assert_send_sync<T: Send + Sync>() {}
assert_send_sync::<Error>();
}
}