apple_security_framework/
base.rs

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