libxml/error.rs
1//!
2//! Wrapper for xmlError
3//!
4use super::bindings;
5
6use std::ffi::{c_char, c_int, CStr};
7
8/// Rust enum variant of libxml2's xmlErrorLevel
9#[derive(Debug)]
10pub enum XmlErrorLevel {
11 /// No error
12 None,
13 /// A simple warning
14 Warning,
15 /// A recoverable error
16 Error,
17 /// A fatal error
18 Fatal,
19}
20
21impl XmlErrorLevel {
22 /// Convert an xmlErrorLevel provided by libxml2 (as an integer) into a Rust enum
23 pub fn from_raw(error_level: bindings::xmlErrorLevel) -> XmlErrorLevel {
24 match error_level {
25 bindings::xmlErrorLevel_XML_ERR_NONE => XmlErrorLevel::None,
26 bindings::xmlErrorLevel_XML_ERR_WARNING => XmlErrorLevel::Warning,
27 bindings::xmlErrorLevel_XML_ERR_ERROR => XmlErrorLevel::Error,
28 bindings::xmlErrorLevel_XML_ERR_FATAL => XmlErrorLevel::Fatal,
29 _ => unreachable!("Should never receive an error level not in the range 0..=3"),
30 }
31 }
32}
33
34/// Wrapper around xmlErrorPtr.
35/// Some fields have been omitted for simplicity/safety
36#[derive(Debug)]
37pub struct StructuredError {
38 /// Human-friendly error message, lossily converted into UTF-8 from the underlying
39 /// C string. May be `None` if an error message is not provided by libxml2.
40 pub message: Option<String>,
41 /// The error's level
42 pub level: XmlErrorLevel,
43 /// The filename, lossily converted into UTF-8 from the underlying C string.
44 /// May be `None` if a filename is not provided by libxml2, such as when validating
45 /// an XML document stored entirely in memory.
46 pub filename: Option<String>,
47 /// The linenumber, or None if not applicable.
48 pub line: Option<c_int>,
49 /// The column where the error is present, or None if not applicable.
50 pub col: Option<c_int>,
51
52 /// The module that the error came from. See libxml's xmlErrorDomain enum.
53 pub domain: c_int,
54 /// The variety of error. See libxml's xmlParserErrors enum.
55 pub code: c_int,
56}
57
58impl StructuredError {
59 /// Copies the error information stored at `error_ptr` into a new `StructuredError`
60 ///
61 /// # Safety
62 /// This function must be given a pointer to a valid `xmlError` struct. Typically, you
63 /// will acquire such a pointer by implementing one of a number of callbacks
64 /// defined in libXml which are provided an `xmlError` as an argument.
65 ///
66 /// This function copies data from the memory `error_ptr` but does not deallocate
67 /// the error. Depending on the context in which this function is used, you may
68 /// need to take additional steps to avoid a memory leak.
69 pub unsafe fn from_raw(error_ptr: *const bindings::xmlError) -> Self {
70 let error = *error_ptr;
71 let message = StructuredError::ptr_to_string(error.message);
72 let level = XmlErrorLevel::from_raw(error.level);
73 let filename = StructuredError::ptr_to_string(error.file);
74
75 let line = if error.line == 0 {
76 None
77 } else {
78 Some(error.line)
79 };
80 let col = if error.int2 == 0 {
81 None
82 } else {
83 Some(error.int2)
84 };
85
86 StructuredError {
87 message,
88 level,
89 filename,
90 line,
91 col,
92 domain: error.domain,
93 code: error.code,
94 }
95 }
96
97 /// Human-readable informative error message.
98 ///
99 /// This function is a hold-over from the original bindings to libxml's error
100 /// reporting mechanism. Instead of calling this method, you can access the
101 /// StructuredError `message` field directly.
102 #[deprecated(since="0.3.3", note="Please use the `message` field directly instead.")]
103 pub fn message(&self) -> &str {
104 self.message.as_deref().unwrap_or("")
105 }
106
107 /// Returns the provided c_str as Some(String), or None if the provided pointer is null.
108 fn ptr_to_string(c_str: *mut c_char) -> Option<String> {
109 if c_str.is_null() {
110 return None;
111 }
112
113 let raw_str = unsafe { CStr::from_ptr(c_str) };
114 Some(String::from_utf8_lossy(raw_str.to_bytes()).to_string())
115 }
116}