• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

facet-rs / facet / 19921098942

04 Dec 2025 07:27AM UTC coverage: 57.083% (-2.1%) from 59.134%
19921098942

Pull #1015

github

web-flow
Merge ee47a41e8 into 0012fd8ca
Pull Request #1015: feat: add facet-xml crate for XML serialization/deserialization

504 of 2176 new or added lines in 3 files covered. (23.16%)

3 existing lines in 1 file now uncovered.

21465 of 37603 relevant lines covered (57.08%)

514.51 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/facet-xml/src/error.rs
1
//! Error types for XML serialization and deserialization.
2

3
use std::{
4
    error::Error,
5
    fmt::{self, Display},
6
};
7

8
use facet_core::Def;
9
use facet_reflect::ReflectError;
10
use miette::SourceSpan;
11

12
/// Error type for XML deserialization.
13
#[derive(Debug)]
14
pub struct XmlError {
15
    /// The specific kind of error
16
    pub(crate) kind: XmlErrorKind,
17
    /// Source code for diagnostics
18
    pub(crate) source_code: Option<String>,
19
    /// Primary span where the error occurred
20
    pub(crate) span: Option<SourceSpan>,
21
}
22

23
impl XmlError {
24
    /// Returns a reference to the error kind for detailed error inspection.
NEW
25
    pub fn kind(&self) -> &XmlErrorKind {
×
NEW
26
        &self.kind
×
NEW
27
    }
×
28

29
    /// Create a new error with the given kind.
NEW
30
    pub(crate) fn new(kind: impl Into<XmlErrorKind>) -> Self {
×
NEW
31
        XmlError {
×
NEW
32
            kind: kind.into(),
×
NEW
33
            source_code: None,
×
NEW
34
            span: None,
×
NEW
35
        }
×
NEW
36
    }
×
37

38
    /// Attach source code to this error for diagnostics.
NEW
39
    pub(crate) fn with_source(mut self, source: impl Into<String>) -> Self {
×
NEW
40
        self.source_code = Some(source.into());
×
NEW
41
        self
×
NEW
42
    }
×
43

44
    /// Attach a span to this error for diagnostics.
NEW
45
    pub(crate) fn with_span(mut self, span: impl Into<SourceSpan>) -> Self {
×
NEW
46
        self.span = Some(span.into());
×
NEW
47
        self
×
NEW
48
    }
×
49
}
50

51
impl Display for XmlError {
NEW
52
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> fmt::Result {
×
NEW
53
        let kind = &self.kind;
×
NEW
54
        write!(f, "{kind}")
×
NEW
55
    }
×
56
}
57

58
impl Error for XmlError {}
59

60
impl<K: Into<XmlErrorKind>> From<K> for XmlError {
NEW
61
    fn from(value: K) -> Self {
×
NEW
62
        XmlError::new(value)
×
NEW
63
    }
×
64
}
65

