objc2_foundation/
exception.rs1use core::fmt;
2use core::hint::unreachable_unchecked;
3use core::panic::{RefUnwindSafe, UnwindSafe};
4
5use objc2::exception::Exception;
6use objc2::rc::Retained;
7use objc2::runtime::{AnyObject, NSObject, NSObjectProtocol};
8use objc2::{extern_methods, msg_send, sel, ClassType};
9
10use crate::{util, NSException};
11
12unsafe impl Sync for NSException {}
15unsafe impl Send for NSException {}
16
17impl UnwindSafe for NSException {}
18impl RefUnwindSafe for NSException {}
19
20impl NSException {
21 extern_methods!(
22 #[unsafe(method(raise))]
23 unsafe fn raise_raw(&self);
24 );
25}
26
27impl NSException {
28 #[cfg(all(feature = "NSObjCRuntime", feature = "NSString"))]
33 #[cfg(feature = "NSDictionary")]
34 pub fn new(
35 name: &crate::NSExceptionName,
36 reason: Option<&crate::NSString>,
37 user_info: Option<&crate::NSDictionary>,
38 ) -> Option<Retained<Self>> {
39 use objc2::AnyThread;
40
41 unsafe {
42 objc2::msg_send![
43 Self::alloc(),
44 initWithName: name,
45 reason: reason,
46 userInfo: user_info,
47 ]
48 }
49 }
50
51 pub fn raise(&self) -> ! {
56 unsafe { self.raise_raw() };
59 unsafe { unreachable_unchecked() }
62 }
63
64 pub fn into_exception(this: Retained<Self>) -> Retained<Exception> {
66 unsafe { Retained::cast_unchecked(this) }
68 }
69
70 fn is_nsexception(obj: &Exception) -> bool {
71 if obj.class().responds_to(sel!(isKindOfClass:)) {
72 let obj: *const Exception = obj;
74 let obj = unsafe { obj.cast::<NSObject>().as_ref().unwrap() };
75 obj.isKindOfClass(Self::class())
76 } else {
77 false
78 }
79 }
80
81 pub fn from_exception(obj: Retained<Exception>) -> Result<Retained<Self>, Retained<Exception>> {
86 if Self::is_nsexception(&obj) {
87 Ok(unsafe { Retained::cast_unchecked::<Self>(obj) })
89 } else {
90 Err(obj)
91 }
92 }
93}
94
95impl fmt::Debug for NSException {
96 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
97 let obj: &AnyObject = self.as_ref();
98 write!(f, "{obj:?}")?;
99
100 write!(f, " '")?;
101 let name: Retained<NSObject> = unsafe { msg_send![self, name] };
102 unsafe { util::display_string(&name, f)? };
104 write!(f, "'")?;
105
106 write!(f, " reason: ")?;
107 let reason: Option<Retained<NSObject>> = unsafe { msg_send![self, reason] };
108 if let Some(reason) = reason {
109 unsafe { util::display_string(&reason, f)? };
111 } else {
112 write!(f, "(NULL)")?;
113 }
114 Ok(())
115 }
116}