1 //! Support types for other modules. 2 3 #[cfg(target_os = "macos")] 4 use core_foundation::string::CFString; 5 use core_foundation_sys::base::OSStatus; 6 use std::error; 7 use std::fmt; 8 use std::num::NonZeroI32; 9 use std::result; 10 11 /// A `Result` type commonly returned by functions. 12 pub type Result<T, E = Error> = result::Result<T, E>; 13 14 /// A Security Framework error. 15 #[derive(Copy, Clone)] 16 pub struct Error(NonZeroI32); 17 18 impl fmt::Debug for Error { 19 #[cold] fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result20 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 21 let mut builder = fmt.debug_struct("Error"); 22 builder.field("code", &self.0); 23 if let Some(message) = self.message() { 24 builder.field("message", &message); 25 } 26 builder.finish() 27 } 28 } 29 30 impl Error { 31 /// Creates a new `Error` from a status code. 32 /// The code must not be zero 33 #[inline] from_code(code: OSStatus) -> Self34 pub fn from_code(code: OSStatus) -> Self { 35 Self(NonZeroI32::new(code as i32).unwrap_or_else(|| NonZeroI32::new(1).unwrap())) 36 } 37 38 /// Returns a string describing the current error, if available. 39 #[inline(always)] message(self) -> Option<String>40 pub fn message(self) -> Option<String> { 41 self.inner_message() 42 } 43 44 #[cfg(target_os = "macos")] 45 #[cold] inner_message(self) -> Option<String>46 fn inner_message(self) -> Option<String> { 47 use core_foundation::base::TCFType; 48 use security_framework_sys::base::SecCopyErrorMessageString; 49 use std::ptr; 50 51 unsafe { 52 let s = SecCopyErrorMessageString(self.code(), ptr::null_mut()); 53 if s.is_null() { 54 None 55 } else { 56 Some(CFString::wrap_under_create_rule(s).to_string()) 57 } 58 } 59 } 60 61 #[cfg(not(target_os = "macos"))] 62 #[inline(always)] inner_message(&self) -> Option<String>63 fn inner_message(&self) -> Option<String> { 64 None 65 } 66 67 /// Returns the code of the current error. 68 #[inline(always)] code(self) -> OSStatus69 pub fn code(self) -> OSStatus { 70 self.0.get() as _ 71 } 72 } 73 74 impl From<OSStatus> for Error { 75 #[inline(always)] from(code: OSStatus) -> Self76 fn from(code: OSStatus) -> Self { 77 Self::from_code(code) 78 } 79 } 80 81 impl fmt::Display for Error { 82 #[cold] fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result83 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 84 if let Some(message) = self.message() { 85 write!(fmt, "{}", message) 86 } else { 87 write!(fmt, "error code {}", self.code()) 88 } 89 } 90 } 91 92 impl error::Error for Error { 93 } 94