66
/// Detailed classification of XML errors.
67
#[derive(Debug)]
68
#[non_exhaustive]
69
pub enum XmlErrorKind {
70
    // Deserialization errors
71
    /// The document shape is invalid (expected struct with element fields).
72
    InvalidDocumentShape(&'static Def),
73
    /// Failed to parse the XML document.
74
    Parse(String),
75
    /// Error from the reflection system during deserialization.
76
    Reflect(ReflectError),
77
    /// Encountered an unsupported shape during deserialization.
78
    UnsupportedShape(String),
79
    /// No field matches the given element name.
80
    NoMatchingElement(String),
81
    /// No field matches the given attribute name.
82
    NoMatchingAttribute(String),
83
    /// Unknown attribute encountered.
84
    UnknownAttribute {
85
        /// The unknown attribute name.
86
        attribute: String,
87
        /// List of expected attribute names.
88
        expected: Vec<&'static str>,
89
    },
90
    /// No text field found for text content.
91
    NoTextField,
92
    /// Unexpected text content.
93
    UnexpectedText,
94
    /// Unsupported value definition.
95
    UnsupportedValueDef(String),
96
    /// Value doesn't fit the expected shape.
97
    InvalidValueForShape(String),
98
    /// Solver error (ambiguous or no matching variant for flattened enum).
99
    Solver(facet_solver::SolverError),
100
    /// Schema construction error.
101
    SchemaError(facet_solver::SchemaError),
102
    /// Unexpected end of input.
103
    UnexpectedEof,
104
    /// Unexpected XML event.
105
    UnexpectedEvent(String),
106
    /// Missing required element.
107
    MissingElement(String),
108
    /// Missing required attribute.
109
    MissingAttribute(String),
110
    /// Invalid attribute value.
111
    InvalidAttributeValue {
112
        /// The attribute name.
113
        name: String,
114
        /// The invalid value.
115
        value: String,
116
        /// The expected type.
117
        expected_type: String,
118
    },
119

120
    /// Unknown field encountered when deny_unknown_fields is set.
121
    UnknownField {
122
        /// The unknown field name.
123
        field: String,
124
        /// List of expected field names.
125
        expected: Vec<&'static str>,
126
    },
127
    /// Invalid UTF-8 in input.
128
    InvalidUtf8(String),
129
    /// Base64 decoding error.
130
    Base64Decode(String),
131

132
    // Serialization errors
133
    /// IO error during serialization.
134
    Io(String),
135
    /// Expected a struct for XML document serialization.
136
    SerializeNotStruct,
137
    /// Expected a list for elements field.
138
    SerializeNotList,
139
    /// Unknown element type during serialization.
140
    SerializeUnknownElementType,
141
    /// Unknown value type during serialization.
142
    SerializeUnknownValueType,
143
}
144

145
impl XmlErrorKind {
146
    /// Returns an error code for this error kind.
NEW
147
    pub fn code(&self) -> &'static str {
×
NEW
148
        match self {
×
NEW
149
            XmlErrorKind::InvalidDocumentShape(_) => "xml::invalid_document_shape",
×
NEW
150
            XmlErrorKind::Parse(_) => "xml::parse",
×
NEW
151
            XmlErrorKind::Reflect(_) => "xml::reflect",
×
NEW
152
            XmlErrorKind::UnsupportedShape(_) => "xml::unsupported_shape",
×
NEW
153
            XmlErrorKind::NoMatchingElement(_) => "xml::no_matching_element",
×
NEW
154
            XmlErrorKind::NoMatchingAttribute(_) => "xml::no_matching_attribute",
×
NEW
155
            XmlErrorKind::UnknownAttribute { .. } => "xml::unknown_attribute",
×
NEW
156
            XmlErrorKind::NoTextField => "xml::no_text_field",
×
NEW
157
            XmlErrorKind::UnexpectedText => "xml::unexpected_text",
×
NEW
158
            XmlErrorKind::UnsupportedValueDef(_) => "xml::unsupported_value_def",
×
NEW
159
            XmlErrorKind::InvalidValueForShape(_) => "xml::invalid_value",
×
NEW
160
            XmlErrorKind::Solver(_) => "xml::solver",
×
NEW
161
            XmlErrorKind::SchemaError(_) => "xml::schema",
×
NEW
162
            XmlErrorKind::UnexpectedEof => "xml::unexpected_eof",
×
NEW
163
            XmlErrorKind::UnexpectedEvent(_) => "xml::unexpected_event",
×
NEW
164
            XmlErrorKind::MissingElement(_) => "xml::missing_element",
×
NEW
165
            XmlErrorKind::MissingAttribute(_) => "xml::missing_attribute",
×
NEW
166
            XmlErrorKind::InvalidAttributeValue { .. } => "xml::invalid_attribute_value",
×
NEW
167
            XmlErrorKind::UnknownField { .. } => "xml::unknown_field",
×
NEW
168
            XmlErrorKind::InvalidUtf8(_) => "xml::invalid_utf8",
×
NEW
169
            XmlErrorKind::Base64Decode(_) => "xml::base64_decode",
×
NEW
170
            XmlErrorKind::Io(_) => "xml::io",
×
NEW
171
            XmlErrorKind::SerializeNotStruct => "xml::serialize_not_struct",
×
NEW
172
            XmlErrorKind::SerializeNotList => "xml::serialize_not_list",
×
NEW
173
            XmlErrorKind::SerializeUnknownElementType => "xml::serialize_unknown_element_type",
×
NEW
174
            XmlErrorKind::SerializeUnknownValueType => "xml::serialize_unknown_value_type",
×
175
        }
NEW
176
    }
×
177
}
178

