1313//! - [Exception Programming Topics for Cocoa](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Exceptions/Exceptions.html)
1414//! - [The Objective-C Programming Language - Exception Handling](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocExceptionHandling.html)
1515//! - [Exception Handling in LLVM](https://llvm.org/docs/ExceptionHandling.html)
16+ //!
17+ //! [`msg_send!`]: crate::msg_send
1618
1719// TODO: Test this with panic=abort, and ensure that the code-size is
1820// reasonable in that case.
1921
20- use alloc:: string:: String ;
21- use alloc:: string:: ToString ;
2222#[ cfg( feature = "exception" ) ]
2323use core:: ffi:: c_void;
2424use core:: fmt;
@@ -29,41 +29,16 @@ use core::panic::RefUnwindSafe;
2929use core:: panic:: UnwindSafe ;
3030#[ cfg( feature = "exception" ) ]
3131use core:: ptr;
32- use core:: slice;
3332use objc2_encode:: Encoding ;
3433use objc2_encode:: RefEncode ;
3534use std:: error:: Error ;
36- use std:: os:: raw:: c_char;
3735
3836#[ cfg( feature = "exception" ) ]
3937use crate :: ffi;
40- use crate :: rc :: autoreleasepool ;
38+ # [ cfg ( feature = "exception" ) ]
4139use crate :: rc:: { Id , Shared } ;
42- use crate :: runtime:: Class ;
4340use crate :: runtime:: Object ;
4441use crate :: Message ;
45- use crate :: { msg_send, msg_send_bool, msg_send_id, sel} ;
46-
47- /// Unfortunate reimplementation of `objc2::foundation::NSString`.
48- ///
49- /// I guess this is the price of wanting to do things "right"...
50- unsafe fn to_string_hack ( obj : Id < Object , Shared > ) -> String {
51- #[ cfg( feature = "apple" ) ]
52- const UTF8_ENCODING : usize = 4 ;
53- #[ cfg( feature = "gnustep-1-7" ) ]
54- const UTF8_ENCODING : i32 = 4 ;
55-
56- autoreleasepool ( |_| {
57- let len: usize = unsafe { msg_send ! [ & obj, lengthOfBytesUsingEncoding: UTF8_ENCODING ] } ;
58-
59- let bytes: * const c_char = unsafe { msg_send ! [ & obj, UTF8String ] } ;
60- let bytes: * const u8 = bytes. cast ( ) ;
61- let bytes: & [ u8 ] = unsafe { slice:: from_raw_parts ( bytes, len) } ;
62-
63- // Use lossy to avoid panic in error situations
64- String :: from_utf8_lossy ( bytes) . to_string ( )
65- } )
66- }
6742
6843/// An Objective-C exception.
6944///
@@ -100,78 +75,45 @@ impl AsRef<Object> for Exception {
10075// Note: We can't implement `Send` nor `Sync` since the exception could be
10176// anything!
10277
103- impl Exception {
104- /// Checks whether this is an instance of `NSException`.
105- ///
106- /// This should be considered a hint; it may return `false` in very, very
107- /// few cases where it is actually `true`, but if it returns `true`, then
108- /// it is definitely an instance of `NSException`.
109- fn is_nsexception ( & self ) -> bool {
110- // If `NSException` class is present
111- if let Some ( cls) = Class :: get ( "NSException" ) {
112- if self . 0 . class ( ) . responds_to ( sel ! ( isKindOfClass: ) ) {
113- unsafe { msg_send_bool ! [ self , isKindOfClass: cls] }
114- } else {
115- false
116- }
117- } else {
118- false
119- }
120- }
121-
122- // SAFETY: Must ensure that self is NSException
123- unsafe fn name ( & self ) -> Option < String > {
124- let obj: Option < Id < Object , Shared > > = unsafe { msg_send_id ! [ self , name] } ;
125- obj. map ( |obj| unsafe { to_string_hack ( obj) } )
126- }
127-
128- // SAFETY: Must ensure that self is NSException
129- unsafe fn reason ( & self ) -> Option < String > {
130- let obj: Option < Id < Object , Shared > > = unsafe { msg_send_id ! [ self , reason] } ;
131- obj. map ( |obj| unsafe { to_string_hack ( obj) } )
132- }
133- }
134-
135- // This is not in any way efficient, but that's not really the point!
136- //
137- // We mostly just want to present a somewhat usable error message when the
138- // `catch-all` feature is enabled!
13978impl fmt:: Debug for Exception {
14079 fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
141- write ! ( f, "exception {:?}" , self . 0 ) ?;
142-
143- // Attempt to provide better error message
144- if self . is_nsexception ( ) {
145- // SAFETY: We know that these are safe to call since this is an
146- // instance of `NSException`.
147- let name = unsafe { self . name ( ) } ;
148- let reason = unsafe { self . reason ( ) } ;
149-
150- if let Some ( name) = name {
151- write ! ( f, " '{}'" , name) ?;
152- } else {
153- write ! ( f, " (NULL)" ) ?;
154- }
155-
156- if let Some ( reason) = reason {
157- write ! ( f, " reason:{}" , reason) ?;
158- } else {
159- write ! ( f, " reason:(NULL)" ) ?;
160- }
80+ write ! ( f, "exception " ) ?;
81+
82+ // Attempt to present a somewhat usable error message if the
83+ // `foundation` feature is enabled
84+ #[ cfg( feature = "foundation" ) ]
85+ if crate :: foundation:: NSException :: is_nsexception ( self ) {
86+ // SAFETY: Just checked that object is an NSException
87+ let obj: * const Self = self ;
88+ let obj = unsafe {
89+ obj. cast :: < crate :: foundation:: NSException > ( )
90+ . as_ref ( )
91+ . unwrap ( )
92+ } ;
93+ return write ! ( f, "{:?}" , obj) ;
16194 }
16295
163- Ok ( ( ) )
96+ // Fall back to `Object` Debug
97+ write ! ( f, "{:?}" , self . 0 )
16498 }
16599}
166100
167101impl fmt:: Display for Exception {
168102 fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
169- if self . is_nsexception ( ) {
170- // SAFETY: Just checked that this is NSException.
171- if let Some ( reason) = unsafe { self . reason ( ) } {
103+ #[ cfg( feature = "foundation" ) ]
104+ if crate :: foundation:: NSException :: is_nsexception ( self ) {
105+ // SAFETY: Just checked that object is an NSException
106+ let obj: * const Self = self ;
107+ let obj = unsafe {
108+ obj. cast :: < crate :: foundation:: NSException > ( )
109+ . as_ref ( )
110+ . unwrap ( )
111+ } ;
112+ if let Some ( reason) = obj. reason ( ) {
172113 return write ! ( f, "{}" , reason) ;
173114 }
174115 }
116+
175117 write ! ( f, "unknown exception" )
176118 }
177119}
0 commit comments