objc2_foundation/
error.rs

1use core::fmt;
2use core::panic::{RefUnwindSafe, UnwindSafe};
3use objc2::msg_send;
4use objc2::rc::Retained;
5use objc2::runtime::NSObject;
6
7use crate::{util, NSError};
8
9impl UnwindSafe for NSError {}
10impl RefUnwindSafe for NSError {}
11
12/// Creation methods.
13impl NSError {
14    /// Construct a new [`NSError`] with the given code in the given domain.
15    #[cfg(feature = "NSDictionary")]
16    #[cfg(feature = "NSString")]
17    pub fn new(
18        code: objc2::ffi::NSInteger,
19        domain: &crate::NSErrorDomain,
20    ) -> objc2::rc::Retained<Self> {
21        use objc2::AnyThread;
22        // SAFETY: `domain` and `user_info` are copied to the error object, so
23        // even if the `&NSString` came from a `&mut NSMutableString`, we're
24        // still good!
25        unsafe { Self::initWithDomain_code_userInfo(Self::alloc(), domain, code, None) }
26    }
27}
28
29/// Accessor methods.
30impl NSError {
31    #[cfg(feature = "NSString")]
32    pub fn NSLocalizedDescriptionKey() -> &'static crate::NSErrorUserInfoKey {
33        unsafe { crate::NSLocalizedDescriptionKey }
34    }
35}
36
37#[cfg(feature = "std")]
38impl std::error::Error for NSError {}
39
40impl fmt::Debug for NSError {
41    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42        let mut debug = f.debug_struct("NSError");
43        debug.field("code", &self.code());
44
45        #[cfg(feature = "NSString")]
46        debug.field("localizedDescription", &self.localizedDescription());
47
48        #[cfg(feature = "NSString")]
49        debug.field("domain", &self.domain());
50
51        #[cfg(all(feature = "NSDictionary", feature = "NSString"))]
52        debug.field("userInfo", &self.userInfo());
53
54        debug.finish_non_exhaustive()
55    }
56}
57
58impl fmt::Display for NSError {
59    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60        let desc: Retained<NSObject> = if cfg!(feature = "gnustep-1-7") {
61            // Can return NULL:
62            // https://github.com/gnustep/libs-base/issues/486
63            let desc: Option<Retained<NSObject>> = unsafe { msg_send![self, localizedDescription] };
64            if let Some(desc) = desc {
65                desc
66            } else {
67                let domain: Retained<NSObject> = unsafe { msg_send![self, domain] };
68                // SAFETY: `domain` returns `NSErrorDomain`, which is `NSString`.
69                unsafe { util::display_string(&domain, f)? };
70                write!(f, " {}", self.code())?;
71
72                return Ok(());
73            }
74        } else {
75            unsafe { msg_send![self, localizedDescription] }
76        };
77
78        // SAFETY: `localizedDescription` returns `NSString`.
79        unsafe { util::display_string(&desc, f) }
80    }
81}