vpp_plugin/vppinfra/
error.rs1use core::str;
7use std::{
8 error::Error as StdError,
9 ffi::{CStr, CString},
10 fmt::{self, Display},
11 mem::ManuallyDrop,
12};
13
14use super::{Vec, VecRef};
15use crate::bindings::{_clib_error_return, CLIB_ERROR_ERRNO_VALID, clib_error_t, uword};
16
17#[derive(Debug, Copy, Clone)]
21#[repr(transparent)]
22pub struct Error(clib_error_t);
23
24impl fmt::Display for Error {
25 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
26 if self.0.what.is_null() {
27 return write!(fmt, "<none>");
28 }
29
30 if !self.0.where_.is_null() {
31 let where_c = unsafe { CStr::from_ptr(self.0.where_.cast()) };
33 write!(fmt, "{}: ", where_c.to_string_lossy())?;
34 }
35 let what_v = unsafe { VecRef::from_raw(self.0.what) };
37 let what_str = str::from_utf8(what_v).unwrap_or("<invalid>");
38 write!(fmt, "{}", what_str)
39 }
40}
41
42#[derive(Debug)]
47pub struct ErrorStack(Vec<Error>);
48
49impl ErrorStack {
50 pub unsafe fn from_raw(ptr: *mut clib_error_t) -> Self {
57 unsafe { Self(Vec::from_raw(ptr.cast())) }
59 }
60
61 pub fn into_raw(self) -> *mut clib_error_t {
66 let errors = ManuallyDrop::new(self);
67 errors.0.as_mut_ptr().cast()
68 }
69
70 fn new_internal(
76 errors: Option<Self>,
77 what: String,
78 code: Option<crate::bindings::any>,
79 ) -> Self {
80 let errors_ptr = if let Some(errors) = errors {
81 errors.into_raw()
82 } else {
83 std::ptr::null_mut()
84 };
85 let what_c = CString::new(what).expect("message should not contain nul characters");
86 let flags = if code.is_some() {
87 CLIB_ERROR_ERRNO_VALID as uword
88 } else {
89 0
90 };
91 let code = code.unwrap_or_default();
92 unsafe {
96 Self::from_raw(_clib_error_return(
97 errors_ptr,
98 code,
99 flags,
100 std::ptr::null_mut(),
101 what_c.as_ptr(),
102 ))
103 }
104 }
105
106 pub fn new<E: StdError + Send + Sync + 'static>(e: E) -> Self {
114 Self::new_internal(None, e.to_string(), None)
115 }
116
117 pub fn msg<M>(message: M) -> Self
123 where
124 M: Display + Send + Sync + 'static,
125 {
126 Self::new_internal(None, message.to_string(), None)
127 }
128
129 pub fn context<C>(self, context: C) -> Self
135 where
136 C: Display + Send + Sync + 'static,
137 {
138 Self::new_internal(Some(self), context.to_string(), None)
139 }
140
141 pub fn errors(&self) -> &[Error] {
143 self.0.as_slice()
144 }
145}
146
147impl Drop for ErrorStack {
148 fn drop(&mut self) {
149 for e in self.errors() {
150 if e.0.what.is_null() {
151 continue;
152 }
153 let _ = unsafe { Vec::from_raw(e.0.what) };
156 }
157 }
158}
159
160impl Display for ErrorStack {
161 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
162 let errs = self.errors();
163 if let Some(err) = errs.last() {
164 write!(f, "{}", err)?;
165 if errs.len() > 1 {
166 write!(f, "\n\nCaused by:")?;
167 for err in errs[..errs.len() - 1].iter().rev() {
168 writeln!(f)?;
169 write!(f, " {}", err)?;
170 }
171 }
172 } else {
173 write!(f, "Empty VPP error")?;
174 }
175 Ok(())
176 }
177}
178
179impl StdError for ErrorStack {}
180
181#[cfg(test)]
182mod tests {
183 use super::*;
184
185 use crate::vppinfra::clib_mem_init;
186
187 #[test]
188 fn basic() {
189 clib_mem_init();
190
191 let io_e = std::io::Error::new(std::io::ErrorKind::AlreadyExists, "Already exists");
192 let e = ErrorStack::new(io_e);
193 assert_eq!(e.errors().len(), 1);
194 assert_eq!(e.to_string(), "Already exists");
195
196 let e = ErrorStack::msg("Unknown interface");
197 assert_eq!(e.errors().len(), 1);
198 assert_eq!(e.to_string(), "Unknown interface");
199
200 let e = e.context("Failed to enable feature");
201 assert_eq!(e.errors().len(), 2);
202 assert_eq!(
203 e.to_string(),
204 "\
205Failed to enable feature
206
207Caused by:
208 Unknown interface"
209 );
210 }
211
212 #[test]
213 fn ptrs() {
214 clib_mem_init();
215
216 let e = ErrorStack::msg("Unknown interface");
217 assert_eq!(e.errors().len(), 1);
218 assert_eq!(e.to_string(), "Unknown interface");
219
220 let ptr = e.into_raw();
221 let e = unsafe { ErrorStack::from_raw(ptr) };
223 assert_eq!(e.errors().len(), 1);
224 assert_eq!(e.to_string(), "Unknown interface");
225 }
226}