1use std::fmt;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub enum XmlSafetyError {
8 InvalidPolicy,
10 InputTooLarge,
12 OutputTooLarge,
14 ExternalEntity,
16 TooDeep,
18 TooManyElements,
20 TooManyAttributes,
22 TextTooLarge,
24 TooManyEvents,
26 InvalidEncoding,
28 Malformed,
30}
31
32impl fmt::Display for XmlSafetyError {
33 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
34 f.write_str(match self {
35 Self::InvalidPolicy => "XML safety limits must be positive",
36 Self::InputTooLarge => "XML input exceeds the configured byte limit",
37 Self::OutputTooLarge => "XML output exceeds the configured byte limit",
38 Self::ExternalEntity => "XML DTD and custom entity declarations are not allowed",
39 Self::TooDeep => "XML nesting depth exceeds the configured limit",
40 Self::TooManyElements => "XML element count exceeds the configured limit",
41 Self::TooManyAttributes => "XML attribute count exceeds the configured limit",
42 Self::TextTooLarge => "XML text size exceeds the configured limit",
43 Self::TooManyEvents => "XML event count exceeds the configured limit",
44 Self::InvalidEncoding => "XML input contains invalid encoded text",
45 Self::Malformed => "malformed XML input",
46 })
47 }
48}
49
50impl std::error::Error for XmlSafetyError {}
51
52#[derive(Debug)]
54pub enum Error {
55 Safety(XmlSafetyError),
57 InvalidXml(String),
59 InvalidData(String),
61 Io(std::io::Error),
63}
64
65impl fmt::Display for Error {
66 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67 match self {
68 Self::Safety(error) => write!(f, "XML safety error: {error}"),
69 Self::InvalidXml(message) => write!(f, "invalid XML: {message}"),
70 Self::InvalidData(message) => write!(f, "invalid XML data: {message}"),
71 Self::Io(error) => write!(f, "XML I/O error: {error}"),
72 }
73 }
74}
75
76impl std::error::Error for Error {
77 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
78 match self {
79 Self::Safety(error) => Some(error),
80 Self::Io(error) => Some(error),
81 Self::InvalidXml(_) | Self::InvalidData(_) => None,
82 }
83 }
84}
85
86impl From<XmlSafetyError> for Error {
87 fn from(error: XmlSafetyError) -> Self {
88 Self::Safety(error)
89 }
90}
91
92impl From<std::io::Error> for Error {
93 fn from(error: std::io::Error) -> Self {
94 Self::Io(error)
95 }
96}
97
98#[cfg(test)]
99mod tests {
100 use super::*;
101
102 #[test]
103 fn wrapped_error_display_is_distinct_from_its_source() {
104 let safety = Error::Safety(XmlSafetyError::TextTooLarge);
105 assert_eq!(
106 safety.to_string(),
107 "XML safety error: XML text size exceeds the configured limit"
108 );
109 assert_eq!(
110 std::error::Error::source(&safety).map(ToString::to_string),
111 Some("XML text size exceeds the configured limit".into())
112 );
113
114 let io = Error::Io(std::io::Error::other("fixture failure"));
115 assert_eq!(io.to_string(), "XML I/O error: fixture failure");
116 assert_eq!(
117 std::error::Error::source(&io).map(ToString::to_string),
118 Some("fixture failure".into())
119 );
120 }
121}