1 use std::ffi; 2 use std::ffi::CString; 3 use std::fmt; 4 use std::str; 5 6 use libc::c_char; 7 use regex; 8 9 #[derive(Debug)] 10 pub struct Error { 11 message: Option<CString>, 12 kind: ErrorKind, 13 } 14 15 #[derive(Debug)] 16 pub enum ErrorKind { 17 None, 18 Str(str::Utf8Error), 19 Regex(regex::Error), 20 Nul(ffi::NulError), 21 } 22 23 impl Error { new(kind: ErrorKind) -> Error24 pub fn new(kind: ErrorKind) -> Error { 25 Error { message: None, kind: kind } 26 } 27 is_err(&self) -> bool28 pub fn is_err(&self) -> bool { 29 match self.kind { 30 ErrorKind::None => false, 31 ErrorKind::Str(_) | ErrorKind::Regex(_) | ErrorKind::Nul(_) => { 32 true 33 } 34 } 35 } 36 } 37 38 impl fmt::Display for Error { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result39 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 40 match self.kind { 41 ErrorKind::None => write!(f, "no error"), 42 ErrorKind::Str(ref e) => e.fmt(f), 43 ErrorKind::Regex(ref e) => e.fmt(f), 44 ErrorKind::Nul(ref e) => e.fmt(f), 45 } 46 } 47 } 48 49 ffi_fn! { 50 fn rure_error_new() -> *mut Error { 51 Box::into_raw(Box::new(Error::new(ErrorKind::None))) 52 } 53 } 54 55 ffi_fn! { 56 fn rure_error_free(err: *mut Error) { 57 unsafe { drop(Box::from_raw(err)); } 58 } 59 } 60 61 ffi_fn! { 62 fn rure_error_message(err: *mut Error) -> *const c_char { 63 let err = unsafe { &mut *err }; 64 let cmsg = match CString::new(format!("{}", err)) { 65 Ok(msg) => msg, 66 Err(err) => { 67 // I guess this can probably happen if the regex itself has a 68 // NUL, and that NUL re-occurs in the context presented by the 69 // error message. In this case, just show as much as we can. 70 let nul = err.nul_position(); 71 let msg = err.into_vec(); 72 CString::new(msg[0..nul].to_owned()).unwrap() 73 } 74 }; 75 let p = cmsg.as_ptr(); 76 err.message = Some(cmsg); 77 p 78 } 79 } 80