From 0ba5c799f1dabebf5f36898c1fa4f7c2010028f4 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Tue, 17 Dec 2024 08:18:24 +0100 Subject: [PATCH] Go through ObjectiveC.modulemap and take information from there Also look at libobjc.A.tdb and ObjectiveC.apinotes. This commit includes a fix to make NSObjectProtocol::isEqual take a nullable argument, which is what the APINotes declare it as (and which is important for users that want to override it, as they must handle nullability). --- crates/objc2/CHANGELOG.md | 2 ++ crates/objc2/src/runtime/mod.rs | 10 ++++++++-- crates/objc2/src/runtime/nsobject.rs | 21 ++++++++++++++------- crates/objc2/src/runtime/nsproxy.rs | 2 +- crates/objc2/src/runtime/protocol_object.rs | 2 +- 5 files changed, 26 insertions(+), 11 deletions(-) diff --git a/crates/objc2/CHANGELOG.md b/crates/objc2/CHANGELOG.md index 884ba63fd..4e94bf423 100644 --- a/crates/objc2/CHANGELOG.md +++ b/crates/objc2/CHANGELOG.md @@ -206,6 +206,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). `Hash`, instead of guarding them behind `T: Message`. * Prevented main thread only classes created using `declare_class!` from automatically implementing the auto traits `Send` and `Sync`. +* **BREAKING**: Fixed the signature of `NSObjectProtocol::isEqual` to take a + nullable argument. ## 0.5.2 - 2024-05-21 diff --git a/crates/objc2/src/runtime/mod.rs b/crates/objc2/src/runtime/mod.rs index ffde9e1c5..15870ccfa 100644 --- a/crates/objc2/src/runtime/mod.rs +++ b/crates/objc2/src/runtime/mod.rs @@ -1142,8 +1142,10 @@ unsafe impl RefEncode for AnyProtocol { /// Note that protocols are objects, though sending messages to them is /// officially deprecated. // -// SAFETY: Protocols are objects internally, and are returned as `Retained` in -// various places in Foundation. +// SAFETY: Protocols are NSObjects internally (and somewhat publicly, see e.g. +// `objc/Protocol.h`), and are returned as `Retained` in various places in +// Foundation. But that's considered deprecated, so we don't implement +// ClassType for them (even though the "Protocol" class exists). unsafe impl Message for AnyProtocol {} impl fmt::Debug for AnyProtocol { @@ -1221,6 +1223,10 @@ unsafe impl RefEncode for AnyObject { // SAFETY: This is technically slightly wrong, not all objects implement the // standard memory management methods. But not having this impl would be too // restrictive, so we'll live with it. +// +// NOTE: AnyObject actually resolves to the class "Object" internally, but we +// don't want to expose that publicly, so we only implement Message here, not +// ClassType. unsafe impl Message for AnyObject {} impl AnyObject { diff --git a/crates/objc2/src/runtime/nsobject.rs b/crates/objc2/src/runtime/nsobject.rs index 87b10e148..43e321a33 100644 --- a/crates/objc2/src/runtime/nsobject.rs +++ b/crates/objc2/src/runtime/nsobject.rs @@ -16,11 +16,9 @@ use crate::{ /// This represents the [`NSObject` class][cls]. The name "NSObject" also /// refers to a protocol, see [`NSObjectProtocol`] for that. /// -/// Since this class is only available with the `Foundation` framework, -/// `objc2` links to it for you. -/// -/// This is exported under `objc2_foundation::NSObject`, you probably -/// want to use that path instead. +/// This class has been defined in `objc` since macOS 10.8, but is also +/// re-exported under `objc2_foundation::NSObject`, you might want to use that +/// path instead. /// /// [cls]: https://developer.apple.com/documentation/objectivec/nsobject?language=objc #[repr(C)] @@ -131,7 +129,7 @@ pub unsafe trait NSObjectProtocol { /// /// [apple-doc]: https://developer.apple.com/documentation/objectivec/1418956-nsobject/1418795-isequal?language=objc #[doc(alias = "isEqual:")] - fn isEqual(&self, other: &AnyObject) -> bool + fn isEqual(&self, other: Option<&AnyObject>) -> bool where Self: Sized + Message, { @@ -259,6 +257,8 @@ pub unsafe trait NSObjectProtocol { /// let desc: Retained = unsafe { Retained::cast_unchecked(obj.description()) }; /// println!("{desc:?}"); /// ``` + // + // Only safe to override if the user-provided return type is NSString. fn description(&self) -> Retained where Self: Sized + Message, @@ -276,6 +276,8 @@ pub unsafe trait NSObjectProtocol { /// same value as `description`. Override either to provide custom object /// descriptions. // optional, introduced in macOS 10.8 + // + // Only safe to override if the user-provided return type is NSString. fn debugDescription(&self) -> Retained where Self: Sized + Message, @@ -334,6 +336,8 @@ pub unsafe trait NSObjectProtocol { { unsafe { msg_send![self, retainCount] } } + + // retain, release and autorelease below to this protocol. } crate::__inner_extern_protocol!( @@ -416,6 +420,9 @@ extern_methods!( } // TODO: `methodForSelector:`, but deprecated, showing how you should do without? + + // Don't expose load, initialize and dealloc, since these should never + // be called by the user. } ); @@ -430,7 +437,7 @@ impl PartialEq for NSObject { #[inline] #[doc(alias = "isEqual:")] fn eq(&self, other: &Self) -> bool { - self.isEqual(other) + self.isEqual(Some(other)) } } diff --git a/crates/objc2/src/runtime/nsproxy.rs b/crates/objc2/src/runtime/nsproxy.rs index 86205163f..3e85a5979 100644 --- a/crates/objc2/src/runtime/nsproxy.rs +++ b/crates/objc2/src/runtime/nsproxy.rs @@ -55,7 +55,7 @@ impl PartialEq for NSProxy { #[inline] #[doc(alias = "isEqual:")] fn eq(&self, other: &Self) -> bool { - self.isEqual(other) + self.isEqual(Some(other)) } } diff --git a/crates/objc2/src/runtime/protocol_object.rs b/crates/objc2/src/runtime/protocol_object.rs index 5c7b8757b..6ad7c1bea 100644 --- a/crates/objc2/src/runtime/protocol_object.rs +++ b/crates/objc2/src/runtime/protocol_object.rs @@ -127,7 +127,7 @@ impl PartialEq for ProtocolObject

{ #[inline] #[doc(alias = "isEqual:")] fn eq(&self, other: &Self) -> bool { - self.isEqual(&other.inner) + self.isEqual(Some(&other.inner)) } }