1use std::ffi::c_void;
49use std::ptr::NonNull;
50
51use mtl_sys::{class, msg_send_0, msg_send_3, sel};
52
53use crate::array::Array;
54use crate::dictionary::Dictionary;
55use crate::object::{Copying, Referencing};
56use crate::string::String;
57use crate::types::Integer;
58
59pub type ErrorDomain = *mut String;
63
64pub type ErrorUserInfoKey = *mut String;
68
69#[link(name = "Foundation", kind = "framework")]
71unsafe extern "C" {
72 #[link_name = "NSCocoaErrorDomain"]
73 static COCOA_ERROR_DOMAIN: *mut c_void;
74
75 #[link_name = "NSPOSIXErrorDomain"]
76 static POSIX_ERROR_DOMAIN: *mut c_void;
77
78 #[link_name = "NSOSStatusErrorDomain"]
79 static OS_STATUS_ERROR_DOMAIN: *mut c_void;
80
81 #[link_name = "NSMachErrorDomain"]
82 static MACH_ERROR_DOMAIN: *mut c_void;
83
84 #[link_name = "NSUnderlyingErrorKey"]
85 static UNDERLYING_ERROR_KEY: *mut c_void;
86
87 #[link_name = "NSLocalizedDescriptionKey"]
88 static LOCALIZED_DESCRIPTION_KEY: *mut c_void;
89
90 #[link_name = "NSLocalizedFailureReasonErrorKey"]
91 static LOCALIZED_FAILURE_REASON_ERROR_KEY: *mut c_void;
92
93 #[link_name = "NSLocalizedRecoverySuggestionErrorKey"]
94 static LOCALIZED_RECOVERY_SUGGESTION_ERROR_KEY: *mut c_void;
95
96 #[link_name = "NSLocalizedRecoveryOptionsErrorKey"]
97 static LOCALIZED_RECOVERY_OPTIONS_ERROR_KEY: *mut c_void;
98
99 #[link_name = "NSRecoveryAttempterErrorKey"]
100 static RECOVERY_ATTEMPTER_ERROR_KEY: *mut c_void;
101
102 #[link_name = "NSHelpAnchorErrorKey"]
103 static HELP_ANCHOR_ERROR_KEY: *mut c_void;
104
105 #[link_name = "NSDebugDescriptionErrorKey"]
106 static DEBUG_DESCRIPTION_ERROR_KEY: *mut c_void;
107
108 #[link_name = "NSLocalizedFailureErrorKey"]
109 static LOCALIZED_FAILURE_ERROR_KEY: *mut c_void;
110
111 #[link_name = "NSStringEncodingErrorKey"]
112 static STRING_ENCODING_ERROR_KEY: *mut c_void;
113
114 #[link_name = "NSURLErrorKey"]
115 static URL_ERROR_KEY: *mut c_void;
116
117 #[link_name = "NSFilePathErrorKey"]
118 static FILE_PATH_ERROR_KEY: *mut c_void;
119}
120
121#[inline]
125pub fn cocoa_error_domain() -> ErrorDomain {
126 unsafe { COCOA_ERROR_DOMAIN as ErrorDomain }
127}
128
129#[inline]
133pub fn posix_error_domain() -> ErrorDomain {
134 unsafe { POSIX_ERROR_DOMAIN as ErrorDomain }
135}
136
137#[inline]
141pub fn os_status_error_domain() -> ErrorDomain {
142 unsafe { OS_STATUS_ERROR_DOMAIN as ErrorDomain }
143}
144
145#[inline]
149pub fn mach_error_domain() -> ErrorDomain {
150 unsafe { MACH_ERROR_DOMAIN as ErrorDomain }
151}
152
153#[inline]
157pub fn underlying_error_key() -> ErrorUserInfoKey {
158 unsafe { UNDERLYING_ERROR_KEY as ErrorUserInfoKey }
159}
160
161#[inline]
165pub fn localized_description_key() -> ErrorUserInfoKey {
166 unsafe { LOCALIZED_DESCRIPTION_KEY as ErrorUserInfoKey }
167}
168
169#[inline]
173pub fn localized_failure_reason_error_key() -> ErrorUserInfoKey {
174 unsafe { LOCALIZED_FAILURE_REASON_ERROR_KEY as ErrorUserInfoKey }
175}
176
177#[inline]
181pub fn localized_recovery_suggestion_error_key() -> ErrorUserInfoKey {
182 unsafe { LOCALIZED_RECOVERY_SUGGESTION_ERROR_KEY as ErrorUserInfoKey }
183}
184
185#[inline]
189pub fn localized_recovery_options_error_key() -> ErrorUserInfoKey {
190 unsafe { LOCALIZED_RECOVERY_OPTIONS_ERROR_KEY as ErrorUserInfoKey }
191}
192
193#[inline]
197pub fn recovery_attempter_error_key() -> ErrorUserInfoKey {
198 unsafe { RECOVERY_ATTEMPTER_ERROR_KEY as ErrorUserInfoKey }
199}
200
201#[inline]
205pub fn help_anchor_error_key() -> ErrorUserInfoKey {
206 unsafe { HELP_ANCHOR_ERROR_KEY as ErrorUserInfoKey }
207}
208
209#[inline]
213pub fn debug_description_error_key() -> ErrorUserInfoKey {
214 unsafe { DEBUG_DESCRIPTION_ERROR_KEY as ErrorUserInfoKey }
215}
216
217#[inline]
221pub fn localized_failure_error_key() -> ErrorUserInfoKey {
222 unsafe { LOCALIZED_FAILURE_ERROR_KEY as ErrorUserInfoKey }
223}
224
225#[inline]
229pub fn string_encoding_error_key() -> ErrorUserInfoKey {
230 unsafe { STRING_ENCODING_ERROR_KEY as ErrorUserInfoKey }
231}
232
233#[inline]
237pub fn url_error_key() -> ErrorUserInfoKey {
238 unsafe { URL_ERROR_KEY as ErrorUserInfoKey }
239}
240
241#[inline]
245pub fn file_path_error_key() -> ErrorUserInfoKey {
246 unsafe { FILE_PATH_ERROR_KEY as ErrorUserInfoKey }
247}
248
249#[repr(transparent)]
253#[derive(Clone)]
254pub struct Error(NonNull<c_void>);
255
256impl Error {
257 #[inline]
261 pub fn error(domain: ErrorDomain, code: Integer, user_info: *mut Dictionary) -> Option<Self> {
262 unsafe {
263 let ptr: *mut c_void = msg_send_3(
264 class!(NSError).as_ptr(),
265 sel!(errorWithDomain:code:userInfo:),
266 domain,
267 code,
268 user_info,
269 );
270 Self::from_ptr(ptr)
271 }
272 }
273
274 #[inline]
278 pub fn alloc() -> Option<Self> {
279 unsafe {
280 let ptr: *mut c_void = msg_send_0(class!(NSError).as_ptr(), sel!(alloc));
281 Self::from_ptr(ptr)
282 }
283 }
284
285 #[inline]
289 pub fn init(&self) -> Option<Self> {
290 unsafe {
291 let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(init));
292 Self::from_ptr(ptr)
293 }
294 }
295
296 #[inline]
300 pub fn init_with_domain(
301 &self,
302 domain: ErrorDomain,
303 code: Integer,
304 user_info: *mut Dictionary,
305 ) -> Option<Self> {
306 unsafe {
307 let ptr: *mut c_void = msg_send_3(
308 self.as_ptr(),
309 sel!(initWithDomain:code:userInfo:),
310 domain,
311 code,
312 user_info,
313 );
314 Self::from_ptr(ptr)
315 }
316 }
317
318 #[inline]
322 pub fn code(&self) -> Integer {
323 unsafe { msg_send_0(self.as_ptr(), sel!(code)) }
324 }
325
326 #[inline]
330 pub fn domain(&self) -> ErrorDomain {
331 unsafe { msg_send_0(self.as_ptr(), sel!(domain)) }
332 }
333
334 #[inline]
338 pub fn user_info(&self) -> *mut Dictionary {
339 unsafe { msg_send_0(self.as_ptr(), sel!(userInfo)) }
340 }
341
342 #[inline]
346 pub fn localized_description(&self) -> *mut String {
347 unsafe { msg_send_0(self.as_ptr(), sel!(localizedDescription)) }
348 }
349
350 #[inline]
354 pub fn localized_recovery_options(&self) -> *mut Array<String> {
355 unsafe { msg_send_0(self.as_ptr(), sel!(localizedRecoveryOptions)) }
356 }
357
358 #[inline]
362 pub fn localized_recovery_suggestion(&self) -> *mut String {
363 unsafe { msg_send_0(self.as_ptr(), sel!(localizedRecoverySuggestion)) }
364 }
365
366 #[inline]
370 pub fn localized_failure_reason(&self) -> *mut String {
371 unsafe { msg_send_0(self.as_ptr(), sel!(localizedFailureReason)) }
372 }
373
374 #[inline]
380 pub unsafe fn from_ptr(ptr: *mut c_void) -> Option<Self> {
381 NonNull::new(ptr).map(Self)
382 }
383}
384
385impl Referencing for Error {
386 #[inline]
387 fn as_ptr(&self) -> *const c_void {
388 self.0.as_ptr()
389 }
390}
391
392impl Copying for Error {
393 #[inline]
394 fn copy(&self) -> Option<Self> {
395 unsafe {
396 let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(copy));
397 Self::from_ptr(ptr)
398 }
399 }
400}
401
402unsafe impl Send for Error {}
404unsafe impl Sync for Error {}
405
406impl std::fmt::Debug for Error {
407 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
408 f.debug_struct("Error")
409 .field("ptr", &self.0)
410 .field("code", &self.code())
411 .finish()
412 }
413}
414
415impl std::fmt::Display for Error {
416 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
417 let desc_ptr = self.localized_description();
418 if !desc_ptr.is_null() {
419 let desc = unsafe { &*desc_ptr };
420 if let Some(s) = desc.to_string() {
421 return write!(f, "{}", s);
422 }
423 }
424 write!(f, "Error(code={})", self.code())
425 }
426}
427
428impl std::error::Error for Error {}
429
430#[cfg(test)]
431mod tests {
432 use super::*;
433
434 #[test]
435 fn test_error_size() {
436 assert_eq!(
438 std::mem::size_of::<Error>(),
439 std::mem::size_of::<*mut c_void>()
440 );
441 }
442}