179
impl Display for XmlErrorKind {
NEW
180
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
×
NEW
181
        match self {
×
NEW
182
            XmlErrorKind::InvalidDocumentShape(def) => {
×
NEW
183
                write!(
×
NEW
184
                    f,
×
185
                    "invalid shape {def:#?} — expected struct with element/attribute fields"
186
                )
187
            }
NEW
188
            XmlErrorKind::Parse(msg) => write!(f, "XML parse error: {msg}"),
×
NEW
189
            XmlErrorKind::Reflect(reflect_error) => write!(f, "{reflect_error}"),
×
NEW
190
            XmlErrorKind::UnsupportedShape(msg) => write!(f, "unsupported shape: {msg}"),
×
NEW
191
            XmlErrorKind::NoMatchingElement(element_name) => {
×
NEW
192
                write!(f, "no matching field for element '{element_name}'")
×
193
            }
NEW
194
            XmlErrorKind::NoMatchingAttribute(attr_name) => {
×
NEW
195
                write!(f, "no matching field for attribute '{attr_name}'")
×
196
            }
197
            XmlErrorKind::UnknownAttribute {
NEW
198
                attribute,
×
NEW
199
                expected,
×
200
            } => {
NEW
201
                write!(
×
NEW
202
                    f,
×
203
                    "unknown attribute '{}', expected one of: {}",
204
                    attribute,
NEW
205
                    expected.join(", ")
×
206
                )
207
            }
208
            XmlErrorKind::NoTextField => {
NEW
209
                write!(f, "no field marked with xml::text to receive text content")
×
210
            }
211
            XmlErrorKind::UnexpectedText => {
NEW
212
                write!(f, "unexpected text content")
×
213
            }
NEW
214
            XmlErrorKind::UnsupportedValueDef(msg) => {
×
NEW
215
                write!(f, "unsupported value definition: {msg}")
×
216
            }
NEW
217
            XmlErrorKind::InvalidValueForShape(msg) => {
×
NEW
218
                write!(f, "invalid value for shape: {msg}")
×
219
            }
NEW
220
            XmlErrorKind::Solver(e) => write!(f, "{e}"),
×
NEW
221
            XmlErrorKind::SchemaError(e) => write!(f, "schema error: {e}"),
×
NEW
222
            XmlErrorKind::UnexpectedEof => write!(f, "unexpected end of XML input"),
×
NEW
223
            XmlErrorKind::UnexpectedEvent(msg) => write!(f, "unexpected XML event: {msg}"),
×
NEW
224
            XmlErrorKind::MissingElement(name) => write!(f, "missing required element '{name}'"),
×
NEW
225
            XmlErrorKind::MissingAttribute(name) => {
×
NEW
226
                write!(f, "missing required attribute '{name}'")
×
227
            }
228
            XmlErrorKind::InvalidAttributeValue {
NEW
229
                name,
×
NEW
230
                value,
×
NEW
231
                expected_type,
×
232
            } => {
NEW
233
                write!(
×
NEW
234
                    f,
×
235
                    "invalid value '{value}' for attribute '{name}', expected {expected_type}"
236
                )
237
            }
NEW
238
            XmlErrorKind::UnknownField { field, expected } => {
×
NEW
239
                write!(
×
NEW
240
                    f,
×
241
                    "unknown field '{}', expected one of: {}",
242
                    field,
NEW
243
                    expected.join(", ")
×
244
                )
245
            }
NEW
246
            XmlErrorKind::InvalidUtf8(msg) => write!(f, "invalid UTF-8: {msg}"),
×
NEW
247
            XmlErrorKind::Base64Decode(msg) => write!(f, "base64 decode error: {msg}"),
×
NEW
248
            XmlErrorKind::Io(msg) => write!(f, "IO error: {msg}"),
×
249
            XmlErrorKind::SerializeNotStruct => {
NEW
250
                write!(f, "expected struct for XML document serialization")
×
251
            }
252
            XmlErrorKind::SerializeNotList => {
NEW
253
                write!(f, "expected list for elements field")
×
254
            }
255
            XmlErrorKind::SerializeUnknownElementType => {
NEW
256
                write!(
×
NEW
257
                    f,
×
258
                    "cannot determine element name for value (expected enum or struct with element_name)"
259
                )
260
            }
261
            XmlErrorKind::SerializeUnknownValueType => {
NEW
262
                write!(f, "cannot serialize value: unknown type")
×
263
            }
264
        }
NEW
265
    }
