security_framework/
base.rs

1//! Support types for other modules.
2
3use core_foundation::string::CFString;
4use core_foundation_sys::base::OSStatus;
5use std::error;
6use std::fmt;
7use std::num::NonZeroI32;
8use std::result;
9
10/// A `Result` type commonly returned by functions.
11pub type Result<T, E = Error> = result::Result<T, E>;
12
13/// A Security Framework error.
14#[derive(Copy, Clone)]
15pub struct Error(NonZeroI32);
16
17impl fmt::Debug for Error {
18    #[cold]
19    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
20        let mut builder = fmt.debug_struct("Error");
21        builder.field("code", &self.0);
22        if let Some(message) = self.message() {
23            builder.field("message", &message);
24        }
25        builder.finish()
26    }
27}
28
29impl Error {
30    /// Creates a new `Error` from a status code.
31    /// The code must not be zero
32    #[inline]
33    #[must_use]
34    pub fn from_code(code: OSStatus) -> Self {
35        Self(NonZeroI32::new(code).unwrap_or_else(|| NonZeroI32::new(1).unwrap()))
36    }
37
38    /// Returns a string describing the current error, if available.
39    #[inline(always)]
40    #[must_use]
41    pub fn message(self) -> Option<String> {
42        self.inner_message()
43    }
44
45    #[cold]
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    /// Returns the code of the current error.
62    #[inline(always)]
63    #[must_use]
64    pub const fn code(self) -> OSStatus {
65        self.0.get() as _
66    }
67}
68
69impl From<OSStatus> for Error {
70    #[inline(always)]
71    #[must_use]
72    fn from(code: OSStatus) -> Self {
73        Self::from_code(code)
74    }
75}
76
77impl fmt::Display for Error {
78    #[cold]
79    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
80        if let Some(message) = self.message() {
81            write!(fmt, "{message}")
82        } else {
83            write!(fmt, "error code {}", self.code())
84        }
85    }
86}
87
88impl error::Error for Error {}