opcua_xml/
error.rs

1use std::{
2    num::{ParseFloatError, ParseIntError},
3    ops::Range,
4    str::ParseBoolError,
5};
6
7use chrono::ParseError;
8use roxmltree::Node;
9use thiserror::Error;
10
11#[derive(Error, Debug, Clone)]
12/// Inner error variant of an error parsing an XML document.
13pub enum XmlErrorInner {
14    #[error("Failed to load XML: {0}")]
15    /// XML parsing error.
16    Xml(#[from] roxmltree::Error),
17    #[error("Expected child: {0}")]
18    /// Required field was missing.
19    MissingField(String),
20    #[error("Expected attribute: {0}")]
21    /// Required attribute was missing.
22    MissingAttribute(String),
23    #[error("Failed to parse {0} as integer.")]
24    /// Failed to parse content as integer.
25    ParseInt(String, ParseIntError),
26    #[error("Failed to parse {0} as float.")]
27    /// Failed to parse content as float.
28    ParseFloat(String, ParseFloatError),
29    #[error("Failed to parse {0} as bool.")]
30    /// Failed to parse content as boolean.
31    ParseBool(String, ParseBoolError),
32    #[error("Missing node content")]
33    /// Missing required content.
34    MissingContent,
35    #[error("Invalid timestamp for {0}: {1}")]
36    /// Failed to parse datatime from string.
37    ParseDateTime(String, ParseError),
38    #[error("Invalid UUID for {0}: {1}")]
39    /// Failed to parse UUID from string.
40    ParseUuid(String, uuid::Error),
41    #[error("{0}")]
42    /// Some other error.
43    Other(String),
44}
45
46#[derive(Error, Debug, Clone)]
47#[error("{error} at {span:?}")]
48/// Error returned from loading an XML document.
49pub struct XmlError {
50    /// Where in the document the node that caused the issue is found.
51    pub span: Range<usize>,
52    /// The inner error variant.
53    pub error: XmlErrorInner,
54}
55
56impl From<roxmltree::Error> for XmlError {
57    fn from(value: roxmltree::Error) -> Self {
58        Self {
59            span: 0..0,
60            error: XmlErrorInner::Xml(value),
61        }
62    }
63}
64
65impl XmlError {
66    /// Create an error for a node with a missing field with name `name`.
67    pub fn missing_field(node: &Node<'_, '_>, name: &str) -> Self {
68        Self {
69            span: node.range(),
70            error: XmlErrorInner::MissingField(name.to_owned()),
71        }
72    }
73
74    /// Create an error for a node with a missing attribute with name `name`.
75    pub fn missing_attribute(node: &Node<'_, '_>, name: &str) -> Self {
76        Self {
77            span: node.range(),
78            error: XmlErrorInner::MissingAttribute(name.to_owned()),
79        }
80    }
81
82    /// Create an error for some other, general error.
83    pub fn other(node: &Node<'_, '_>, info: &str) -> Self {
84        Self {
85            span: node.range(),
86            error: XmlErrorInner::Other(info.to_owned()),
87        }
88    }
89
90    /// Create an error for failing to parse a string as an integer.
91    pub fn parse_int(node: &Node<'_, '_>, attr: &str, err: ParseIntError) -> Self {
92        Self {
93            span: node.range(),
94            error: XmlErrorInner::ParseInt(attr.to_owned(), err),
95        }
96    }
97
98    /// Create an error for failing to parse a string as a float.
99    pub fn parse_float(node: &Node<'_, '_>, attr: &str, err: ParseFloatError) -> Self {
100        Self {
101            span: node.range(),
102            error: XmlErrorInner::ParseFloat(attr.to_owned(), err),
103        }
104    }
105
106    /// Create an error for failing to parse a string as a boolean.
107    pub fn parse_bool(node: &Node<'_, '_>, attr: &str, err: ParseBoolError) -> Self {
108        Self {
109            span: node.range(),
110            error: XmlErrorInner::ParseBool(attr.to_owned(), err),
111        }
112    }
113
114    /// Create an error for failing to parse a string as a date time.
115    pub fn parse_date_time(node: &Node<'_, '_>, attr: &str, err: ParseError) -> Self {
116        Self {
117            span: node.range(),
118            error: XmlErrorInner::ParseDateTime(attr.to_owned(), err),
119        }
120    }
121
122    /// Create an error for failing to parse a string as a UUID.
123    pub fn parse_uuid(node: &Node<'_, '_>, attr: &str, err: uuid::Error) -> Self {
124        Self {
125            span: node.range(),
126            error: XmlErrorInner::ParseUuid(attr.to_owned(), err),
127        }
128    }
129
130    /// Create an error indicating that `node` does not have the necessary content.
131    pub fn missing_content(node: &Node<'_, '_>) -> Self {
132        Self {
133            span: node.range(),
134            error: XmlErrorInner::MissingContent,
135        }
136    }
137}