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(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