×
266
}
267

268
impl From<ReflectError> for XmlErrorKind {
NEW
269
    fn from(value: ReflectError) -> Self {
×
NEW
270
        Self::Reflect(value)
×
NEW
271
    }
×
272
}
273

274
impl From<facet_solver::SchemaError> for XmlErrorKind {
NEW
275
    fn from(value: facet_solver::SchemaError) -> Self {
×
NEW
276
        Self::SchemaError(value)
×
NEW
277
    }
×
278
}
279

280
// ============================================================================
281
// Diagnostic Implementation
282
// ============================================================================
283

284
impl miette::Diagnostic for XmlError {
NEW
285
    fn code<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
×
NEW
286
        Some(Box::new(self.kind.code()))
×
NEW
287
    }
×
288

NEW
289
    fn source_code(&self) -> Option<&dyn miette::SourceCode> {
×
NEW
290
        self.source_code
×
NEW
291
            .as_ref()
×
NEW
292
            .map(|s| s as &dyn miette::SourceCode)
×
NEW
293
    }
×
294

NEW
295
    fn labels(&self) -> Option<Box<dyn Iterator<Item = miette::LabeledSpan> + '_>> {
×
NEW
296
        if let Some(span) = self.span {
×
NEW
297
            let label = match &self.kind {
×
NEW
298
                XmlErrorKind::UnknownAttribute { attribute, .. } => {
×
NEW
299
                    format!("unknown attribute `{attribute}`")
×
300
                }
NEW
301
                XmlErrorKind::NoMatchingElement(name) => {
×
NEW
302
                    format!("no field matches `{name}`")
×
303
                }
NEW
304
                XmlErrorKind::NoMatchingAttribute(name) => {
×
NEW
305
                    format!("no field matches attribute `{name}`")
×
306
                }
NEW
307
                XmlErrorKind::MissingElement(name) => {
×
NEW
308
                    format!("missing element `{name}`")
×
309
                }
NEW
310
                XmlErrorKind::MissingAttribute(name) => {
×
NEW
311
                    format!("missing attribute `{name}`")
×
312
                }
NEW
313
                XmlErrorKind::UnknownField { field, .. } => {
×
NEW
314
                    format!("unknown field `{field}`")
×
315
                }
NEW
316
                _ => "error occurred here".to_string(),
×
317
            };
NEW
318
            Some(Box::new(std::iter::once(miette::LabeledSpan::at(
×
NEW
319
                span, label,
×
NEW
320
            ))))
×
321
        } else {
NEW
322
            None
×
323
        }
NEW
324
    }
×
325

NEW
326
    fn help<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
×
NEW
327
        match &self.kind {
×
NEW
328
            XmlErrorKind::UnknownAttribute { expected, .. } => Some(Box::new(format!(
×
NEW
329
                "expected one of: {}",
×
NEW
330
                expected.join(", ")
×
NEW
331
            ))),
×
NEW
332
            XmlErrorKind::NoTextField => Some(Box::new(
×
NEW
333
                "add #[facet(xml::text)] to a String field to capture text content",
×
NEW
334
            )),
×
NEW
335
            XmlErrorKind::UnknownField { expected, .. } => Some(Box::new(format!(
×
NEW
336
                "expected one of: {}",
×
NEW
337
                expected.join(", ")
×
NEW
338
            ))),
×
NEW
339
            _ => None,
×
340
        }
NEW
341
    }
×
342
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc