1use core::fmt;
4
5use apple_cf::CFError;
6
7pub type Result<T, E = SecurityError> = std::result::Result<T, E>;
9
10pub type OsStatus = i32;
12
13pub mod status {
15 use super::OsStatus;
16
17 pub const SUCCESS: OsStatus = 0;
18 pub const DUPLICATE_ITEM: OsStatus = -25_299;
19 pub const ITEM_NOT_FOUND: OsStatus = -25_300;
20 pub const INTERACTION_NOT_ALLOWED: OsStatus = -25_308;
21}
22
23#[derive(Debug, Clone, PartialEq, Eq)]
25pub struct StatusError {
26 pub operation: &'static str,
28 pub status: OsStatus,
30 pub message: String,
32}
33
34impl fmt::Display for StatusError {
35 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36 write!(
37 f,
38 "{} failed with OSStatus {}: {}",
39 self.operation, self.status, self.message
40 )
41 }
42}
43
44impl std::error::Error for StatusError {}
45
46#[derive(Debug, Clone, PartialEq, Eq)]
48#[non_exhaustive]
49pub enum SecurityError {
50 InvalidArgument(String),
52 ItemNotFound(String),
54 DuplicateItem(String),
56 InteractionNotAllowed(String),
58 TrustEvaluationFailed(String),
60 UnexpectedType {
62 operation: &'static str,
64 expected: &'static str,
66 },
67 Serialization(String),
69 CoreFoundation(CFError),
71 Status(StatusError),
73}
74
75impl SecurityError {
76 #[must_use]
77 pub const fn code(&self) -> Option<OsStatus> {
78 match self {
79 Self::ItemNotFound(_) => Some(status::ITEM_NOT_FOUND),
80 Self::DuplicateItem(_) => Some(status::DUPLICATE_ITEM),
81 Self::InteractionNotAllowed(_) => Some(status::INTERACTION_NOT_ALLOWED),
82 Self::Status(error) => Some(error.status),
83 _ => None,
84 }
85 }
86
87 pub(crate) fn from_status(operation: &'static str, status: OsStatus, message: String) -> Self {
88 match status {
89 status::ITEM_NOT_FOUND => Self::ItemNotFound(message),
90 status::DUPLICATE_ITEM => Self::DuplicateItem(message),
91 status::INTERACTION_NOT_ALLOWED => Self::InteractionNotAllowed(message),
92 _ => Self::Status(StatusError {
93 operation,
94 status,
95 message,
96 }),
97 }
98 }
99}
100
101impl fmt::Display for SecurityError {
102 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
103 match self {
104 Self::InvalidArgument(message) => write!(f, "invalid argument: {message}"),
105 Self::ItemNotFound(message) => write!(f, "item not found: {message}"),
106 Self::DuplicateItem(message) => write!(f, "duplicate item: {message}"),
107 Self::InteractionNotAllowed(message) => write!(f, "interaction not allowed: {message}"),
108 Self::TrustEvaluationFailed(message) => {
109 write!(f, "trust evaluation failed: {message}")
110 }
111 Self::UnexpectedType {
112 operation,
113 expected,
114 } => write!(
115 f,
116 "{operation} returned an unexpected value (expected {expected})"
117 ),
118 Self::Serialization(message) => write!(f, "serialization error: {message}"),
119 Self::CoreFoundation(error) => write!(f, "{error}"),
120 Self::Status(error) => write!(f, "{error}"),
121 }
122 }
123}
124
125impl std::error::Error for SecurityError {
126 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
127 match self {
128 Self::CoreFoundation(error) => Some(error),
129 Self::Status(error) => Some(error),
130 _ => None,
131 }
132 }
133}