use std::{ collections::{HashMap, VecDeque}, num::ParseIntError, str::Utf8Error, sync::Arc, }; use thiserror::Error; #[cfg(target_arch = "wasm32")] use wasm_bindgen::JsValue; use crate::{ element::{Content, Name, NamespaceDeclaration}, Element, }; /// Error type for the `FromElement` trait. Used when deserialising from an `Element`. #[derive(Error, Debug, Clone)] pub enum DeserializeError { /// Could not parse string. #[error("could not parse string {0:?} to requested value")] FromStr(String), /// Unexpected attributes. #[error("unexpected attributes {0:?}")] UnexpectedAttributes(HashMap), /// Unexpected element content. #[error("unexpected element content: {0:?}")] UnexpectedContent(VecDeque), /// Missing attribute. #[error("attribute `{0:?}` missing")] MissingAttribute(Name), /// Incorrect localname encountered. #[error("incorrect localname: expected `{expected:?}`, found `{found:?}`")] IncorrectName { expected: String, found: String }, /// Incorrect namespace encountered. #[error("incorrect namespace: expected `{expected:?}`, found `{found:?}`")] IncorrectNamespace { expected: String, found: String }, /// Unqualified namespace when expecting qualified namespace. #[error("unqualified namespace: expected `{expected:?}`")] Unqualified { expected: String }, /// Element missing expected child. #[error("element missing expected child")] MissingChild, /// Element missing expected text value. #[error("element missing expected text value")] MissingValue, // not used by crate (yet), but may be used by consumers implementing FromElement /// Unexpected element. #[error("unexpected element: {0:?}")] UnexpectedElement(Element), /// Attribute is an empty string. #[error("attribute `{0}` is an empty string")] AttributeEmptyString(String), /// Empty string. #[error("empty string")] EmptyString, } /// General error type for functions in the crate. // TODO: add error context (usually the stanza) #[derive(Error, Debug, Clone)] pub enum Error { #[cfg(target_arch = "wasm32")] #[error("websocket closed")] WebSocketClosed, #[error("io: {0}")] // TODO: is this okay? ReadError(Arc), #[error("utf8 conversion: {0}")] Utf8Error(#[from] Utf8Error), #[error("nom parsing: {0}")] ParseError(String, String), #[error("unknown xml entity reference `&{0};`")] EntityProcessError(String), #[error("invalid character reference: {0}")] InvalidCharRef(CharRefError), #[error("duplicate namespace declaration: {0:?}")] DuplicateNameSpaceDeclaration(NamespaceDeclaration), #[error("duplicate attribute: {0}")] DuplicateAttribute(String), #[error("mismatched end tag: expected `{0:?}`, found `{1:?}`")] MismatchedEndTag(Name, Name), #[error("not currently in any element")] NotInElement(String), #[error("extra unexpected data included in complete parse: `{0}`")] ExtraData(String), #[error("namespace `{0}` has not previously been declared")] UndeclaredNamespace(String), #[error("deserialization error: {0}")] Deserialize(#[from] DeserializeError), #[error("root element has already been fully processed")] RootElementEnded, #[cfg(target_arch = "wasm32")] #[error("websocket error: {0}")] Websocket(#[from] WebsocketError), } /// Websocket-related errors. #[cfg(target_arch = "wasm32")] #[derive(Error, Debug, Clone)] pub enum WebsocketError { /// Websocket write error. #[error("write")] Write, /// Invalid encoding. #[error("invalid encoding")] InvalidEncoding, /// Can't decode blob. #[error("can't decode blob")] CantDecodeBlob, /// Unknown data type. #[error("unknown data type")] UnknownDataType, } #[cfg(target_arch = "wasm32")] impl From for Error { fn from(_e: JsValue) -> Self { Self::Websocket(WebsocketError::Write) } } impl From for Error { fn from(e: std::io::Error) -> Self { Self::ReadError(Arc::new(e)) } } /// Character reference decode error. #[derive(Error, Debug, Clone)] pub enum CharRefError { /// Int parsing. #[error("int parsing: {0}")] ParseInt(#[from] ParseIntError), /// Integer is not a valid char. #[error("u32 `{0}` does not represent a valid char")] IntegerNotAChar(u32), /// Character is an invalid XML char. #[error("`{0}` is not a valid xml char")] InvalidXMLChar(char), }