aboutsummaryrefslogtreecommitdiffstats
path: root/src/error.rs
blob: 26b7766854ae26421d003499dc1d334824778eb1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
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<Name, String>),
    /// Unexpected element content.
    #[error("unexpected element content: {0:?}")]
    UnexpectedContent(VecDeque<Content>),
    /// 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<std::io::Error>),
    #[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<JsValue> for Error {
    fn from(_e: JsValue) -> Self {
        Self::Websocket(WebsocketError::Write)
    }
}

impl From<std::io::Error> 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),
}