diff --git a/Cargo.lock b/Cargo.lock index 0a11d7763..112412047 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -500,6 +500,7 @@ dependencies = [ name = "test_declare_class" version = "0.1.0" dependencies = [ + "icrate", "objc2", ] diff --git a/crates/header-translator/src/data/AppKit.rs b/crates/header-translator/src/data/AppKit.rs index fab0b72b4..57bc56ac4 100644 --- a/crates/header-translator/src/data/AppKit.rs +++ b/crates/header-translator/src/data/AppKit.rs @@ -250,4 +250,8 @@ data! { // `addChildWindow:ordered:` is not safe, as cycles must be prevented } + + class NSTouch: Immutable {} + + class NSUserInterfaceCompressionOptions: Immutable {} } diff --git a/crates/header-translator/src/data/CloudKit.rs b/crates/header-translator/src/data/CloudKit.rs index 89a871f29..4588cc7f1 100644 --- a/crates/header-translator/src/data/CloudKit.rs +++ b/crates/header-translator/src/data/CloudKit.rs @@ -1,2 +1,4 @@ data! { + class CKRecordID: Immutable {} + class CKRecordZoneID: Immutable {} } diff --git a/crates/header-translator/src/data/Foundation.rs b/crates/header-translator/src/data/Foundation.rs index 928fc67fb..40f0b20e3 100644 --- a/crates/header-translator/src/data/Foundation.rs +++ b/crates/header-translator/src/data/Foundation.rs @@ -241,4 +241,6 @@ data! { class NSURLRequest: ImmutableWithMutableSubclass {} class NSMutableURLRequest: MutableWithImmutableSuperclass {} + + class NSIndexPath: Immutable {} } diff --git a/crates/icrate/CHANGELOG.md b/crates/icrate/CHANGELOG.md index 58cd68d27..01a0f4da0 100644 --- a/crates/icrate/CHANGELOG.md +++ b/crates/icrate/CHANGELOG.md @@ -15,6 +15,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). * Added `Send` and `Sync` implementations for a bunch more types (same as the ones Swift marks as `@Sendable`). * Made some common methods in `AppKit` safe. +* Added missing `NSCopying` and `NSMutableCopying` zone methods. +* Added `Eq` and `Ord` implementations for `NSNumber`, since its + handling of floating point values allows it. +* Added `NS[Mutable]Dictionary::from_id_slice` and + `NS[Mutable]Dictionary::from_slice`. +* Added `NSMutableDictionary::insert` and `NSMutableSet::insert` which can + be more efficient than the previous insertion methods. ### Changed * Moved the `ns_string!` macro to `icrate::Foundation::ns_string`. The old @@ -41,10 +48,23 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). // Do something with `app` and `view` ``` * **BREAKING**: Changed the `NSApp` static to be a function taking `MainThreadMarker`. +* **BREAKING**: Renamed `NS[Mutable]Dictionary::from_keys_and_objects` to + `NS[Mutable]Dictionary::from_vec`. +* **BREAKING**: Renamed `NSMutableDictionary::insert` and + `NSMutableSet::insert` to `insert_id`. ### Removed * **BREAKING**: Removed the `MainThreadMarker` argument from the closure passed to `MainThreadBound::get_on_main`. +* **BREAKING**: Removed `Foundation::CopyHelper` since it is superseded by + `objc2::mutability::CounterpartOrSelf`. + +### Fixed +* **BREAKING**: Added `Eq + Hash` requirement on most `NSDictionary` and + `NSSet` methods, thereby making sure that the types are actually correct + to use in such hashing collections. +* **BREAKING**: Added `HasStableHash` requirement on `NSDictionary` and + `NSSet` creation methods, fixing a long-standing soundess issue. ## icrate 0.0.4 - 2023-07-31 diff --git a/crates/icrate/examples/basic_usage.rs b/crates/icrate/examples/basic_usage.rs index 711273a10..7b40c67b4 100644 --- a/crates/icrate/examples/basic_usage.rs +++ b/crates/icrate/examples/basic_usage.rs @@ -36,8 +36,8 @@ fn main() { // Create a dictionary mapping strings to objects let keys = &[string]; - let vals = vec![obj]; - let dict = NSDictionary::from_keys_and_objects(keys, vals); + let objects = &[obj]; + let dict = NSDictionary::from_id_slice(keys, objects); println!("{:?}", dict.get(string)); println!("{}", dict.len()); } diff --git a/crates/icrate/src/additions/Foundation/dictionary.rs b/crates/icrate/src/additions/Foundation/dictionary.rs index c0526f43d..f2fef8d08 100644 --- a/crates/icrate/src/additions/Foundation/dictionary.rs +++ b/crates/icrate/src/additions/Foundation/dictionary.rs @@ -1,65 +1,152 @@ //! Utilities for the `NSDictionary` and `NSMutableDictionary` classes. #![cfg(feature = "Foundation_NSDictionary")] use alloc::vec::Vec; +use core::borrow::Borrow; use core::cmp::min; use core::fmt; +use core::hash::Hash; use core::mem; use core::ops::{Index, IndexMut}; use core::panic::{RefUnwindSafe, UnwindSafe}; use core::ptr::{self, NonNull}; -use objc2::mutability::IsMutable; +use objc2::mutability::{CounterpartOrSelf, HasStableHash, IsIdCloneable, IsMutable, IsRetainable}; use super::iter; use super::util; use crate::common::*; #[cfg(feature = "Foundation_NSMutableDictionary")] use crate::Foundation::NSMutableDictionary; -use crate::Foundation::{self, Copyhelper, NSCopying, NSDictionary}; +use crate::Foundation::{self, NSCopying, NSDictionary}; -impl NSDictionary { - pub fn from_keys_and_objects(keys: &[&T], mut vals: Vec>) -> Id +impl NSDictionary { + pub fn from_vec(keys: &[&Q], mut objects: Vec>) -> Id + where + Q: Message + NSCopying + CounterpartOrSelf, + { + // Find the minimum of the two provided lengths, to ensure that we + // don't read too far in one of the buffers. + // + // Note: We could also have chosen to just panic here if the buffers have + // different lengths, either would be fine. + let count = min(keys.len(), objects.len()); + + let keys: *mut NonNull = util::ref_ptr_cast_const(keys.as_ptr()); + let keys: *mut NonNull = keys.cast(); + let objects = util::id_ptr_cast(objects.as_mut_ptr()); + + // SAFETY: + // - The objects are valid, similar reasoning as `NSArray::from_vec`. + // + // - The key must not be mutated, as that may cause the hash value to + // change, which is unsound as stated in: + // https://developer.apple.com/library/archive/documentation/General/Conceptual/CocoaEncyclopedia/ObjectMutability/ObjectMutability.html#//apple_ref/doc/uid/TP40010810-CH5-SW69 + // + // The dictionary always copies its keys, which is why we require + // `NSCopying` and use `CounterpartOrSelf` on all input data - we + // want to ensure that it is very clear that it's not actually + // `NSMutableString` that is being stored, but `NSString`. + // + // But that is not by itself enough to verify that the key does not + // still contain interior mutable objects (e.g. if the copy was only + // a shallow copy), which is why we also require `HasStableHash`. + // + // - The length is lower than or equal to the length of the two arrays. + unsafe { Self::initWithObjects_forKeys_count(Self::alloc(), objects, keys, count) } + } + + pub fn from_id_slice(keys: &[&Q], objects: &[Id]) -> Id where - T: ClassType + NSCopying, - T::Mutability: Copyhelper, + Q: Message + NSCopying + CounterpartOrSelf, + V: IsIdCloneable, { - let count = min(keys.len(), vals.len()); + let count = min(keys.len(), objects.len()); - let keys: *mut NonNull = util::ref_ptr_cast_const(keys.as_ptr()); + let keys: *mut NonNull = util::ref_ptr_cast_const(keys.as_ptr()); let keys: *mut NonNull = keys.cast(); - let vals = util::id_ptr_cast(vals.as_mut_ptr()); + let objects = util::id_ptr_cast_const(objects.as_ptr()); - unsafe { Self::initWithObjects_forKeys_count(Self::alloc(), vals, keys, count) } + // SAFETY: See `NSDictionary::from_vec` and `NSArray::from_id_slice`. + unsafe { Self::initWithObjects_forKeys_count(Self::alloc(), objects, keys, count) } + } + + pub fn from_slice(keys: &[&Q], objects: &[&V]) -> Id + where + Q: Message + NSCopying + CounterpartOrSelf, + V: IsRetainable, + { + let count = min(keys.len(), objects.len()); + + let keys: *mut NonNull = util::ref_ptr_cast_const(keys.as_ptr()); + let keys: *mut NonNull = keys.cast(); + let objects = util::ref_ptr_cast_const(objects.as_ptr()); + + // SAFETY: See `NSDictionary::from_vec` and `NSArray::from_slice`. + unsafe { Self::initWithObjects_forKeys_count(Self::alloc(), objects, keys, count) } } } #[cfg(feature = "Foundation_NSMutableDictionary")] -impl NSMutableDictionary { - pub fn from_keys_and_objects(keys: &[&T], mut vals: Vec>) -> Id +impl NSMutableDictionary { + pub fn from_vec(keys: &[&Q], mut objects: Vec>) -> Id where - T: ClassType + NSCopying, - T::Mutability: Copyhelper, + Q: Message + NSCopying + CounterpartOrSelf, { - let count = min(keys.len(), vals.len()); + let count = min(keys.len(), objects.len()); - let keys: *mut NonNull = util::ref_ptr_cast_const(keys.as_ptr()); + let keys: *mut NonNull = util::ref_ptr_cast_const(keys.as_ptr()); let keys: *mut NonNull = keys.cast(); - let vals = util::id_ptr_cast(vals.as_mut_ptr()); + let objects = util::id_ptr_cast(objects.as_mut_ptr()); - unsafe { Self::initWithObjects_forKeys_count(Self::alloc(), vals, keys, count) } + // SAFETY: See `NSDictionary::from_vec` + unsafe { Self::initWithObjects_forKeys_count(Self::alloc(), objects, keys, count) } } -} -extern_methods!( - unsafe impl NSDictionary { - pub fn len(&self) -> usize { - self.count() - } + pub fn from_id_slice(keys: &[&Q], objects: &[Id]) -> Id + where + Q: Message + NSCopying + CounterpartOrSelf, + V: IsIdCloneable, + { + let count = min(keys.len(), objects.len()); - pub fn is_empty(&self) -> bool { - self.len() == 0 - } + let keys: *mut NonNull = util::ref_ptr_cast_const(keys.as_ptr()); + let keys: *mut NonNull = keys.cast(); + let objects = util::id_ptr_cast_const(objects.as_ptr()); + + // SAFETY: See `NSDictionary::from_vec` and `NSArray::from_id_slice`. + unsafe { Self::initWithObjects_forKeys_count(Self::alloc(), objects, keys, count) } + } + + pub fn from_slice(keys: &[&Q], objects: &[&V]) -> Id + where + Q: Message + NSCopying + CounterpartOrSelf, + V: IsRetainable, + { + let count = min(keys.len(), objects.len()); + + let keys: *mut NonNull = util::ref_ptr_cast_const(keys.as_ptr()); + let keys: *mut NonNull = keys.cast(); + let objects = util::ref_ptr_cast_const(objects.as_ptr()); + // SAFETY: See `NSDictionary::from_vec` and `NSArray::from_slice`. + unsafe { Self::initWithObjects_forKeys_count(Self::alloc(), objects, keys, count) } + } +} + +// Note: We'd like to make getter methods take `K: Borrow` like +// `std::collections::HashMap`, so that e.g. +// `NSDictionary` could take a `&NSObject` as input, +// and still make that work since `NSString` borrows to `NSObject`. +// +// But we can't really, at least not with extra `unsafe` / an extra +// trait, since we don't control how the comparisons happen. +// +// The most useful alternative would probably be to take +// `impl AsRef`, but objc2 classes deref to their superclass anyhow, so +// let's just use a simple normal reference. + +extern_methods!( + unsafe impl NSDictionary { #[doc(alias = "objectForKey:")] #[method(objectForKey:)] pub fn get(&self, key: &K) -> Option<&V>; @@ -95,7 +182,7 @@ extern_methods!( /// use icrate::Foundation::{ns_string, NSMutableDictionary, NSMutableString, NSString}; /// /// let mut dict = NSMutableDictionary::new(); - /// dict.insert(NSString::from_str("one"), NSMutableString::new()); + /// dict.insert_id(ns_string!("one"), NSMutableString::new()); /// println!("{:?}", dict.get_mut(ns_string!("one"))); /// ``` #[doc(alias = "objectForKey:")] @@ -107,6 +194,14 @@ extern_methods!( ); impl NSDictionary { + pub fn len(&self) -> usize { + self.count() + } + + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + #[doc(alias = "getObjects:andKeys:")] pub fn keys_vec(&self) -> Vec<&K> { let len = self.len(); @@ -119,8 +214,7 @@ impl NSDictionary { } } - // We don't provide `keys_mut_vec`, since keys are expected to be - // immutable. + // We don't provide `keys_mut_vec`, since keys are immutable. #[doc(alias = "getObjects:andKeys:")] pub fn values_vec(&self) -> Vec<&V> { @@ -152,10 +246,10 @@ impl NSDictionary { )), doc = "```ignore" )] - /// use icrate::Foundation::{NSMutableDictionary, NSMutableString, NSString}; + /// use icrate::Foundation::{ns_string, NSMutableDictionary, NSMutableString, NSString}; /// /// let mut dict = NSMutableDictionary::new(); - /// dict.insert(NSString::from_str("one"), NSMutableString::from_str("two")); + /// dict.insert_id(ns_string!("one"), NSMutableString::from_str("two")); /// for val in dict.values_mut() { /// println!("{:?}", val); /// } @@ -188,10 +282,35 @@ impl NSDictionary { (mem::transmute(keys), mem::transmute(objs)) } } + + /// Returns an [`NSArray`] containing the dictionary's values. + /// + /// [`NSArray`]: crate::Foundation::NSArray + /// + /// + /// # Examples + /// + /// ``` + /// use icrate::Foundation::{ns_string, NSMutableDictionary, NSObject, NSString}; + /// + /// let mut dict = NSMutableDictionary::new(); + /// dict.insert_id(ns_string!("one"), NSObject::new()); + /// let array = dict.to_array(); + /// assert_eq!(array.len(), 1); + /// ``` + #[cfg(feature = "Foundation_NSArray")] + pub fn to_array(&self) -> Id> + where + V: IsIdCloneable, + { + // SAFETY: The elements are retainable behind `Id`, so getting + // another reference to them (via. `NSArray`) is sound. + unsafe { self.allValues() } + } } #[cfg(feature = "Foundation_NSMutableDictionary")] -impl NSMutableDictionary { +impl NSMutableDictionary { /// Inserts a key-value pair into the dictionary. /// /// If the dictionary did not have this key present, None is returned. @@ -201,69 +320,93 @@ impl NSMutableDictionary { /// # Examples /// /// ``` - /// use icrate::Foundation::{NSMutableDictionary, NSObject, NSString}; + /// use icrate::Foundation::{NSMutableDictionary, NSObject, ns_string}; /// /// let mut dict = NSMutableDictionary::new(); - /// dict.insert(NSString::from_str("one"), NSObject::new()); + /// dict.insert_id(ns_string!("one"), NSObject::new()); /// ``` #[doc(alias = "setObject:forKey:")] - pub fn insert(&mut self, key: Id, value: Id) -> Option> { + pub fn insert_id(&mut self, key: &K, value: Id) -> Option> + where + K: NSCopying + CounterpartOrSelf, + { // SAFETY: We remove the object from the dictionary below let old_obj = self - .get(&key) + .get(key) .map(|old_obj| unsafe { util::mutable_collection_retain_removed_id(old_obj) }); - // SAFETY: It is always safe to transmute an `Id` to `AnyObject`. - let key: Id = unsafe { Id::cast(key) }; - // SAFETY: We have ownership over both the key and the value. - unsafe { self.setObject_forKey(&value, &key) }; + // SAFETY: It is always safe to transmute an `&T` where `T: Message` + // to `&AnyObject`. + let key: NonNull = NonNull::from(key); + let key: NonNull = key.cast(); + let key: &AnyObject = unsafe { key.as_ref() }; + // SAFETY: The key is NSCopying (see `NSDictionary::from_vec`), and we + // have ownership over the value. + unsafe { self.setObject_forKey(&value, key) }; old_obj } - /// Removes a key from the dictionary, returning the value at the key - /// if the key was previously in the dictionary. + /// Inserts a key-value pair into the dictionary. + /// + /// If the dictionary did not have this key present, None is returned. + /// If the dictionary did have this key present, the value is updated, + /// and the old value is returned. /// /// # Examples /// /// ``` - /// use icrate::Foundation::{ns_string, NSMutableDictionary, NSObject, NSString}; + /// use icrate::Foundation::{ns_string, NSCopying, NSMutableDictionary}; /// /// let mut dict = NSMutableDictionary::new(); - /// dict.insert(NSString::from_str("one"), NSObject::new()); - /// dict.remove(ns_string!("one")); - /// assert!(dict.is_empty()); + /// dict.insert_id(ns_string!("key"), ns_string!("value").copy()); /// ``` - #[doc(alias = "removeObjectForKey:")] - pub fn remove(&mut self, key: &K) -> Option> { + #[doc(alias = "setObject:forKey:")] + pub fn insert(&mut self, key: &K, value: &V) -> Option> + where + K: NSCopying + CounterpartOrSelf, + V: IsRetainable, + { // SAFETY: We remove the object from the dictionary below let old_obj = self .get(key) .map(|old_obj| unsafe { util::mutable_collection_retain_removed_id(old_obj) }); - self.removeObjectForKey(key); + + // SAFETY: It is always safe to transmute an `&T` where `T: Message` + // to `&AnyObject`. + let key: NonNull = NonNull::from(key); + let key: NonNull = key.cast(); + let key: &AnyObject = unsafe { key.as_ref() }; + // SAFETY: The key is NSCopying (see `NSDictionary::from_vec`), and + // the value is `IsRetainable` (and hence safe for the collection to + // retain). + unsafe { self.setObject_forKey(value, key) }; old_obj } - /// Returns an [`NSArray`] containing the dictionary's values, - /// consuming the dictionary. - /// - /// [`NSArray`]: crate::Foundation::NSArray - /// + /// Removes a key from the dictionary, returning the value at the key + /// if the key was previously in the dictionary. /// /// # Examples /// /// ``` - /// use icrate::Foundation::{NSMutableDictionary, NSObject, NSString}; + /// use icrate::Foundation::{ns_string, NSMutableDictionary, NSObject}; /// /// let mut dict = NSMutableDictionary::new(); - /// dict.insert(NSString::from_str("one"), NSObject::new()); - /// let array = NSMutableDictionary::into_values_array(dict); - /// println!("{:?}", array); + /// dict.insert_id(ns_string!("one"), NSObject::new()); + /// dict.remove(ns_string!("one")); + /// assert!(dict.is_empty()); /// ``` - #[cfg(feature = "Foundation_NSArray")] - pub fn into_values_array(this: Id) -> Id> { - // SAFETY: We've consumed the dictionary, so getting an array from - // it is safe. - unsafe { this.allValues() } + #[doc(alias = "removeObjectForKey:")] + pub fn remove(&mut self, key: &K) -> Option> + where + K: CounterpartOrSelf, + { + // SAFETY: We remove the object from the dictionary below + let old_obj = self + .get(key) + .map(|old_obj| unsafe { util::mutable_collection_retain_removed_id(old_obj) }); + self.removeObjectForKey(key); + old_obj } } @@ -420,7 +563,7 @@ mod iter_helpers { #[cfg(feature = "Foundation_NSEnumerator")] pub use self::iter_helpers::*; -impl<'a, K: Message, V: Message> Index<&'a K> for NSDictionary { +impl<'a, K: Message + Eq + Hash, V: Message> Index<&'a K> for NSDictionary { type Output = V; fn index<'s>(&'s self, index: &'a K) -> &'s V { @@ -429,7 +572,7 @@ impl<'a, K: Message, V: Message> Index<&'a K> for NSDictionary { } #[cfg(feature = "Foundation_NSMutableDictionary")] -impl<'a, K: Message, V: Message> Index<&'a K> for NSMutableDictionary { +impl<'a, K: Message + Eq + Hash, V: Message> Index<&'a K> for NSMutableDictionary { type Output = V; fn index<'s>(&'s self, index: &'a K) -> &'s V { @@ -437,14 +580,14 @@ impl<'a, K: Message, V: Message> Index<&'a K> for NSMutableDictionary { } } -impl<'a, K: Message, V: IsMutable> IndexMut<&'a K> for NSDictionary { +impl<'a, K: Message + Eq + Hash, V: IsMutable> IndexMut<&'a K> for NSDictionary { fn index_mut<'s>(&'s mut self, index: &'a K) -> &'s mut V { self.get_mut(index).unwrap() } } #[cfg(feature = "Foundation_NSMutableDictionary")] -impl<'a, K: Message, V: IsMutable> IndexMut<&'a K> for NSMutableDictionary { +impl<'a, K: Message + Eq + Hash, V: IsMutable> IndexMut<&'a K> for NSMutableDictionary { fn index_mut<'s>(&'s mut self, index: &'a K) -> &'s mut V { self.get_mut(index).unwrap() } diff --git a/crates/icrate/src/additions/Foundation/mod.rs b/crates/icrate/src/additions/Foundation/mod.rs index 76c06be22..f87cf1e7c 100644 --- a/crates/icrate/src/additions/Foundation/mod.rs +++ b/crates/icrate/src/additions/Foundation/mod.rs @@ -49,7 +49,3 @@ pub use objc2::ffi::{NSInteger, NSUInteger}; #[cfg(feature = "Foundation_NSProxy")] pub use objc2::runtime::__NSProxy as NSProxy; pub use objc2::runtime::{NSObject, NSObjectProtocol, NSZone}; -#[doc(inline)] -pub use objc2::runtime::{ - __Copyhelper as Copyhelper, __NSCopying as NSCopying, __NSMutableCopying as NSMutableCopying, -}; diff --git a/crates/icrate/src/additions/Foundation/number.rs b/crates/icrate/src/additions/Foundation/number.rs index 8a997e5ea..decc59fff 100644 --- a/crates/icrate/src/additions/Foundation/number.rs +++ b/crates/icrate/src/additions/Foundation/number.rs @@ -217,13 +217,33 @@ impl PartialEq for NSNumber { } } +/// Beware: This uses the Objective-C method "isEqualToNumber:", which has +/// different floating point NaN semantics than Rust! +// +// This is valid since the following pass (i.e. Objective-C says that two NaNs +// are equal): +// ``` +// let nan = NSNumber::from_f32(f32::NAN); +// assert_eq!(nan, nan); +// ``` +impl Eq for NSNumber {} + /// Beware: This uses the Objective-C method "compare:", which has different /// floating point NaN semantics than Rust! impl PartialOrd for NSNumber { #[doc(alias = "compare:")] fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +/// Beware: This uses the Objective-C method "compare:", which has different +/// floating point NaN semantics than Rust! +impl Ord for NSNumber { + #[doc(alias = "compare:")] + fn cmp(&self, other: &Self) -> Ordering { // Use Objective-C semantics for comparison - Some(self.compare(other).into()) + self.compare(other).into() } } diff --git a/crates/icrate/src/additions/Foundation/set.rs b/crates/icrate/src/additions/Foundation/set.rs index 0f3c9f7db..0d338b8fb 100644 --- a/crates/icrate/src/additions/Foundation/set.rs +++ b/crates/icrate/src/additions/Foundation/set.rs @@ -2,9 +2,10 @@ #![cfg(feature = "Foundation_NSSet")] use alloc::vec::Vec; use core::fmt; +use core::hash::Hash; use core::panic::{RefUnwindSafe, UnwindSafe}; -use objc2::mutability::IsRetainable; +use objc2::mutability::{HasStableHash, IsRetainable}; use objc2::rc::IdFromIterator; use super::iter; @@ -15,6 +16,38 @@ use crate::Foundation::NSMutableSet; use crate::Foundation::{self, NSSet}; impl NSSet { + /// Returns the number of elements in the set. + /// + /// # Examples + /// + /// ``` + /// use icrate::Foundation::{NSSet, NSString}; + /// + /// let strs = ["one", "two", "three"].map(NSString::from_str); + /// let set = NSSet::from_id_slice(&strs); + /// assert_eq!(set.len(), 3); + /// ``` + #[doc(alias = "count")] + pub fn len(&self) -> usize { + self.count() + } + + /// Returns `true` if the set contains no elements. + /// + /// # Examples + /// + /// ``` + /// use icrate::Foundation::{NSSet, NSString}; + /// + /// let set = NSSet::::new(); + /// assert!(set.is_empty()); + /// ``` + pub fn is_empty(&self) -> bool { + self.len() == 0 + } +} + +impl NSSet { /// Creates an [`NSSet`] from a vector. /// /// # Examples @@ -25,7 +58,10 @@ impl NSSet { /// let strs = ["one", "two", "three"].map(NSString::from_str).to_vec(); /// let set = NSSet::from_vec(strs); /// ``` - pub fn from_vec(mut vec: Vec>) -> Id { + pub fn from_vec(mut vec: Vec>) -> Id + where + T: HasStableHash, + { let len = vec.len(); let ptr = util::id_ptr_cast(vec.as_mut_ptr()); // SAFETY: Same as `NSArray::from_vec`. @@ -44,7 +80,7 @@ impl NSSet { /// ``` pub fn from_id_slice(slice: &[Id]) -> Id where - T: IsIdCloneable, + T: HasStableHash + IsIdCloneable, { let len = slice.len(); let ptr = util::id_ptr_cast_const(slice.as_ptr()); @@ -54,7 +90,7 @@ impl NSSet { pub fn from_slice(slice: &[&T]) -> Id where - T: IsRetainable, + T: HasStableHash + IsRetainable, { let len = slice.len(); let ptr = util::ref_ptr_cast_const(slice.as_ptr()); @@ -126,7 +162,7 @@ impl NSSet { } #[cfg(feature = "Foundation_NSMutableSet")] -impl NSMutableSet { +impl NSMutableSet { /// Creates an [`NSMutableSet`] from a vector. /// /// # Examples @@ -137,7 +173,10 @@ impl NSMutableSet { /// let strs = ["one", "two", "three"].map(NSString::from_str).to_vec(); /// let set = NSMutableSet::from_vec(strs); /// ``` - pub fn from_vec(mut vec: Vec>) -> Id { + pub fn from_vec(mut vec: Vec>) -> Id + where + T: HasStableHash, + { let len = vec.len(); let ptr = util::id_ptr_cast(vec.as_mut_ptr()); // SAFETY: Same as `NSArray::from_vec`. @@ -156,7 +195,7 @@ impl NSMutableSet { /// ``` pub fn from_id_slice(slice: &[Id]) -> Id where - T: IsIdCloneable, + T: HasStableHash + IsIdCloneable, { let len = slice.len(); let ptr = util::id_ptr_cast_const(slice.as_ptr()); @@ -166,7 +205,7 @@ impl NSMutableSet { pub fn from_slice(slice: &[&T]) -> Id where - T: IsRetainable, + T: HasStableHash + IsRetainable, { let len = slice.len(); let ptr = util::ref_ptr_cast_const(slice.as_ptr()); @@ -197,36 +236,6 @@ impl NSMutableSet { extern_methods!( unsafe impl NSSet { - /// Returns the number of elements in the set. - /// - /// # Examples - /// - /// ``` - /// use icrate::Foundation::{NSSet, NSString}; - /// - /// let strs = ["one", "two", "three"].map(NSString::from_str); - /// let set = NSSet::from_id_slice(&strs); - /// assert_eq!(set.len(), 3); - /// ``` - #[doc(alias = "count")] - pub fn len(&self) -> usize { - self.count() - } - - /// Returns `true` if the set contains no elements. - /// - /// # Examples - /// - /// ``` - /// use icrate::Foundation::{NSSet, NSString}; - /// - /// let set = NSSet::::new(); - /// assert!(set.is_empty()); - /// ``` - pub fn is_empty(&self) -> bool { - self.len() == 0 - } - /// Returns a reference to one of the objects in the set, or `None` if /// the set is empty. /// @@ -245,10 +254,7 @@ extern_methods!( pub fn get_any(&self) -> Option<&T>; } - // We're explicit about `T` being `PartialEq` for these methods because - // the set compares the input value(s) with elements in the set. For - // comparison: Rust's HashSet requires similar methods to be `Hash` + `Eq` - unsafe impl NSSet { + unsafe impl NSSet { /// Returns `true` if the set contains a value. /// /// # Examples @@ -292,7 +298,7 @@ extern_methods!( } // Note: No `get_mut` method exposed on sets, since their objects' - // hashes are supposed to be immutable. + // hashes are immutable. /// Returns `true` if the set is a subset of another, i.e., `other` /// contains at least all the values in `self`. @@ -353,8 +359,34 @@ extern_methods!( ); #[cfg(feature = "Foundation_NSMutableSet")] -impl NSMutableSet { - /// Adds a value to the set. Returns whether the value was +impl NSMutableSet { + /// Add a value to the set. Returns whether the value was + /// newly inserted. + /// + /// # Examples + /// + /// ``` + /// use icrate::Foundation::{NSNumber, NSMutableSet}; + /// + /// let mut set = NSMutableSet::new(); + /// + /// assert_eq!(set.insert(&*NSNumber::new_u32(42)), true); + /// assert_eq!(set.insert(&*NSNumber::new_u32(42)), false); + /// assert_eq!(set.len(), 1); + /// ``` + #[doc(alias = "addObject:")] + pub fn insert(&mut self, value: &T) -> bool + where + T: HasStableHash + IsRetainable, + { + let contains_value = self.contains(value); + // SAFETY: Because of the `T: IsRetainable` bound, it is safe for the + // set to retain the object here. + unsafe { self.addObject(value) }; + !contains_value + } + + /// Add an `Id` to the set. Returns whether the value was /// newly inserted. /// /// # Examples @@ -364,12 +396,15 @@ impl NSMutableSet { /// /// let mut set = NSMutableSet::new(); /// - /// assert_eq!(set.insert(NSString::from_str("one")), true); - /// assert_eq!(set.insert(NSString::from_str("one")), false); + /// assert_eq!(set.insert_id(NSString::from_str("one")), true); + /// assert_eq!(set.insert_id(NSString::from_str("one")), false); /// assert_eq!(set.len(), 1); /// ``` #[doc(alias = "addObject:")] - pub fn insert(&mut self, value: Id) -> bool { + pub fn insert_id(&mut self, value: Id) -> bool + where + T: HasStableHash, + { let contains_value = self.contains(&value); // SAFETY: We've consumed ownership of the object. unsafe { self.addObject(&value) }; @@ -386,18 +421,24 @@ impl NSMutableSet { /// /// let mut set = NSMutableSet::new(); /// - /// set.insert(NSString::from_str("one")); + /// set.insert_id(NSString::from_str("one")); /// assert_eq!(set.remove(ns_string!("one")), true); /// assert_eq!(set.remove(ns_string!("one")), false); /// ``` #[doc(alias = "removeObject:")] - pub fn remove(&mut self, value: &T) -> bool { + pub fn remove(&mut self, value: &T) -> bool + where + T: HasStableHash, + { let contains_value = self.contains(value); unsafe { self.removeObject(value) }; contains_value } } +// Iteration is not supposed to touch the elements, not even do comparisons. +// +// TODO: Verify that this is actually the case. impl NSSet { /// An iterator visiting all elements in arbitrary order. /// @@ -499,32 +540,31 @@ impl fmt::Debug for NSSet { } #[cfg(feature = "Foundation_NSMutableSet")] -impl Extend> for NSMutableSet { +impl Extend> for NSMutableSet { fn extend>>(&mut self, iter: I) { iter.into_iter().for_each(move |item| { - self.insert(item); + self.insert_id(item); }) } } #[cfg(feature = "Foundation_NSMutableSet")] -impl<'a, T: IsRetainable + PartialEq> Extend<&'a T> for NSMutableSet { +impl<'a, T: IsRetainable + Eq + Hash + HasStableHash> Extend<&'a T> for NSMutableSet { fn extend>(&mut self, iter: I) { - // SAFETY: Because of the `T: IsRetainable` bound, it is safe for the - // set to retain the object here. - iter.into_iter() - .for_each(move |item| unsafe { self.addObject(item) }) + iter.into_iter().for_each(move |item| { + self.insert(item); + }) } } -impl<'a, T: IsRetainable + 'a> IdFromIterator<&'a T> for NSSet { +impl<'a, T: IsRetainable + Eq + Hash + HasStableHash + 'a> IdFromIterator<&'a T> for NSSet { fn id_from_iter>(iter: I) -> Id { let vec = Vec::from_iter(iter); Self::from_slice(&vec) } } -impl IdFromIterator> for NSSet { +impl IdFromIterator> for NSSet { fn id_from_iter>>(iter: I) -> Id { let vec = Vec::from_iter(iter); Self::from_vec(vec) @@ -532,7 +572,9 @@ impl IdFromIterator> for NSSet { } #[cfg(feature = "Foundation_NSMutableSet")] -impl<'a, T: IsRetainable + 'a> IdFromIterator<&'a T> for NSMutableSet { +impl<'a, T: IsRetainable + Eq + Hash + HasStableHash + 'a> IdFromIterator<&'a T> + for NSMutableSet +{ fn id_from_iter>(iter: I) -> Id { let vec = Vec::from_iter(iter); Self::from_slice(&vec) @@ -540,7 +582,7 @@ impl<'a, T: IsRetainable + 'a> IdFromIterator<&'a T> for NSMutableSet { } #[cfg(feature = "Foundation_NSMutableSet")] -impl IdFromIterator> for NSMutableSet { +impl IdFromIterator> for NSMutableSet { fn id_from_iter>>(iter: I) -> Id { let vec = Vec::from_iter(iter); Self::from_vec(vec) diff --git a/crates/icrate/src/fixes/Foundation/copying.rs b/crates/icrate/src/fixes/Foundation/copying.rs new file mode 100644 index 000000000..5117ae079 --- /dev/null +++ b/crates/icrate/src/fixes/Foundation/copying.rs @@ -0,0 +1,92 @@ +use objc2::mutability::CounterpartOrSelf; +use objc2::rc::Id; +use objc2::runtime::NSZone; +use objc2::{extern_protocol, ProtocolType}; + +extern_protocol!( + /// A protocol to provide functional copies of objects. + /// + /// This is similar to Rust's [`Clone`] trait, along with sharing a few + /// similarities to the [`std::borrow::ToOwned`] trait with regards to the + /// output type. + /// + /// See [Apple's documentation][apple-doc] for details. + /// + /// [apple-doc]: https://developer.apple.com/documentation/foundation/nscopying + pub unsafe trait NSCopying { + /// Returns a new instance that's a copy of the receiver. + /// + /// The output type is the immutable counterpart of the object, which is + /// usually `Self`, but e.g. `NSMutableString` returns `NSString`. + #[method_id(copy)] + #[optional] + fn copy(&self) -> Id + where + Self: Sized, + Self: CounterpartOrSelf; + + /// Returns a new instance that's a copy of the receiver. + /// + /// This is only used when implementing `NSCopying`, use + /// [`copy`][NSCopying::copy] instead. + /// + /// + /// # Safety + /// + /// The zone pointer must be valid or NULL. + #[method_id(copyWithZone:)] + unsafe fn copyWithZone(&self, zone: *mut NSZone) -> Id + where + Self: Sized, + Self: CounterpartOrSelf; + } + + unsafe impl ProtocolType for dyn NSCopying { + const NAME: &'static str = "NSCopying"; + } +); + +// FIXME: Remove this hack which makes NSMutableDictionary tests work +unsafe impl NSCopying for objc2::rc::__RcTestObject {} + +extern_protocol!( + /// A protocol to provide mutable copies of objects. + /// + /// Only classes that have an “immutable vs. mutable” distinction should adopt + /// this protocol. + /// + /// See [Apple's documentation][apple-doc] for details. + /// + /// [apple-doc]: https://developer.apple.com/documentation/foundation/nsmutablecopying + pub unsafe trait NSMutableCopying { + /// Returns a new instance that's a mutable copy of the receiver. + /// + /// The output type is the mutable counterpart of the object. E.g. both + /// `NSString` and `NSMutableString` return `NSMutableString`. + #[method_id(mutableCopy)] + #[optional] + fn mutableCopy(&self) -> Id + where + Self: Sized, + Self: CounterpartOrSelf; + + /// Returns a new instance that's a mutable copy of the receiver. + /// + /// This is only used when implementing `NSMutableCopying`, use + /// [`mutableCopy`][NSMutableCopying::mutableCopy] instead. + /// + /// + /// # Safety + /// + /// The zone pointer must be valid or NULL. + #[method_id(mutableCopyWithZone:)] + unsafe fn mutableCopyWithZone(&self, zone: *mut NSZone) -> Id + where + Self: Sized, + Self: CounterpartOrSelf; + } + + unsafe impl ProtocolType for dyn NSMutableCopying { + const NAME: &'static str = "NSMutableCopying"; + } +); diff --git a/crates/icrate/src/fixes/Foundation/mod.rs b/crates/icrate/src/fixes/Foundation/mod.rs index b6945a2ca..7849f379d 100644 --- a/crates/icrate/src/fixes/Foundation/mod.rs +++ b/crates/icrate/src/fixes/Foundation/mod.rs @@ -4,6 +4,7 @@ mod __NSDecimal; #[path = "NSNotFound.rs"] mod __NSNotFound; mod copy; +mod copying; mod debug; mod enumerator; mod exception; @@ -13,6 +14,7 @@ mod ns_consumed; pub use self::__NSDecimal::NSDecimal; pub use self::__NSNotFound::NSNotFound; +pub use self::copying::{NSCopying, NSMutableCopying}; pub use self::enumerator::NSFastEnumerationState; pub use self::generics::*; #[cfg(feature = "Foundation_NSMapTable")] diff --git a/crates/icrate/src/generated b/crates/icrate/src/generated index 560cb6a40..316a9c6f9 160000 --- a/crates/icrate/src/generated +++ b/crates/icrate/src/generated @@ -1 +1 @@ -Subproject commit 560cb6a40f078eed5a6e1af49fdd5299b1ad0ba1 +Subproject commit 316a9c6f9640f34f859c0d9bf0da8973f03a3a00 diff --git a/crates/icrate/tests/attributed_string.rs b/crates/icrate/tests/attributed_string.rs index 6cc0acb13..c41a0d745 100644 --- a/crates/icrate/tests/attributed_string.rs +++ b/crates/icrate/tests/attributed_string.rs @@ -60,10 +60,7 @@ fn test_debug() { let s = unsafe { NSAttributedString::new_with_attributes( &NSString::from_str("abc"), - &Foundation::NSDictionary::from_keys_and_objects( - &[&*NSString::from_str("test")], - vec![obj], - ), + &Foundation::NSDictionary::from_vec(&[&*NSString::from_str("test")], vec![obj]), ) }; let expected = if cfg!(feature = "gnustep-1-7") { diff --git a/crates/icrate/tests/dictionary.rs b/crates/icrate/tests/dictionary.rs index e390b13d3..e03a234f0 100644 --- a/crates/icrate/tests/dictionary.rs +++ b/crates/icrate/tests/dictionary.rs @@ -7,7 +7,7 @@ use icrate::Foundation::{NSDictionary, NSObject, NSString}; fn sample_dict(key: &str) -> Id> { let string = NSString::from_str(key); let obj = NSObject::new(); - NSDictionary::from_keys_and_objects(&[&*string], vec![obj]) + NSDictionary::from_vec(&[&*string], vec![obj]) } #[test] @@ -87,7 +87,7 @@ fn test_arrays() { assert_eq!(keys[0].as_str(pool), "abcd"); }); - // let objs = NSDictionary::into_values_array(dict); + // let objs = dict.to_array(); // assert_eq!(objs.len(), 1); } @@ -95,6 +95,19 @@ fn test_arrays() { fn test_debug() { let key = NSString::from_str("a"); let val = NSString::from_str("b"); - let dict = NSDictionary::from_keys_and_objects(&[&*key], vec![val]); + let dict = NSDictionary::from_id_slice(&[&*key], &[val]); assert_eq!(format!("{dict:?}"), r#"{"a": "b"}"#); } + +#[test] +fn new_different_lengths() { + let dict = NSDictionary::from_id_slice( + &[ + &*NSString::from_str("a"), + &*NSString::from_str("b"), + &*NSString::from_str("c"), + ], + &[NSObject::new(), NSObject::new()], + ); + assert_eq!(dict.len(), 2); +} diff --git a/crates/icrate/tests/mutable_dictionary.rs b/crates/icrate/tests/mutable_dictionary.rs index 83ed4ba67..61db87512 100644 --- a/crates/icrate/tests/mutable_dictionary.rs +++ b/crates/icrate/tests/mutable_dictionary.rs @@ -6,19 +6,19 @@ use objc2::rc::{Id, __RcTestObject, __ThreadTestData}; use icrate::Foundation::{NSMutableDictionary, NSNumber, NSObject}; fn sample_dict() -> Id> { - NSMutableDictionary::from_keys_and_objects( + NSMutableDictionary::from_id_slice( &[ &*NSNumber::new_i32(1), &*NSNumber::new_i32(2), &*NSNumber::new_i32(3), ], - vec![NSObject::new(), NSObject::new(), NSObject::new()], + &[NSObject::new(), NSObject::new(), NSObject::new()], ) } #[cfg(feature = "Foundation_NSMutableString")] fn sample_dict_mut() -> Id> { - NSMutableDictionary::from_keys_and_objects( + NSMutableDictionary::from_vec( &[ &*NSNumber::new_i32(1), &*NSNumber::new_i32(2), @@ -32,6 +32,18 @@ fn sample_dict_mut() -> Id> = + NSMutableDictionary::from_id_slice( + &[&*icrate::Foundation::NSMutableString::from_str("a")], + &[Id::into_super( + icrate::Foundation::NSMutableString::from_str("b"), + )], + ); +} + #[test] fn test_new() { let dict = NSMutableDictionary::::new(); @@ -58,29 +70,33 @@ fn test_values_mut() { #[test] fn test_insert() { - let mut dict = NSMutableDictionary::new(); - assert!(dict.insert(NSNumber::new_i32(1), NSObject::new()).is_none()); - assert!(dict.insert(NSNumber::new_i32(2), NSObject::new()).is_none()); - assert!(dict.insert(NSNumber::new_i32(3), NSObject::new()).is_none()); - assert!(dict.insert(NSNumber::new_i32(1), NSObject::new()).is_some()); + let mut dict = >::new(); + assert!(dict + .insert_id(&NSNumber::new_i32(1), NSObject::new()) + .is_none()); + assert!(dict + .insert_id(&NSNumber::new_i32(2), NSObject::new()) + .is_none()); + assert!(dict + .insert_id(&NSNumber::new_i32(3), NSObject::new()) + .is_none()); + assert!(dict + .insert_id(&NSNumber::new_i32(1), NSObject::new()) + .is_some()); assert_eq!(dict.len(), 3); } #[test] fn test_insert_key_copies() { - let mut dict = NSMutableDictionary::new(); + let mut dict = >::new(); let key1 = __RcTestObject::new(); let mut expected = __ThreadTestData::current(); - let _ = dict.insert(key1, NSNumber::new_i32(1)); + let _ = dict.insert_id(&key1, NSNumber::new_i32(1)); // Create copy expected.copy += 1; expected.alloc += 1; expected.init += 1; - - // Release passed-in key - expected.release += 1; - expected.dealloc += 1; expected.assert_current(); dict.removeAllObjects(); @@ -90,14 +106,26 @@ fn test_insert_key_copies() { expected.assert_current(); } +#[test] +fn test_get_key_copies() { + let mut dict = >::new(); + let key1 = __RcTestObject::new(); + let _ = dict.insert_id(&key1, NSNumber::new_i32(1)); + let expected = __ThreadTestData::current(); + + let _ = dict.get(&key1); + // No change, getting doesn't do anything to the key! + expected.assert_current(); +} + #[test] fn test_insert_value_retain_release() { - let mut dict = NSMutableDictionary::new(); - dict.insert(NSNumber::new_i32(1), __RcTestObject::new()); + let mut dict = >::new(); + dict.insert_id(&NSNumber::new_i32(1), __RcTestObject::new()); let to_insert = __RcTestObject::new(); let mut expected = __ThreadTestData::current(); - let old = dict.insert(NSNumber::new_i32(1), to_insert); + let old = dict.insert(&NSNumber::new_i32(1), &to_insert); // Grab old value expected.retain += 1; @@ -105,9 +133,6 @@ fn test_insert_value_retain_release() { expected.retain += 1; expected.release += 1; - // Release passed-in `Id` - expected.release += 1; - expected.assert_current(); drop(old); @@ -138,9 +163,9 @@ fn test_clear() { #[test] fn test_remove_clear_release_dealloc() { - let mut dict = NSMutableDictionary::new(); + let mut dict = >::new(); for i in 0..4 { - dict.insert(NSNumber::new_i32(i), __RcTestObject::new()); + dict.insert_id(&NSNumber::new_i32(i), __RcTestObject::new()); } let mut expected = __ThreadTestData::current(); @@ -165,9 +190,9 @@ fn test_remove_clear_release_dealloc() { #[test] #[cfg(feature = "Foundation_NSArray")] -fn test_into_values_array() { +fn test_to_array() { let dict = sample_dict(); - let array = NSMutableDictionary::into_values_array(dict); + let array = dict.to_array(); assert_eq!(array.len(), 3); } diff --git a/crates/icrate/tests/mutable_set.rs b/crates/icrate/tests/mutable_set.rs index ba47c3310..da18d0266 100644 --- a/crates/icrate/tests/mutable_set.rs +++ b/crates/icrate/tests/mutable_set.rs @@ -10,9 +10,9 @@ fn test_insert() { let mut set = NSMutableSet::new(); assert!(set.is_empty()); - assert!(set.insert(NSString::from_str("one"))); - assert!(!set.insert(NSString::from_str("one"))); - assert!(set.insert(NSString::from_str("two"))); + assert!(set.insert_id(NSString::from_str("one"))); + assert!(!set.insert_id(NSString::from_str("one"))); + assert!(set.insert_id(NSString::from_str("two"))); } #[test] @@ -69,7 +69,7 @@ fn test_mutable_copy() { let set1 = NSSet::from_id_slice(&["one", "two", "three"].map(NSString::from_str)); let mut set2 = set1.mutableCopy(); - set2.insert(NSString::from_str("four")); + set2.insert_id(NSString::from_str("four")); assert!(set1.is_subset(&set2)); assert_ne!(set1.mutableCopy(), set2); @@ -77,34 +77,28 @@ fn test_mutable_copy() { #[test] fn test_insert_retain_release() { - let mut set = NSMutableSet::new(); + let mut set = >::new(); let obj1 = __RcTestObject::new(); let obj2 = __RcTestObject::new(); let obj2_copy = obj2.retain(); let mut expected = __ThreadTestData::current(); - set.insert(obj1); + set.insert(&obj1); // Retain to store in set expected.retain += 1; - // Release passed in object - expected.release += 1; expected.assert_current(); assert_eq!(set.len(), 1); assert_eq!(set.get_any(), set.get_any()); - set.insert(obj2); + set.insert(&obj2); // Retain to store in set expected.retain += 1; - // Release passed in object - expected.release += 1; expected.assert_current(); assert_eq!(set.len(), 2); - set.insert(obj2_copy); + set.insert(&obj2_copy); // No retain, since the object is already in the set expected.retain += 0; - // Release passed in object - expected.release += 1; expected.assert_current(); assert_eq!(set.len(), 2); } @@ -113,7 +107,7 @@ fn test_insert_retain_release() { fn test_clear_release_dealloc() { let mut set = NSMutableSet::new(); for _ in 0..4 { - set.insert(__RcTestObject::new()); + set.insert_id(__RcTestObject::new()); } let mut expected = __ThreadTestData::current(); diff --git a/crates/icrate/tests/mutable_string.rs b/crates/icrate/tests/mutable_string.rs index 4e00ba9e2..9ea2d52ae 100644 --- a/crates/icrate/tests/mutable_string.rs +++ b/crates/icrate/tests/mutable_string.rs @@ -1,7 +1,13 @@ #![cfg(feature = "Foundation_NSMutableString")] +use core::any::TypeId; +use std::ptr; + +use objc2::mutability::CounterpartOrSelf; use objc2::rc::Id; -use icrate::Foundation::{self, NSMutableString, NSObjectProtocol, NSString}; +use icrate::Foundation::{ + self, NSCopying, NSMutableCopying, NSMutableString, NSObjectProtocol, NSString, +}; #[test] fn display_debug() { @@ -53,3 +59,36 @@ fn test_copy() { assert_ne!(Id::as_ptr(&s1), Id::as_ptr(&s3)); assert!(s3.is_kind_of::()); } + +#[test] +fn counterpart() { + assert_eq!( + TypeId::of::<::Immutable>(), + TypeId::of::(), + ); + assert_eq!( + TypeId::of::<::Mutable>(), + TypeId::of::(), + ); + + assert_eq!( + TypeId::of::<::Immutable>(), + TypeId::of::(), + ); + assert_eq!( + TypeId::of::<::Mutable>(), + TypeId::of::(), + ); +} + +#[test] +fn test_copy_with_zone() { + let s1 = NSString::from_str("abc"); + let s2 = unsafe { s1.copyWithZone(ptr::null_mut()) }; + assert_eq!(Id::as_ptr(&s1), Id::as_ptr(&s2)); + assert!(s2.is_kind_of::()); + + let s3 = unsafe { s1.mutableCopyWithZone(ptr::null_mut()) }; + assert_ne!(Id::as_ptr(&s1).cast::(), Id::as_ptr(&s3)); + assert!(s3.is_kind_of::()); +} diff --git a/crates/icrate/tests/number.rs b/crates/icrate/tests/number.rs index 05ed98710..c1d8dc247 100644 --- a/crates/icrate/tests/number.rs +++ b/crates/icrate/tests/number.rs @@ -88,6 +88,28 @@ fn equality() { assert_ne!(val1, val4); } +#[test] +#[cfg_attr(feature = "gnustep-1-7", ignore = "GNUStep handles NaNs differently")] +fn nan_equality() { + let nan = NSNumber::new_f32(f32::NAN); + let nan2 = NSNumber::new_f32(f32::NAN); + let neg_nan = NSNumber::new_f32(-f32::NAN); + assert_eq!(nan, nan); + assert_eq!(nan, nan2); + assert_eq!(neg_nan, neg_nan); + assert_eq!(nan, neg_nan); +} + +// Ensure that comparisons are made on the number, and not the bits of the floating point value +#[test] +fn float_int_equality() { + let val1 = NSNumber::new_f32(1.0); + let val2 = NSNumber::new_u32(1); + let val3 = NSNumber::new_u32(1.0f32.to_bits()); + assert_eq!(val1, val2); + assert_ne!(val1, val3); +} + #[test] #[cfg(feature = "Foundation_NSString")] fn display_debug() { diff --git a/crates/icrate/tests/set.rs b/crates/icrate/tests/set.rs index 5979bf77e..fe4a5fbd4 100644 --- a/crates/icrate/tests/set.rs +++ b/crates/icrate/tests/set.rs @@ -4,7 +4,7 @@ use objc2::rc::{__RcTestObject, __ThreadTestData}; -use icrate::Foundation::{self, ns_string, NSNumber, NSObject, NSSet, NSString}; +use icrate::Foundation::{self, ns_string, NSNumber, NSSet, NSString}; #[test] fn test_new() { @@ -48,7 +48,11 @@ fn test_len() { let set = NSSet::from_id_slice(&["one", "two", "two"].map(NSString::from_str)); assert_eq!(set.len(), 2); - let set = NSSet::from_vec(vec![NSObject::new(), NSObject::new(), NSObject::new()]); + let set = NSSet::from_vec(vec![ + NSNumber::new_i32(1), + NSNumber::new_i32(2), + NSNumber::new_i32(3), + ]); assert_eq!(set.len(), 3); } @@ -290,3 +294,16 @@ fn test_iter_minimal_retains() { expected.dealloc += 1; expected.assert_current(); } + +/// This currently works, but we should figure out a way to disallow it! +#[test] +#[cfg(all(feature = "Foundation_NSArray", feature = "Foundation_NSConnection"))] +#[allow(deprecated)] +fn invalid_generic() { + let something_interior_mutable = unsafe { Foundation::NSConnection::defaultConnection() }; + let set = NSSet::from_id_slice(&[Foundation::NSArray::from_id_slice(&[ + something_interior_mutable, + ])]); + let _ = set.get_any().unwrap().get(0).unwrap(); + // something_interior_mutable.setAbc(...) +} diff --git a/crates/objc2/CHANGELOG.md b/crates/objc2/CHANGELOG.md index 085d76cd0..c458ad14e 100644 --- a/crates/objc2/CHANGELOG.md +++ b/crates/objc2/CHANGELOG.md @@ -7,7 +7,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## Unreleased - YYYY-MM-DD ### Added -* Added `mutability::IsMainThreadOnly`. +* Added the following traits to the `mutability` module (see the documentation + for motivation and usage info): + - `HasStableHash`. + - `IsMainThreadOnly`. + - `CounterpartOrSelf`. * Added new `encode` traits `EncodeReturn`, `EncodeArgument` and `EncodeArguments`. diff --git a/crates/objc2/src/declare/mod.rs b/crates/objc2/src/declare/mod.rs index 14bca38a4..6f1cde4c5 100644 --- a/crates/objc2/src/declare/mod.rs +++ b/crates/objc2/src/declare/mod.rs @@ -769,8 +769,8 @@ mod tests { use super::*; use crate::mutability::Immutable; use crate::rc::Id; - use crate::runtime::{NSObject, NSObjectProtocol, NSZone, __NSCopying as NSCopying}; - use crate::{declare_class, extern_methods, msg_send, test_utils, ClassType, ProtocolType}; + use crate::runtime::{NSObject, NSObjectProtocol}; + use crate::{declare_class, extern_methods, msg_send, test_utils, ClassType}; #[test] fn test_alignment() { @@ -962,159 +962,6 @@ mod tests { assert_eq!(result, 7); } - #[test] - #[should_panic = "could not create new class TestDeclareClassDuplicate. Perhaps a class with that name already exists?"] - fn test_declare_class_duplicate() { - declare_class!( - struct Custom1; - - unsafe impl ClassType for Custom1 { - type Super = NSObject; - type Mutability = Immutable; - const NAME: &'static str = "TestDeclareClassDuplicate"; - } - ); - - declare_class!( - struct Custom2; - - unsafe impl ClassType for Custom2 { - type Super = NSObject; - type Mutability = Immutable; - const NAME: &'static str = "TestDeclareClassDuplicate"; - } - ); - - let _cls = Custom1::class(); - // Should panic - let _cls = Custom2::class(); - } - - #[test] - fn test_declare_class_protocol() { - declare_class!( - struct Custom; - - unsafe impl ClassType for Custom { - type Super = NSObject; - type Mutability = Immutable; - const NAME: &'static str = "TestDeclareClassProtocolNotFound"; - } - - unsafe impl NSCopying for Custom { - #[method_id(copyWithZone:)] - fn copy_with_zone(&self, _zone: *const NSZone) -> Id { - unimplemented!() - } - } - ); - - let cls = Custom::class(); - assert!(cls.conforms_to(::protocol().unwrap())); - } - - #[test] - #[cfg_attr( - debug_assertions, - should_panic = "declared invalid method -[TestDeclareClassInvalidMethod description]: expected return to have type code '@', but found 'v'" - )] - fn test_declare_class_invalid_method() { - declare_class!( - struct Custom; - - unsafe impl ClassType for Custom { - type Super = NSObject; - type Mutability = Immutable; - const NAME: &'static str = "TestDeclareClassInvalidMethod"; - } - - unsafe impl Custom { - // Override `description` with a bad return type - #[method(description)] - fn description(&self) {} - } - ); - - let _cls = Custom::class(); - } - - #[test] - #[cfg_attr( - all(debug_assertions, feature = "verify"), - should_panic = "must implement required protocol method -[NSCopying copyWithZone:]" - )] - fn test_declare_class_missing_protocol_method() { - declare_class!( - struct Custom; - - unsafe impl ClassType for Custom { - type Super = NSObject; - type Mutability = Immutable; - const NAME: &'static str = "TestDeclareClassMissingProtocolMethod"; - } - - unsafe impl NSCopying for Custom { - // Missing required method - } - ); - - let _cls = Custom::class(); - } - - #[test] - // #[cfg_attr(all(debug_assertions, feature = "verify"), should_panic = "...")] - fn test_declare_class_invalid_protocol_method() { - declare_class!( - struct Custom; - - unsafe impl ClassType for Custom { - type Super = NSObject; - type Mutability = Immutable; - const NAME: &'static str = "TestDeclareClassInvalidProtocolMethod"; - } - - unsafe impl NSCopying for Custom { - // Override with a bad return type - #[method(copyWithZone:)] - fn copy_with_zone(&self, _zone: *const NSZone) -> u8 { - 42 - } - } - ); - - let _cls = Custom::class(); - } - - #[test] - #[cfg_attr( - all(debug_assertions, feature = "verify"), - should_panic = "failed overriding protocol method -[NSCopying someOtherMethod]: method not found" - )] - fn test_declare_class_extra_protocol_method() { - declare_class!( - struct Custom; - - unsafe impl ClassType for Custom { - type Super = NSObject; - type Mutability = Immutable; - const NAME: &'static str = "TestDeclareClassExtraProtocolMethod"; - } - - unsafe impl NSCopying for Custom { - #[method_id(copyWithZone:)] - fn copy_with_zone(&self, _zone: *const NSZone) -> Id { - unimplemented!() - } - - // This doesn't exist on the protocol - #[method(someOtherMethod)] - fn some_other_method(&self) {} - } - ); - - let _cls = Custom::class(); - } - // Proof-of-concept how we could make declare_class! accept generic types. #[test] fn test_generic() { diff --git a/crates/objc2/src/macros/declare_class.rs b/crates/objc2/src/macros/declare_class.rs index 9a05c3154..126dd94e6 100644 --- a/crates/objc2/src/macros/declare_class.rs +++ b/crates/objc2/src/macros/declare_class.rs @@ -186,8 +186,8 @@ /// ``` /// use std::os::raw::c_int; /// -/// # use objc2::runtime::{__NSCopying as NSCopying, NSObject, NSObjectProtocol, NSZone}; -/// # #[cfg(available_elsewhere)] +/// # use objc2::runtime::{NSObject, NSObjectProtocol, NSZone}; +/// # #[cfg(available_in_icrate)] /// use icrate::Foundation::{NSCopying, NSObject, NSObjectProtocol, NSZone}; /// use objc2::declare::{Ivar, IvarDrop, IvarEncode}; /// use objc2::rc::Id; @@ -250,11 +250,19 @@ /// fn __my_class_method() -> bool { /// true /// } +/// # +/// # #[method_id(copyWithZone:)] +/// # fn copyWithZone(&self, _zone: *const NSZone) -> Id { +/// # let mut obj = Self::new(*self.foo); +/// # *obj.bar = *self.bar; +/// # obj +/// # } /// } /// +/// # #[cfg(available_in_icrate)] /// unsafe impl NSCopying for MyCustomObject { /// #[method_id(copyWithZone:)] -/// fn copy_with_zone(&self, _zone: *const NSZone) -> Id { +/// fn copyWithZone(&self, _zone: *const NSZone) -> Id { /// let mut obj = Self::new(*self.foo); /// *obj.bar = *self.bar; /// obj @@ -293,9 +301,9 @@ /// assert_eq!(*obj.bar, 42); /// assert!(obj.object.is_kind_of::()); /// -/// let obj: Id = unsafe { -/// msg_send_id![&obj, copy] -/// }; // Or obj.copy() with `icrate` +/// # let obj: Id = unsafe { msg_send_id![&obj, copy] }; +/// # #[cfg(available_in_icrate)] +/// let obj = obj.copy(); /// /// assert_eq!(obj.get_foo(), 3); /// assert!(obj.get_object().is_kind_of::()); diff --git a/crates/objc2/src/macros/extern_class.rs b/crates/objc2/src/macros/extern_class.rs index 51f14023c..90a95856a 100644 --- a/crates/objc2/src/macros/extern_class.rs +++ b/crates/objc2/src/macros/extern_class.rs @@ -93,7 +93,7 @@ /// ``` /// # #[cfg(not_available)] /// use icrate::Foundation::{NSCoding, NSCopying, NSObjectProtocol}; -/// # use objc2::runtime::{NSObjectProtocol, __NSCopying as NSCopying}; +/// # use objc2::runtime::NSObjectProtocol; /// use objc2::rc::Id; /// use objc2::runtime::NSObject; /// use objc2::{extern_class, msg_send_id, mutability, ClassType}; @@ -117,6 +117,7 @@ /// // Note: We have to specify the protocols for the superclasses as well, /// // since Rust doesn't do inheritance. /// unsafe impl NSObjectProtocol for NSFormatter {} +/// # #[cfg(not_available)] /// unsafe impl NSCopying for NSFormatter {} /// # #[cfg(not_available)] /// unsafe impl NSCoding for NSFormatter {} @@ -136,7 +137,7 @@ /// ``` /// # #[cfg(not_available)] /// use icrate::Foundation::{NSCoding, NSCopying, NSObjectProtocol}; -/// # use objc2::runtime::{NSObjectProtocol, __NSCopying as NSCopying}; +/// # use objc2::runtime::NSObjectProtocol; /// use objc2::runtime::NSObject; /// use objc2::{extern_class, mutability, ClassType}; /// # @@ -464,8 +465,9 @@ macro_rules! __extern_class_impl_traits { // same object, and would violate aliasing rules. // // But `&mut NSMutableString` -> `&mut NSString` safe, since the - // `NSCopying` implementation of `NSMutableString` is used, and that - // is guaranteed to return a different object. + // `NSCopying` implementation of `NSMutableString` is still used on + // the `&mut NSString`, and that is guaranteed to return a different + // object. $(#[$impl_m])* impl<$($t)*> $crate::__macro_helpers::DerefMut for $for { #[inline] diff --git a/crates/objc2/src/mutability.rs b/crates/objc2/src/mutability.rs index b90f39eb4..799189084 100644 --- a/crates/objc2/src/mutability.rs +++ b/crates/objc2/src/mutability.rs @@ -136,10 +136,17 @@ pub struct ImmutableWithMutableSubclass { /// Marker type for mutable classes that have a immutable counterpart. /// -/// This is effectively the same as [`Mutable`], except that the immutable +/// This is effectively the same as [`Mutable`], except for the immutable /// counterpart being be specified as the type parameter `IS` to allow /// `NSCopying` and `NSMutableCopying` to return the correct type. /// +/// Functionality that is provided with this: +/// - [`IsAllocableAnyThread`] -> [`ClassType::alloc`]. +/// - [`IsMutable`] -> [`impl DerefMut for Id`][crate::rc::Id#impl-DerefMut-for-Id]. +/// - You are allowed to hand out pointers / references to an instance's +/// internal data, since you know such data will never be mutated without +/// the borrowchecker catching it. +/// /// /// # Example /// @@ -201,6 +208,11 @@ pub struct InteriorMutable { /// /// It is unsound to implement [`Send`] or [`Sync`] on a type with this /// mutability. +/// +/// Functionality that is provided with this: +/// - [`IsRetainable`] -> [`ClassType::retain`]. +/// - [`IsIdCloneable`] -> [`Id::clone`][crate::rc::Id#impl-Clone-for-Id]. +/// - [`IsMainThreadOnly`] -> `MainThreadMarker::from`. // // While Xcode's Main Thread Checker doesn't report `alloc` and `dealloc` as // unsafe from other threads, things like `NSView` and `NSWindow` still do a @@ -253,8 +265,54 @@ mod private { pub trait MutabilityIsMainThreadOnly: Mutability {} impl MutabilityIsMainThreadOnly for MainThreadOnly {} - // TODO: Trait for objects whose `hash` is guaranteed to never change, - // which allows it to be used as a key in `NSDictionary`. + pub trait MutabilityHashIsStable: Mutability {} + impl MutabilityHashIsStable for Immutable {} + impl MutabilityHashIsStable for Mutable {} + impl MutabilityHashIsStable for ImmutableWithMutableSubclass {} + impl MutabilityHashIsStable for MutableWithImmutableSuperclass {} + + pub trait MutabilityCounterpartOrSelf: Mutability { + type Immutable: ?Sized + ClassType; + type Mutable: ?Sized + ClassType; + } + impl> MutabilityCounterpartOrSelf for Root { + type Immutable = T; + type Mutable = T; + } + impl> MutabilityCounterpartOrSelf for Immutable { + type Immutable = T; + type Mutable = T; + } + impl> MutabilityCounterpartOrSelf for Mutable { + type Immutable = T; + type Mutable = T; + } + impl MutabilityCounterpartOrSelf for ImmutableWithMutableSubclass + where + T: ClassType>, + S: ClassType>, + { + type Immutable = T; + type Mutable = S; + } + impl MutabilityCounterpartOrSelf for MutableWithImmutableSuperclass + where + T: ClassType>, + S: ClassType>, + { + type Immutable = S; + type Mutable = T; + } + impl> MutabilityCounterpartOrSelf + for InteriorMutable + { + type Immutable = T; + type Mutable = T; + } + impl> MutabilityCounterpartOrSelf for MainThreadOnly { + type Immutable = T; + type Mutable = T; + } } /// Marker trait for the different types of mutability a class can have. @@ -349,10 +407,63 @@ impl IsMainThreadOnly for T where { } +/// Marker trait for classes whose `hash` and `isEqual:` methods are stable. +/// +/// This is useful for hashing collection types like `NSDictionary` and +/// `NSSet` which require that their keys never change. +/// +/// This is implemented for classes whose [`ClassType::Mutability`] is one of: +/// - [`Immutable`]. +/// - [`Mutable`]. +/// - [`ImmutableWithMutableSubclass`]. +/// - [`MutableWithImmutableSuperclass`]. +/// +/// Since all of these do not use interior mutability, and since the `hash` +/// and `isEqual:` methods are required to not use external sources like +/// thread locals or randomness to determine their result, we can guarantee +/// that the hash is stable for these types. +// +// TODO: Exclude generic types like `NSArray` from this! +pub trait HasStableHash: ClassType {} +impl HasStableHash for T where T::Mutability: private::MutabilityHashIsStable {} + +/// Retrieve the immutable/mutable counterpart class, and fall back to `Self` +/// if not applicable. +/// +/// This is mostly used for describing the return type of `NSCopying` and +/// `NSMutableCopying`, since due to Rust trait limitations, those two can't +/// have associated types themselves (at least not since we want to use them +/// in `ProtocolObject`). +pub trait CounterpartOrSelf: ClassType { + /// The immutable counterpart of the type, or `Self` if the type has no + /// immutable counterpart. + /// + /// The implementation for `NSString` has itself (`NSString`) here, while + /// `NSMutableString` instead has `NSString`. + type Immutable: ?Sized + ClassType; + + /// The mutable counterpart of the type, or `Self` if the type has no + /// mutable counterpart. + /// + /// The implementation for `NSString` has `NSMutableString` here, while + /// `NSMutableString` has itself (`NSMutableString`). + type Mutable: ?Sized + ClassType; +} +impl CounterpartOrSelf for T +where + T::Mutability: private::MutabilityCounterpartOrSelf, +{ + type Immutable = >::Immutable; + type Mutable = >::Mutable; +} + #[cfg(test)] mod tests { + use crate::runtime::NSObject; + use super::*; + use core::any::TypeId; use core::fmt; use core::hash; @@ -379,4 +490,16 @@ mod tests { assert_sized::(); } } + + #[test] + fn counterpart_root() { + assert_eq!( + TypeId::of::(), + TypeId::of::<::Immutable>(), + ); + assert_eq!( + TypeId::of::(), + TypeId::of::<::Mutable>(), + ); + } } diff --git a/crates/objc2/src/rc/test_object.rs b/crates/objc2/src/rc/test_object.rs index 339a8b0ae..2faed6de2 100644 --- a/crates/objc2/src/rc/test_object.rs +++ b/crates/objc2/src/rc/test_object.rs @@ -60,7 +60,7 @@ std::thread_local! { declare_class!( /// A helper object that counts how many times various reference-counting /// primitives are called. - #[derive(Debug, PartialEq, Eq)] + #[derive(Debug, PartialEq, Eq, Hash)] #[doc(hidden)] pub struct __RcTestObject; diff --git a/crates/objc2/src/runtime/mod.rs b/crates/objc2/src/runtime/mod.rs index a3bc0c2fd..f7b8de1df 100644 --- a/crates/objc2/src/runtime/mod.rs +++ b/crates/objc2/src/runtime/mod.rs @@ -33,7 +33,6 @@ use std::os::raw::c_uint; pub mod __nsstring; mod bool; mod method_encoding_iter; -mod nscopying; mod nsobject; mod nsproxy; mod nszone; @@ -46,12 +45,8 @@ use crate::encode::{Encode, EncodeArguments, EncodeReturn, Encoding, OptionEncod use crate::verify::{verify_method_signature, Inner}; use crate::{ffi, Message}; -// Note: While these are not public, they are still a breaking change to -// remove, since `icrate` relies on them. -#[doc(hidden)] -pub use self::nscopying::{ - Copyhelper as __Copyhelper, NSCopying as __NSCopying, NSMutableCopying as __NSMutableCopying, -}; +// Note: While this is not public, it is still a breaking change to remove, +// since `icrate` relies on it. #[doc(hidden)] pub use self::nsproxy::NSProxy as __NSProxy; diff --git a/crates/objc2/src/runtime/nscopying.rs b/crates/objc2/src/runtime/nscopying.rs deleted file mode 100644 index 0ff20bb9d..000000000 --- a/crates/objc2/src/runtime/nscopying.rs +++ /dev/null @@ -1,159 +0,0 @@ -use crate::mutability::{ - Immutable, ImmutableWithMutableSubclass, InteriorMutable, MainThreadOnly, Mutability, Mutable, - MutableWithImmutableSuperclass, Root, -}; -use crate::rc::Id; -use crate::{msg_send_id, ClassType, ProtocolType}; - -/// Helper trait for [`NSCopying`] and [`NSMutableCopying`]. -/// -/// This is needed since those two can't have associated types themselves (at -/// least not if they want to be usable as `ProtocolObject`), -/// and because the return type of those differ if the class has a mutable or -/// an immutable counterpart (as is the case for `NSString` and -/// `NSMutableString`). -// -// Note: This trait is intentionally not object safe. -pub trait Copyhelper: Mutability { - /// The output type of [`NSCopying`] for the given `T`. - type CopyOutput: ?Sized + ClassType; - /// The output type of [`NSMutableCopying`] for the given `T`. - type MutableCopyOutput: ?Sized + ClassType; - - // TODO: Use this to autogenerate `ToOwned` impls - #[doc(hidden)] - fn __do_copy(t: &T) -> Id; -} -impl> Copyhelper for Root { - type CopyOutput = T; - type MutableCopyOutput = T; - - #[inline] - fn __do_copy(t: &T) -> Id { - t.copy() - } -} -impl> Copyhelper for Immutable { - type CopyOutput = T; - type MutableCopyOutput = T; - - #[inline] - fn __do_copy(t: &T) -> Id { - t.retain() - } -} -impl> Copyhelper for Mutable { - type CopyOutput = T; - type MutableCopyOutput = T; - - #[inline] - fn __do_copy(t: &T) -> Id { - t.copy() - } -} -impl Copyhelper for ImmutableWithMutableSubclass -where - T: NSCopying + ClassType>, - S: ClassType>, -{ - type CopyOutput = T; - type MutableCopyOutput = S; - - #[inline] - fn __do_copy(t: &T) -> Id { - t.copy() - } -} -impl Copyhelper for MutableWithImmutableSuperclass -where - T: NSMutableCopying + ClassType>, - S: ClassType>, -{ - type CopyOutput = S; - type MutableCopyOutput = T; - - #[inline] - fn __do_copy(t: &T) -> Id { - t.mutableCopy() - } -} -impl> Copyhelper for InteriorMutable { - type CopyOutput = T; - type MutableCopyOutput = T; - - #[inline] - fn __do_copy(t: &T) -> Id { - t.retain() - } -} -impl> Copyhelper for MainThreadOnly { - type CopyOutput = T; - type MutableCopyOutput = T; - - #[inline] - fn __do_copy(t: &T) -> Id { - t.retain() - } -} - -/// A protocol to provide functional copies of objects. -/// -/// This is similar to Rust's [`Clone`] trait, along with sharing a few -/// similarities to the [`std::borrow::ToOwned`] trait with regards to the -/// output type. -/// -/// See [Apple's documentation][apple-doc] for details. -/// -/// [apple-doc]: https://developer.apple.com/documentation/foundation/nscopying -#[allow(clippy::missing_safety_doc)] // Same as all other traits -pub unsafe trait NSCopying { - /// Returns a new instance that's a copy of the receiver. - /// - /// The output type is usually `Self`, but e.g. `NSMutableString` returns - /// `NSString`. - fn copy(&self) -> Id<>::CopyOutput> - where - Self: Sized + ClassType, - Self::Mutability: Copyhelper, - { - unsafe { msg_send_id![self, copy] } - } -} - -crate::__inner_extern_protocol!( - () - (NSCopying) - (dyn NSCopying) - ("NSCopying") -); - -/// A protocol to provide mutable copies of objects. -/// -/// Only classes that have an “immutable vs. mutable” distinction should adopt -/// this protocol. -/// -/// See [Apple's documentation][apple-doc] for details. -/// -/// [apple-doc]: https://developer.apple.com/documentation/foundation/nsmutablecopying -#[allow(clippy::missing_safety_doc)] // Same as all other traits -pub unsafe trait NSMutableCopying { - /// Returns a new instance that's a mutable copy of the receiver. - /// - /// The output type is the mutable counterpart of the object. E.g. both - /// `NSString` and `NSMutableString` return `NSMutableString`. - #[allow(non_snake_case)] - fn mutableCopy(&self) -> Id<>::MutableCopyOutput> - where - Self: Sized + ClassType, - Self::Mutability: Copyhelper, - { - unsafe { msg_send_id![self, mutableCopy] } - } -} - -crate::__inner_extern_protocol!( - () - (NSMutableCopying) - (dyn NSMutableCopying) - ("NSMutableCopying") -); diff --git a/crates/objc2/src/runtime/nsobject.rs b/crates/objc2/src/runtime/nsobject.rs index 549c330b0..4b2570818 100644 --- a/crates/objc2/src/runtime/nsobject.rs +++ b/crates/objc2/src/runtime/nsobject.rs @@ -102,6 +102,8 @@ unsafe impl ClassType for NSObject { /// that implements the `NSObject` protocol. #[allow(non_snake_case)] pub unsafe trait NSObjectProtocol { + // Note: This method must remain `unsafe` to override, since hashing + // collections like `NSDictionary` and `NSSet` rely on it being stable. #[doc(hidden)] fn __isEqual(&self, other: &Self) -> bool where @@ -110,6 +112,8 @@ pub unsafe trait NSObjectProtocol { unsafe { msg_send![self, isEqual: other] } } + // Note: This method must remain `unsafe` to override, since hashing + // collections like `NSDictionary` and `NSSet` rely on it being stable. #[doc(hidden)] fn __hash(&self) -> usize where diff --git a/crates/test-assembly/crates/test_declare_class/Cargo.toml b/crates/test-assembly/crates/test_declare_class/Cargo.toml index bc46cbaf0..7e42d6c45 100644 --- a/crates/test-assembly/crates/test_declare_class/Cargo.toml +++ b/crates/test-assembly/crates/test_declare_class/Cargo.toml @@ -9,17 +9,20 @@ path = "lib.rs" [dependencies] objc2 = { path = "../../../objc2", default-features = false, optional = true } +icrate = { path = "../../../icrate", default-features = false, optional = true } [features] -default = ["apple", "std"] -std = ["objc2?/std"] +default = ["apple", "std", "Foundation"] +std = ["icrate?/std", "icrate?/std"] # Runtime -apple = ["objc2", "objc2?/apple"] -gnustep-1-7 = ["objc2?/gnustep-1-7"] -gnustep-1-8 = ["gnustep-1-7", "objc2?/gnustep-1-8"] -gnustep-1-9 = ["gnustep-1-8", "objc2?/gnustep-1-9"] -gnustep-2-0 = ["gnustep-1-9", "objc2?/gnustep-2-0"] -gnustep-2-1 = ["gnustep-2-0", "objc2?/gnustep-2-1"] +apple = ["objc2", "icrate", "icrate?/apple"] +gnustep-1-7 = ["icrate?/gnustep-1-7"] +gnustep-1-8 = ["gnustep-1-7", "icrate?/gnustep-1-8"] +gnustep-1-9 = ["gnustep-1-8", "icrate?/gnustep-1-9"] +gnustep-2-0 = ["gnustep-1-9", "icrate?/gnustep-2-0"] +gnustep-2-1 = ["gnustep-2-0", "icrate?/gnustep-2-1"] + +Foundation = ["icrate?/Foundation"] # Hack to prevent the feature flag from being enabled in the entire project assembly-features = ["objc2?/unstable-static-sel-inlined", "objc2?/unstable-static-class-inlined"] diff --git a/crates/test-assembly/crates/test_declare_class/expected/apple-aarch64.s b/crates/test-assembly/crates/test_declare_class/expected/apple-aarch64.s index 59304b69b..3423c421c 100644 --- a/crates/test-assembly/crates/test_declare_class/expected/apple-aarch64.s +++ b/crates/test-assembly/crates/test_declare_class/expected/apple-aarch64.s @@ -94,9 +94,9 @@ Lloh26: mov x4, x19 bl SYM(objc2::declare::ClassBuilder::add_method_inner::GENERATED_ID, 0) Lloh27: - adrp x8, L_OBJC_SELECTOR_REFERENCES_8dd788dbcc16b9bc@PAGE + adrp x8, L_OBJC_SELECTOR_REFERENCES_d874ee9262978be2@PAGE Lloh28: - ldr x1, [x8, L_OBJC_SELECTOR_REFERENCES_8dd788dbcc16b9bc@PAGEOFF] + ldr x1, [x8, L_OBJC_SELECTOR_REFERENCES_d874ee9262978be2@PAGEOFF] Lloh29: adrp x5, _class_method@PAGE Lloh30: @@ -107,9 +107,9 @@ Lloh30: mov x4, x21 bl SYM(objc2::declare::ClassBuilder::add_class_method_inner::GENERATED_ID, 0) Lloh31: - adrp x8, L_OBJC_SELECTOR_REFERENCES_450db9db0953dff5@PAGE + adrp x8, L_OBJC_SELECTOR_REFERENCES_4539fd1dbda0cddc@PAGE Lloh32: - ldr x1, [x8, L_OBJC_SELECTOR_REFERENCES_450db9db0953dff5@PAGEOFF] + ldr x1, [x8, L_OBJC_SELECTOR_REFERENCES_4539fd1dbda0cddc@PAGEOFF] Lloh33: adrp x5, _method@PAGE Lloh34: @@ -120,9 +120,9 @@ Lloh34: mov x4, x21 bl SYM(objc2::declare::ClassBuilder::add_method_inner::GENERATED_ID, 0) Lloh35: - adrp x8, L_OBJC_SELECTOR_REFERENCES_783b35bc45c6e4a6@PAGE + adrp x8, L_OBJC_SELECTOR_REFERENCES_2b1b3a94e0ece2e5@PAGE Lloh36: - ldr x1, [x8, L_OBJC_SELECTOR_REFERENCES_783b35bc45c6e4a6@PAGEOFF] + ldr x1, [x8, L_OBJC_SELECTOR_REFERENCES_2b1b3a94e0ece2e5@PAGEOFF] Lloh37: adrp x21, l_anon.[ID].4@PAGE Lloh38: @@ -137,9 +137,9 @@ Lloh40: mov x4, x21 bl SYM(objc2::declare::ClassBuilder::add_method_inner::GENERATED_ID, 0) Lloh41: - adrp x8, L_OBJC_SELECTOR_REFERENCES_828e9fbc6d0b4498@PAGE + adrp x8, L_OBJC_SELECTOR_REFERENCES_f7f521670860b0ce@PAGE Lloh42: - ldr x1, [x8, L_OBJC_SELECTOR_REFERENCES_828e9fbc6d0b4498@PAGEOFF] + ldr x1, [x8, L_OBJC_SELECTOR_REFERENCES_f7f521670860b0ce@PAGEOFF] Lloh43: adrp x5, _method_id@PAGE Lloh44: @@ -150,9 +150,9 @@ Lloh44: mov x4, x19 bl SYM(objc2::declare::ClassBuilder::add_method_inner::GENERATED_ID, 0) Lloh45: - adrp x8, L_OBJC_SELECTOR_REFERENCES_788cc14ba6a28eb8@PAGE + adrp x8, L_OBJC_SELECTOR_REFERENCES_6addfcf634c6232f@PAGE Lloh46: - ldr x1, [x8, L_OBJC_SELECTOR_REFERENCES_788cc14ba6a28eb8@PAGEOFF] + ldr x1, [x8, L_OBJC_SELECTOR_REFERENCES_6addfcf634c6232f@PAGEOFF] Lloh47: adrp x5, _method_id_with_param@PAGE Lloh48: @@ -172,17 +172,17 @@ Lloh50: mov x0, sp bl SYM(objc2::__macro_helpers::::__add_protocol_methods::GENERATED_ID, 0) Lloh51: - adrp x8, L_OBJC_SELECTOR_REFERENCES_f058a81939de2cb9@PAGE + adrp x8, L_OBJC_SELECTOR_REFERENCES_4a8c690dbc9d8166@PAGE Lloh52: - ldr x1, [x8, L_OBJC_SELECTOR_REFERENCES_f058a81939de2cb9@PAGEOFF] + ldr x1, [x8, L_OBJC_SELECTOR_REFERENCES_4a8c690dbc9d8166@PAGEOFF] Lloh53: adrp x2, l_anon.[ID].7@PAGE Lloh54: add x2, x2, l_anon.[ID].7@PAGEOFF Lloh55: - adrp x5, _copy_with_zone@PAGE + adrp x5, _copyWithZone@PAGE Lloh56: - add x5, x5, _copy_with_zone@PAGEOFF + add x5, x5, _copyWithZone@PAGEOFF mov w3, #1 mov x4, x19 bl SYM(objc2::declare::ClassBuilder::add_method_inner::GENERATED_ID, 0) @@ -685,9 +685,9 @@ LBB14_5: .loh AdrpAdd Lloh139, Lloh140 .loh AdrpAdd Lloh137, Lloh138 - .globl _copy_with_zone + .globl _copyWithZone .p2align 2 -_copy_with_zone: +_copyWithZone: stp x24, x23, [sp, #-64]! stp x22, x21, [sp, #16] stp x20, x19, [sp, #32] @@ -849,7 +849,7 @@ l_anon.[ID].14: .p2align 3, 0x0 l_anon.[ID].15: .quad l_anon.[ID].14 - .asciz "5\000\000\000\000\000\000\000\013\000\000\000\001\000\000" + .asciz "5\000\000\000\000\000\000\000\f\000\000\000\001\000\000" .section __TEXT,__const l_anon.[ID].16: @@ -879,105 +879,105 @@ l_anon.[ID].21: .asciz "\017\000\000\000\000\000\000" .section __DATA,__objc_imageinfo,regular,no_dead_strip - .globl L_OBJC_IMAGE_INFO_8dd788dbcc16b9bc + .globl L_OBJC_IMAGE_INFO_d874ee9262978be2 .p2align 2, 0x0 -L_OBJC_IMAGE_INFO_8dd788dbcc16b9bc: +L_OBJC_IMAGE_INFO_d874ee9262978be2: .asciz "\000\000\000\000@\000\000" .section __TEXT,__objc_methname,cstring_literals - .globl L_OBJC_METH_VAR_NAME_8dd788dbcc16b9bc -L_OBJC_METH_VAR_NAME_8dd788dbcc16b9bc: + .globl L_OBJC_METH_VAR_NAME_d874ee9262978be2 +L_OBJC_METH_VAR_NAME_d874ee9262978be2: .asciz "classMethod" .section __DATA,__objc_selrefs,literal_pointers,no_dead_strip - .globl L_OBJC_SELECTOR_REFERENCES_8dd788dbcc16b9bc + .globl L_OBJC_SELECTOR_REFERENCES_d874ee9262978be2 .p2align 3, 0x0 -L_OBJC_SELECTOR_REFERENCES_8dd788dbcc16b9bc: - .quad L_OBJC_METH_VAR_NAME_8dd788dbcc16b9bc +L_OBJC_SELECTOR_REFERENCES_d874ee9262978be2: + .quad L_OBJC_METH_VAR_NAME_d874ee9262978be2 .section __DATA,__objc_imageinfo,regular,no_dead_strip - .globl L_OBJC_IMAGE_INFO_450db9db0953dff5 + .globl L_OBJC_IMAGE_INFO_4539fd1dbda0cddc .p2align 2, 0x0 -L_OBJC_IMAGE_INFO_450db9db0953dff5: +L_OBJC_IMAGE_INFO_4539fd1dbda0cddc: .asciz "\000\000\000\000@\000\000" .section __TEXT,__objc_methname,cstring_literals - .globl L_OBJC_METH_VAR_NAME_450db9db0953dff5 -L_OBJC_METH_VAR_NAME_450db9db0953dff5: + .globl L_OBJC_METH_VAR_NAME_4539fd1dbda0cddc +L_OBJC_METH_VAR_NAME_4539fd1dbda0cddc: .asciz "method" .section __DATA,__objc_selrefs,literal_pointers,no_dead_strip - .globl L_OBJC_SELECTOR_REFERENCES_450db9db0953dff5 + .globl L_OBJC_SELECTOR_REFERENCES_4539fd1dbda0cddc .p2align 3, 0x0 -L_OBJC_SELECTOR_REFERENCES_450db9db0953dff5: - .quad L_OBJC_METH_VAR_NAME_450db9db0953dff5 +L_OBJC_SELECTOR_REFERENCES_4539fd1dbda0cddc: + .quad L_OBJC_METH_VAR_NAME_4539fd1dbda0cddc .section __DATA,__objc_imageinfo,regular,no_dead_strip - .globl L_OBJC_IMAGE_INFO_783b35bc45c6e4a6 + .globl L_OBJC_IMAGE_INFO_2b1b3a94e0ece2e5 .p2align 2, 0x0 -L_OBJC_IMAGE_INFO_783b35bc45c6e4a6: +L_OBJC_IMAGE_INFO_2b1b3a94e0ece2e5: .asciz "\000\000\000\000@\000\000" .section __TEXT,__objc_methname,cstring_literals - .globl L_OBJC_METH_VAR_NAME_783b35bc45c6e4a6 -L_OBJC_METH_VAR_NAME_783b35bc45c6e4a6: + .globl L_OBJC_METH_VAR_NAME_2b1b3a94e0ece2e5 +L_OBJC_METH_VAR_NAME_2b1b3a94e0ece2e5: .asciz "methodBool:" .section __DATA,__objc_selrefs,literal_pointers,no_dead_strip - .globl L_OBJC_SELECTOR_REFERENCES_783b35bc45c6e4a6 + .globl L_OBJC_SELECTOR_REFERENCES_2b1b3a94e0ece2e5 .p2align 3, 0x0 -L_OBJC_SELECTOR_REFERENCES_783b35bc45c6e4a6: - .quad L_OBJC_METH_VAR_NAME_783b35bc45c6e4a6 +L_OBJC_SELECTOR_REFERENCES_2b1b3a94e0ece2e5: + .quad L_OBJC_METH_VAR_NAME_2b1b3a94e0ece2e5 .section __DATA,__objc_imageinfo,regular,no_dead_strip - .globl L_OBJC_IMAGE_INFO_828e9fbc6d0b4498 + .globl L_OBJC_IMAGE_INFO_f7f521670860b0ce .p2align 2, 0x0 -L_OBJC_IMAGE_INFO_828e9fbc6d0b4498: +L_OBJC_IMAGE_INFO_f7f521670860b0ce: .asciz "\000\000\000\000@\000\000" .section __TEXT,__objc_methname,cstring_literals - .globl L_OBJC_METH_VAR_NAME_828e9fbc6d0b4498 -L_OBJC_METH_VAR_NAME_828e9fbc6d0b4498: + .globl L_OBJC_METH_VAR_NAME_f7f521670860b0ce +L_OBJC_METH_VAR_NAME_f7f521670860b0ce: .asciz "methodId" .section __DATA,__objc_selrefs,literal_pointers,no_dead_strip - .globl L_OBJC_SELECTOR_REFERENCES_828e9fbc6d0b4498 + .globl L_OBJC_SELECTOR_REFERENCES_f7f521670860b0ce .p2align 3, 0x0 -L_OBJC_SELECTOR_REFERENCES_828e9fbc6d0b4498: - .quad L_OBJC_METH_VAR_NAME_828e9fbc6d0b4498 +L_OBJC_SELECTOR_REFERENCES_f7f521670860b0ce: + .quad L_OBJC_METH_VAR_NAME_f7f521670860b0ce .section __DATA,__objc_imageinfo,regular,no_dead_strip - .globl L_OBJC_IMAGE_INFO_788cc14ba6a28eb8 + .globl L_OBJC_IMAGE_INFO_6addfcf634c6232f .p2align 2, 0x0 -L_OBJC_IMAGE_INFO_788cc14ba6a28eb8: +L_OBJC_IMAGE_INFO_6addfcf634c6232f: .asciz "\000\000\000\000@\000\000" .section __TEXT,__objc_methname,cstring_literals - .globl L_OBJC_METH_VAR_NAME_788cc14ba6a28eb8 -L_OBJC_METH_VAR_NAME_788cc14ba6a28eb8: + .globl L_OBJC_METH_VAR_NAME_6addfcf634c6232f +L_OBJC_METH_VAR_NAME_6addfcf634c6232f: .asciz "methodIdWithParam:" .section __DATA,__objc_selrefs,literal_pointers,no_dead_strip - .globl L_OBJC_SELECTOR_REFERENCES_788cc14ba6a28eb8 + .globl L_OBJC_SELECTOR_REFERENCES_6addfcf634c6232f .p2align 3, 0x0 -L_OBJC_SELECTOR_REFERENCES_788cc14ba6a28eb8: - .quad L_OBJC_METH_VAR_NAME_788cc14ba6a28eb8 +L_OBJC_SELECTOR_REFERENCES_6addfcf634c6232f: + .quad L_OBJC_METH_VAR_NAME_6addfcf634c6232f .section __DATA,__objc_imageinfo,regular,no_dead_strip - .globl L_OBJC_IMAGE_INFO_f058a81939de2cb9 + .globl L_OBJC_IMAGE_INFO_4a8c690dbc9d8166 .p2align 2, 0x0 -L_OBJC_IMAGE_INFO_f058a81939de2cb9: +L_OBJC_IMAGE_INFO_4a8c690dbc9d8166: .asciz "\000\000\000\000@\000\000" .section __TEXT,__objc_methname,cstring_literals - .globl L_OBJC_METH_VAR_NAME_f058a81939de2cb9 -L_OBJC_METH_VAR_NAME_f058a81939de2cb9: + .globl L_OBJC_METH_VAR_NAME_4a8c690dbc9d8166 +L_OBJC_METH_VAR_NAME_4a8c690dbc9d8166: .asciz "copyWithZone:" .section __DATA,__objc_selrefs,literal_pointers,no_dead_strip - .globl L_OBJC_SELECTOR_REFERENCES_f058a81939de2cb9 + .globl L_OBJC_SELECTOR_REFERENCES_4a8c690dbc9d8166 .p2align 3, 0x0 -L_OBJC_SELECTOR_REFERENCES_f058a81939de2cb9: - .quad L_OBJC_METH_VAR_NAME_f058a81939de2cb9 +L_OBJC_SELECTOR_REFERENCES_4a8c690dbc9d8166: + .quad L_OBJC_METH_VAR_NAME_4a8c690dbc9d8166 .subsections_via_symbols diff --git a/crates/test-assembly/crates/test_declare_class/expected/apple-armv7.s b/crates/test-assembly/crates/test_declare_class/expected/apple-armv7.s index c380efdab..5d17ff828 100644 --- a/crates/test-assembly/crates/test_declare_class/expected/apple-armv7.s +++ b/crates/test-assembly/crates/test_declare_class/expected/apple-armv7.s @@ -97,9 +97,9 @@ LPC1_11: add r9, pc, r9 strd r8, r9, [sp] bl SYM(objc2::declare::ClassBuilder::add_method_inner::GENERATED_ID, 0) - movw r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_8dd788dbcc16b9bc-(LPC1_12+8)) + movw r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_d874ee9262978be2-(LPC1_12+8)) mov r0, r4 - movt r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_8dd788dbcc16b9bc-(LPC1_12+8)) + movt r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_d874ee9262978be2-(LPC1_12+8)) mov r2, r5 LPC1_12: ldr r1, [pc, r1] @@ -110,9 +110,9 @@ LPC1_13: add r11, pc, r11 strd r10, r11, [sp] bl SYM(objc2::declare::ClassBuilder::add_class_method_inner::GENERATED_ID, 0) - movw r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_450db9db0953dff5-(LPC1_14+8)) + movw r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_4539fd1dbda0cddc-(LPC1_14+8)) mov r0, r4 - movt r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_450db9db0953dff5-(LPC1_14+8)) + movt r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_4539fd1dbda0cddc-(LPC1_14+8)) mov r2, r5 LPC1_14: ldr r1, [pc, r1] @@ -123,9 +123,9 @@ LPC1_15: add r11, pc, r11 strd r10, r11, [sp] bl SYM(objc2::declare::ClassBuilder::add_method_inner::GENERATED_ID, 0) - movw r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_783b35bc45c6e4a6-(LPC1_16+8)) + movw r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_2b1b3a94e0ece2e5-(LPC1_16+8)) mov r0, r4 - movt r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_783b35bc45c6e4a6-(LPC1_16+8)) + movt r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_2b1b3a94e0ece2e5-(LPC1_16+8)) LPC1_16: ldr r1, [pc, r1] movw r3, :lower16:(_method_bool-(LPC1_17+8)) @@ -141,9 +141,9 @@ LPC1_18: mov r3, #1 mov r2, r10 bl SYM(objc2::declare::ClassBuilder::add_method_inner::GENERATED_ID, 0) - movw r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_828e9fbc6d0b4498-(LPC1_19+8)) + movw r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_f7f521670860b0ce-(LPC1_19+8)) mov r0, r4 - movt r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_828e9fbc6d0b4498-(LPC1_19+8)) + movt r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_f7f521670860b0ce-(LPC1_19+8)) mov r2, r5 LPC1_19: ldr r1, [pc, r1] @@ -154,9 +154,9 @@ LPC1_20: add r9, pc, r9 strd r8, r9, [sp] bl SYM(objc2::declare::ClassBuilder::add_method_inner::GENERATED_ID, 0) - movw r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_788cc14ba6a28eb8-(LPC1_21+8)) + movw r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_6addfcf634c6232f-(LPC1_21+8)) mov r0, r4 - movt r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_788cc14ba6a28eb8-(LPC1_21+8)) + movt r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_6addfcf634c6232f-(LPC1_21+8)) mov r2, r10 LPC1_21: ldr r1, [pc, r1] @@ -179,14 +179,14 @@ LPC1_23: movw r2, :lower16:(l_anon.[ID].7-(LPC1_24+8)) mov r3, #1 movt r2, :upper16:(l_anon.[ID].7-(LPC1_24+8)) - movw r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_f058a81939de2cb9-(LPC1_25+8)) - movt r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_f058a81939de2cb9-(LPC1_25+8)) + movw r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_4a8c690dbc9d8166-(LPC1_25+8)) + movt r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_4a8c690dbc9d8166-(LPC1_25+8)) LPC1_24: add r2, pc, r2 LPC1_25: ldr r1, [pc, r1] - movw r9, :lower16:(_copy_with_zone-(LPC1_26+8)) - movt r9, :upper16:(_copy_with_zone-(LPC1_26+8)) + movw r9, :lower16:(_copyWithZone-(LPC1_26+8)) + movt r9, :upper16:(_copyWithZone-(LPC1_26+8)) LPC1_26: add r9, pc, r9 strd r8, r9, [sp] @@ -621,10 +621,10 @@ LBB14_5: pop {r4, r5, r6, r7, lr} b _objc_autoreleaseReturnValue - .globl _copy_with_zone + .globl _copyWithZone .p2align 2 .code 32 -_copy_with_zone: +_copyWithZone: push {r4, r5, r6, r7, lr} add r7, sp, #12 push {r8, r10} @@ -777,7 +777,7 @@ l_anon.[ID].14: .p2align 2, 0x0 l_anon.[ID].15: .long l_anon.[ID].14 - .asciz "5\000\000\000\013\000\000\000\001\000\000" + .asciz "5\000\000\000\f\000\000\000\001\000\000" .section __TEXT,__const l_anon.[ID].16: @@ -807,106 +807,106 @@ l_anon.[ID].21: .asciz "\017\000\000" .section __DATA,__objc_imageinfo,regular,no_dead_strip - .globl L_OBJC_IMAGE_INFO_8dd788dbcc16b9bc + .globl L_OBJC_IMAGE_INFO_d874ee9262978be2 .p2align 2, 0x0 -L_OBJC_IMAGE_INFO_8dd788dbcc16b9bc: +L_OBJC_IMAGE_INFO_d874ee9262978be2: .asciz "\000\000\000\000@\000\000" .section __TEXT,__objc_methname,cstring_literals - .globl L_OBJC_METH_VAR_NAME_8dd788dbcc16b9bc -L_OBJC_METH_VAR_NAME_8dd788dbcc16b9bc: + .globl L_OBJC_METH_VAR_NAME_d874ee9262978be2 +L_OBJC_METH_VAR_NAME_d874ee9262978be2: .asciz "classMethod" .section __DATA,__objc_selrefs,literal_pointers,no_dead_strip - .globl L_OBJC_SELECTOR_REFERENCES_8dd788dbcc16b9bc + .globl L_OBJC_SELECTOR_REFERENCES_d874ee9262978be2 .p2align 2, 0x0 -L_OBJC_SELECTOR_REFERENCES_8dd788dbcc16b9bc: - .long L_OBJC_METH_VAR_NAME_8dd788dbcc16b9bc +L_OBJC_SELECTOR_REFERENCES_d874ee9262978be2: + .long L_OBJC_METH_VAR_NAME_d874ee9262978be2 .section __DATA,__objc_imageinfo,regular,no_dead_strip - .globl L_OBJC_IMAGE_INFO_450db9db0953dff5 + .globl L_OBJC_IMAGE_INFO_4539fd1dbda0cddc .p2align 2, 0x0 -L_OBJC_IMAGE_INFO_450db9db0953dff5: +L_OBJC_IMAGE_INFO_4539fd1dbda0cddc: .asciz "\000\000\000\000@\000\000" .section __TEXT,__objc_methname,cstring_literals - .globl L_OBJC_METH_VAR_NAME_450db9db0953dff5 -L_OBJC_METH_VAR_NAME_450db9db0953dff5: + .globl L_OBJC_METH_VAR_NAME_4539fd1dbda0cddc +L_OBJC_METH_VAR_NAME_4539fd1dbda0cddc: .asciz "method" .section __DATA,__objc_selrefs,literal_pointers,no_dead_strip - .globl L_OBJC_SELECTOR_REFERENCES_450db9db0953dff5 + .globl L_OBJC_SELECTOR_REFERENCES_4539fd1dbda0cddc .p2align 2, 0x0 -L_OBJC_SELECTOR_REFERENCES_450db9db0953dff5: - .long L_OBJC_METH_VAR_NAME_450db9db0953dff5 +L_OBJC_SELECTOR_REFERENCES_4539fd1dbda0cddc: + .long L_OBJC_METH_VAR_NAME_4539fd1dbda0cddc .section __DATA,__objc_imageinfo,regular,no_dead_strip - .globl L_OBJC_IMAGE_INFO_783b35bc45c6e4a6 + .globl L_OBJC_IMAGE_INFO_2b1b3a94e0ece2e5 .p2align 2, 0x0 -L_OBJC_IMAGE_INFO_783b35bc45c6e4a6: +L_OBJC_IMAGE_INFO_2b1b3a94e0ece2e5: .asciz "\000\000\000\000@\000\000" .section __TEXT,__objc_methname,cstring_literals - .globl L_OBJC_METH_VAR_NAME_783b35bc45c6e4a6 -L_OBJC_METH_VAR_NAME_783b35bc45c6e4a6: + .globl L_OBJC_METH_VAR_NAME_2b1b3a94e0ece2e5 +L_OBJC_METH_VAR_NAME_2b1b3a94e0ece2e5: .asciz "methodBool:" .section __DATA,__objc_selrefs,literal_pointers,no_dead_strip - .globl L_OBJC_SELECTOR_REFERENCES_783b35bc45c6e4a6 + .globl L_OBJC_SELECTOR_REFERENCES_2b1b3a94e0ece2e5 .p2align 2, 0x0 -L_OBJC_SELECTOR_REFERENCES_783b35bc45c6e4a6: - .long L_OBJC_METH_VAR_NAME_783b35bc45c6e4a6 +L_OBJC_SELECTOR_REFERENCES_2b1b3a94e0ece2e5: + .long L_OBJC_METH_VAR_NAME_2b1b3a94e0ece2e5 .section __DATA,__objc_imageinfo,regular,no_dead_strip - .globl L_OBJC_IMAGE_INFO_828e9fbc6d0b4498 + .globl L_OBJC_IMAGE_INFO_f7f521670860b0ce .p2align 2, 0x0 -L_OBJC_IMAGE_INFO_828e9fbc6d0b4498: +L_OBJC_IMAGE_INFO_f7f521670860b0ce: .asciz "\000\000\000\000@\000\000" .section __TEXT,__objc_methname,cstring_literals - .globl L_OBJC_METH_VAR_NAME_828e9fbc6d0b4498 -L_OBJC_METH_VAR_NAME_828e9fbc6d0b4498: + .globl L_OBJC_METH_VAR_NAME_f7f521670860b0ce +L_OBJC_METH_VAR_NAME_f7f521670860b0ce: .asciz "methodId" .section __DATA,__objc_selrefs,literal_pointers,no_dead_strip - .globl L_OBJC_SELECTOR_REFERENCES_828e9fbc6d0b4498 + .globl L_OBJC_SELECTOR_REFERENCES_f7f521670860b0ce .p2align 2, 0x0 -L_OBJC_SELECTOR_REFERENCES_828e9fbc6d0b4498: - .long L_OBJC_METH_VAR_NAME_828e9fbc6d0b4498 +L_OBJC_SELECTOR_REFERENCES_f7f521670860b0ce: + .long L_OBJC_METH_VAR_NAME_f7f521670860b0ce .section __DATA,__objc_imageinfo,regular,no_dead_strip - .globl L_OBJC_IMAGE_INFO_788cc14ba6a28eb8 + .globl L_OBJC_IMAGE_INFO_6addfcf634c6232f .p2align 2, 0x0 -L_OBJC_IMAGE_INFO_788cc14ba6a28eb8: +L_OBJC_IMAGE_INFO_6addfcf634c6232f: .asciz "\000\000\000\000@\000\000" .section __TEXT,__objc_methname,cstring_literals - .globl L_OBJC_METH_VAR_NAME_788cc14ba6a28eb8 -L_OBJC_METH_VAR_NAME_788cc14ba6a28eb8: + .globl L_OBJC_METH_VAR_NAME_6addfcf634c6232f +L_OBJC_METH_VAR_NAME_6addfcf634c6232f: .asciz "methodIdWithParam:" .section __DATA,__objc_selrefs,literal_pointers,no_dead_strip - .globl L_OBJC_SELECTOR_REFERENCES_788cc14ba6a28eb8 + .globl L_OBJC_SELECTOR_REFERENCES_6addfcf634c6232f .p2align 2, 0x0 -L_OBJC_SELECTOR_REFERENCES_788cc14ba6a28eb8: - .long L_OBJC_METH_VAR_NAME_788cc14ba6a28eb8 +L_OBJC_SELECTOR_REFERENCES_6addfcf634c6232f: + .long L_OBJC_METH_VAR_NAME_6addfcf634c6232f .section __DATA,__objc_imageinfo,regular,no_dead_strip - .globl L_OBJC_IMAGE_INFO_f058a81939de2cb9 + .globl L_OBJC_IMAGE_INFO_4a8c690dbc9d8166 .p2align 2, 0x0 -L_OBJC_IMAGE_INFO_f058a81939de2cb9: +L_OBJC_IMAGE_INFO_4a8c690dbc9d8166: .asciz "\000\000\000\000@\000\000" .section __TEXT,__objc_methname,cstring_literals - .globl L_OBJC_METH_VAR_NAME_f058a81939de2cb9 -L_OBJC_METH_VAR_NAME_f058a81939de2cb9: + .globl L_OBJC_METH_VAR_NAME_4a8c690dbc9d8166 +L_OBJC_METH_VAR_NAME_4a8c690dbc9d8166: .asciz "copyWithZone:" .section __DATA,__objc_selrefs,literal_pointers,no_dead_strip - .globl L_OBJC_SELECTOR_REFERENCES_f058a81939de2cb9 + .globl L_OBJC_SELECTOR_REFERENCES_4a8c690dbc9d8166 .p2align 2, 0x0 -L_OBJC_SELECTOR_REFERENCES_f058a81939de2cb9: - .long L_OBJC_METH_VAR_NAME_f058a81939de2cb9 +L_OBJC_SELECTOR_REFERENCES_4a8c690dbc9d8166: + .long L_OBJC_METH_VAR_NAME_4a8c690dbc9d8166 .section __DATA,__nl_symbol_ptr,non_lazy_symbol_pointers .p2align 2, 0x0 diff --git a/crates/test-assembly/crates/test_declare_class/expected/apple-armv7s.s b/crates/test-assembly/crates/test_declare_class/expected/apple-armv7s.s index da99dfe97..3fbd8f431 100644 --- a/crates/test-assembly/crates/test_declare_class/expected/apple-armv7s.s +++ b/crates/test-assembly/crates/test_declare_class/expected/apple-armv7s.s @@ -100,8 +100,8 @@ LPC1_11: movw r11, :lower16:(_class_method-(LPC1_12+8)) mov r0, r4 movt r11, :upper16:(_class_method-(LPC1_12+8)) - movw r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_8dd788dbcc16b9bc-(LPC1_13+8)) - movt r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_8dd788dbcc16b9bc-(LPC1_13+8)) + movw r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_d874ee9262978be2-(LPC1_13+8)) + movt r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_d874ee9262978be2-(LPC1_13+8)) LPC1_12: add r11, pc, r11 LPC1_13: @@ -113,8 +113,8 @@ LPC1_13: movw r11, :lower16:(_method-(LPC1_14+8)) mov r0, r4 movt r11, :upper16:(_method-(LPC1_14+8)) - movw r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_450db9db0953dff5-(LPC1_15+8)) - movt r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_450db9db0953dff5-(LPC1_15+8)) + movw r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_4539fd1dbda0cddc-(LPC1_15+8)) + movt r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_4539fd1dbda0cddc-(LPC1_15+8)) LPC1_14: add r11, pc, r11 LPC1_15: @@ -126,8 +126,8 @@ LPC1_15: movw r3, :lower16:(_method_bool-(LPC1_16+8)) mov r0, r4 movt r3, :upper16:(_method_bool-(LPC1_16+8)) - movw r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_783b35bc45c6e4a6-(LPC1_17+8)) - movt r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_783b35bc45c6e4a6-(LPC1_17+8)) + movw r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_2b1b3a94e0ece2e5-(LPC1_17+8)) + movt r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_2b1b3a94e0ece2e5-(LPC1_17+8)) LPC1_16: add r3, pc, r3 LPC1_17: @@ -144,8 +144,8 @@ LPC1_18: movw r9, :lower16:(_method_id-(LPC1_19+8)) mov r0, r4 movt r9, :upper16:(_method_id-(LPC1_19+8)) - movw r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_828e9fbc6d0b4498-(LPC1_20+8)) - movt r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_828e9fbc6d0b4498-(LPC1_20+8)) + movw r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_f7f521670860b0ce-(LPC1_20+8)) + movt r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_f7f521670860b0ce-(LPC1_20+8)) LPC1_19: add r9, pc, r9 LPC1_20: @@ -157,8 +157,8 @@ LPC1_20: movw r9, :lower16:(_method_id_with_param-(LPC1_21+8)) mov r0, r4 movt r9, :upper16:(_method_id_with_param-(LPC1_21+8)) - movw r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_788cc14ba6a28eb8-(LPC1_22+8)) - movt r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_788cc14ba6a28eb8-(LPC1_22+8)) + movw r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_6addfcf634c6232f-(LPC1_22+8)) + movt r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_6addfcf634c6232f-(LPC1_22+8)) LPC1_21: add r9, pc, r9 LPC1_22: @@ -176,11 +176,11 @@ LPC1_23: mov r1, r0 mov r0, r4 bl SYM(objc2::__macro_helpers::::__add_protocol_methods::GENERATED_ID, 0) - movw r9, :lower16:(_copy_with_zone-(LPC1_24+8)) + movw r9, :lower16:(_copyWithZone-(LPC1_24+8)) mov r3, #1 - movt r9, :upper16:(_copy_with_zone-(LPC1_24+8)) - movw r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_f058a81939de2cb9-(LPC1_25+8)) - movt r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_f058a81939de2cb9-(LPC1_25+8)) + movt r9, :upper16:(_copyWithZone-(LPC1_24+8)) + movw r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_4a8c690dbc9d8166-(LPC1_25+8)) + movt r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_4a8c690dbc9d8166-(LPC1_25+8)) LPC1_24: add r9, pc, r9 LPC1_25: @@ -624,10 +624,10 @@ LBB14_5: bl _objc_autoreleaseReturnValue pop {r4, r5, r6, r7, pc} - .globl _copy_with_zone + .globl _copyWithZone .p2align 2 .code 32 -_copy_with_zone: +_copyWithZone: push {r4, r5, r6, r7, lr} add r7, sp, #12 push {r8, r10} @@ -780,7 +780,7 @@ l_anon.[ID].14: .p2align 2, 0x0 l_anon.[ID].15: .long l_anon.[ID].14 - .asciz "5\000\000\000\013\000\000\000\001\000\000" + .asciz "5\000\000\000\f\000\000\000\001\000\000" .section __TEXT,__const l_anon.[ID].16: @@ -810,106 +810,106 @@ l_anon.[ID].21: .asciz "\017\000\000" .section __DATA,__objc_imageinfo,regular,no_dead_strip - .globl L_OBJC_IMAGE_INFO_8dd788dbcc16b9bc + .globl L_OBJC_IMAGE_INFO_d874ee9262978be2 .p2align 2, 0x0 -L_OBJC_IMAGE_INFO_8dd788dbcc16b9bc: +L_OBJC_IMAGE_INFO_d874ee9262978be2: .asciz "\000\000\000\000@\000\000" .section __TEXT,__objc_methname,cstring_literals - .globl L_OBJC_METH_VAR_NAME_8dd788dbcc16b9bc -L_OBJC_METH_VAR_NAME_8dd788dbcc16b9bc: + .globl L_OBJC_METH_VAR_NAME_d874ee9262978be2 +L_OBJC_METH_VAR_NAME_d874ee9262978be2: .asciz "classMethod" .section __DATA,__objc_selrefs,literal_pointers,no_dead_strip - .globl L_OBJC_SELECTOR_REFERENCES_8dd788dbcc16b9bc + .globl L_OBJC_SELECTOR_REFERENCES_d874ee9262978be2 .p2align 2, 0x0 -L_OBJC_SELECTOR_REFERENCES_8dd788dbcc16b9bc: - .long L_OBJC_METH_VAR_NAME_8dd788dbcc16b9bc +L_OBJC_SELECTOR_REFERENCES_d874ee9262978be2: + .long L_OBJC_METH_VAR_NAME_d874ee9262978be2 .section __DATA,__objc_imageinfo,regular,no_dead_strip - .globl L_OBJC_IMAGE_INFO_450db9db0953dff5 + .globl L_OBJC_IMAGE_INFO_4539fd1dbda0cddc .p2align 2, 0x0 -L_OBJC_IMAGE_INFO_450db9db0953dff5: +L_OBJC_IMAGE_INFO_4539fd1dbda0cddc: .asciz "\000\000\000\000@\000\000" .section __TEXT,__objc_methname,cstring_literals - .globl L_OBJC_METH_VAR_NAME_450db9db0953dff5 -L_OBJC_METH_VAR_NAME_450db9db0953dff5: + .globl L_OBJC_METH_VAR_NAME_4539fd1dbda0cddc +L_OBJC_METH_VAR_NAME_4539fd1dbda0cddc: .asciz "method" .section __DATA,__objc_selrefs,literal_pointers,no_dead_strip - .globl L_OBJC_SELECTOR_REFERENCES_450db9db0953dff5 + .globl L_OBJC_SELECTOR_REFERENCES_4539fd1dbda0cddc .p2align 2, 0x0 -L_OBJC_SELECTOR_REFERENCES_450db9db0953dff5: - .long L_OBJC_METH_VAR_NAME_450db9db0953dff5 +L_OBJC_SELECTOR_REFERENCES_4539fd1dbda0cddc: + .long L_OBJC_METH_VAR_NAME_4539fd1dbda0cddc .section __DATA,__objc_imageinfo,regular,no_dead_strip - .globl L_OBJC_IMAGE_INFO_783b35bc45c6e4a6 + .globl L_OBJC_IMAGE_INFO_2b1b3a94e0ece2e5 .p2align 2, 0x0 -L_OBJC_IMAGE_INFO_783b35bc45c6e4a6: +L_OBJC_IMAGE_INFO_2b1b3a94e0ece2e5: .asciz "\000\000\000\000@\000\000" .section __TEXT,__objc_methname,cstring_literals - .globl L_OBJC_METH_VAR_NAME_783b35bc45c6e4a6 -L_OBJC_METH_VAR_NAME_783b35bc45c6e4a6: + .globl L_OBJC_METH_VAR_NAME_2b1b3a94e0ece2e5 +L_OBJC_METH_VAR_NAME_2b1b3a94e0ece2e5: .asciz "methodBool:" .section __DATA,__objc_selrefs,literal_pointers,no_dead_strip - .globl L_OBJC_SELECTOR_REFERENCES_783b35bc45c6e4a6 + .globl L_OBJC_SELECTOR_REFERENCES_2b1b3a94e0ece2e5 .p2align 2, 0x0 -L_OBJC_SELECTOR_REFERENCES_783b35bc45c6e4a6: - .long L_OBJC_METH_VAR_NAME_783b35bc45c6e4a6 +L_OBJC_SELECTOR_REFERENCES_2b1b3a94e0ece2e5: + .long L_OBJC_METH_VAR_NAME_2b1b3a94e0ece2e5 .section __DATA,__objc_imageinfo,regular,no_dead_strip - .globl L_OBJC_IMAGE_INFO_828e9fbc6d0b4498 + .globl L_OBJC_IMAGE_INFO_f7f521670860b0ce .p2align 2, 0x0 -L_OBJC_IMAGE_INFO_828e9fbc6d0b4498: +L_OBJC_IMAGE_INFO_f7f521670860b0ce: .asciz "\000\000\000\000@\000\000" .section __TEXT,__objc_methname,cstring_literals - .globl L_OBJC_METH_VAR_NAME_828e9fbc6d0b4498 -L_OBJC_METH_VAR_NAME_828e9fbc6d0b4498: + .globl L_OBJC_METH_VAR_NAME_f7f521670860b0ce +L_OBJC_METH_VAR_NAME_f7f521670860b0ce: .asciz "methodId" .section __DATA,__objc_selrefs,literal_pointers,no_dead_strip - .globl L_OBJC_SELECTOR_REFERENCES_828e9fbc6d0b4498 + .globl L_OBJC_SELECTOR_REFERENCES_f7f521670860b0ce .p2align 2, 0x0 -L_OBJC_SELECTOR_REFERENCES_828e9fbc6d0b4498: - .long L_OBJC_METH_VAR_NAME_828e9fbc6d0b4498 +L_OBJC_SELECTOR_REFERENCES_f7f521670860b0ce: + .long L_OBJC_METH_VAR_NAME_f7f521670860b0ce .section __DATA,__objc_imageinfo,regular,no_dead_strip - .globl L_OBJC_IMAGE_INFO_788cc14ba6a28eb8 + .globl L_OBJC_IMAGE_INFO_6addfcf634c6232f .p2align 2, 0x0 -L_OBJC_IMAGE_INFO_788cc14ba6a28eb8: +L_OBJC_IMAGE_INFO_6addfcf634c6232f: .asciz "\000\000\000\000@\000\000" .section __TEXT,__objc_methname,cstring_literals - .globl L_OBJC_METH_VAR_NAME_788cc14ba6a28eb8 -L_OBJC_METH_VAR_NAME_788cc14ba6a28eb8: + .globl L_OBJC_METH_VAR_NAME_6addfcf634c6232f +L_OBJC_METH_VAR_NAME_6addfcf634c6232f: .asciz "methodIdWithParam:" .section __DATA,__objc_selrefs,literal_pointers,no_dead_strip - .globl L_OBJC_SELECTOR_REFERENCES_788cc14ba6a28eb8 + .globl L_OBJC_SELECTOR_REFERENCES_6addfcf634c6232f .p2align 2, 0x0 -L_OBJC_SELECTOR_REFERENCES_788cc14ba6a28eb8: - .long L_OBJC_METH_VAR_NAME_788cc14ba6a28eb8 +L_OBJC_SELECTOR_REFERENCES_6addfcf634c6232f: + .long L_OBJC_METH_VAR_NAME_6addfcf634c6232f .section __DATA,__objc_imageinfo,regular,no_dead_strip - .globl L_OBJC_IMAGE_INFO_f058a81939de2cb9 + .globl L_OBJC_IMAGE_INFO_4a8c690dbc9d8166 .p2align 2, 0x0 -L_OBJC_IMAGE_INFO_f058a81939de2cb9: +L_OBJC_IMAGE_INFO_4a8c690dbc9d8166: .asciz "\000\000\000\000@\000\000" .section __TEXT,__objc_methname,cstring_literals - .globl L_OBJC_METH_VAR_NAME_f058a81939de2cb9 -L_OBJC_METH_VAR_NAME_f058a81939de2cb9: + .globl L_OBJC_METH_VAR_NAME_4a8c690dbc9d8166 +L_OBJC_METH_VAR_NAME_4a8c690dbc9d8166: .asciz "copyWithZone:" .section __DATA,__objc_selrefs,literal_pointers,no_dead_strip - .globl L_OBJC_SELECTOR_REFERENCES_f058a81939de2cb9 + .globl L_OBJC_SELECTOR_REFERENCES_4a8c690dbc9d8166 .p2align 2, 0x0 -L_OBJC_SELECTOR_REFERENCES_f058a81939de2cb9: - .long L_OBJC_METH_VAR_NAME_f058a81939de2cb9 +L_OBJC_SELECTOR_REFERENCES_4a8c690dbc9d8166: + .long L_OBJC_METH_VAR_NAME_4a8c690dbc9d8166 .section __DATA,__nl_symbol_ptr,non_lazy_symbol_pointers .p2align 2, 0x0 diff --git a/crates/test-assembly/crates/test_declare_class/expected/apple-old-x86.s b/crates/test-assembly/crates/test_declare_class/expected/apple-old-x86.s index 8226e0df6..ee414d41d 100644 --- a/crates/test-assembly/crates/test_declare_class/expected/apple-old-x86.s +++ b/crates/test-assembly/crates/test_declare_class/expected/apple-old-x86.s @@ -88,7 +88,7 @@ L1$pb: push eax push 0 push edi - push dword ptr [esi + L_OBJC_SELECTOR_REFERENCES_8dd788dbcc16b9bc-L1$pb] + push dword ptr [esi + L_OBJC_SELECTOR_REFERENCES_d874ee9262978be2-L1$pb] push ebx call SYM(objc2::declare::ClassBuilder::add_class_method_inner::GENERATED_ID, 0) add esp, 24 @@ -98,7 +98,7 @@ L1$pb: push eax push 0 push edi - push dword ptr [esi + L_OBJC_SELECTOR_REFERENCES_450db9db0953dff5-L1$pb] + push dword ptr [esi + L_OBJC_SELECTOR_REFERENCES_4539fd1dbda0cddc-L1$pb] push ebx call SYM(objc2::declare::ClassBuilder::add_method_inner::GENERATED_ID, 0) add esp, 24 @@ -108,7 +108,7 @@ L1$pb: push ecx push 1 push ecx - push dword ptr [esi + L_OBJC_SELECTOR_REFERENCES_783b35bc45c6e4a6-L1$pb] + push dword ptr [esi + L_OBJC_SELECTOR_REFERENCES_2b1b3a94e0ece2e5-L1$pb] push ebx call SYM(objc2::declare::ClassBuilder::add_method_inner::GENERATED_ID, 0) add esp, 24 @@ -119,7 +119,7 @@ L1$pb: push 0 lea eax, [esi + l_anon.[ID].1-L1$pb] push eax - push dword ptr [esi + L_OBJC_SELECTOR_REFERENCES_828e9fbc6d0b4498-L1$pb] + push dword ptr [esi + L_OBJC_SELECTOR_REFERENCES_f7f521670860b0ce-L1$pb] push ebx call SYM(objc2::declare::ClassBuilder::add_method_inner::GENERATED_ID, 0) add esp, 24 @@ -129,7 +129,7 @@ L1$pb: push 1 lea eax, [esi + l_anon.[ID].4-L1$pb] push eax - push dword ptr [esi + L_OBJC_SELECTOR_REFERENCES_788cc14ba6a28eb8-L1$pb] + push dword ptr [esi + L_OBJC_SELECTOR_REFERENCES_6addfcf634c6232f-L1$pb] push ebx call SYM(objc2::declare::ClassBuilder::add_method_inner::GENERATED_ID, 0) add esp, 24 @@ -142,13 +142,13 @@ L1$pb: push ebx call SYM(objc2::__macro_helpers::::__add_protocol_methods::GENERATED_ID, 0) add esp, 8 - lea ecx, [esi + _copy_with_zone-L1$pb] + lea ecx, [esi + _copyWithZone-L1$pb] lea edx, [esi + l_anon.[ID].7-L1$pb] push ecx push edi push 1 push edx - push dword ptr [esi + L_OBJC_SELECTOR_REFERENCES_f058a81939de2cb9-L1$pb] + push dword ptr [esi + L_OBJC_SELECTOR_REFERENCES_4a8c690dbc9d8166-L1$pb] push eax call SYM(objc2::declare::ClassBuilder::add_method_inner::GENERATED_ID, 0) add esp, 20 @@ -629,9 +629,9 @@ LBB14_5: pop ebp ret - .globl _copy_with_zone + .globl _copyWithZone .p2align 4, 0x90 -_copy_with_zone: +_copyWithZone: push ebp mov ebp, esp push ebx @@ -802,7 +802,7 @@ l_anon.[ID].14: .p2align 2, 0x0 l_anon.[ID].15: .long l_anon.[ID].14 - .asciz "5\000\000\000\013\000\000\000\001\000\000" + .asciz "5\000\000\000\f\000\000\000\001\000\000" .section __TEXT,__const l_anon.[ID].16: @@ -832,106 +832,106 @@ l_anon.[ID].21: .asciz "\017\000\000" .section __OBJC,__image_info - .globl L_OBJC_IMAGE_INFO_8dd788dbcc16b9bc + .globl L_OBJC_IMAGE_INFO_d874ee9262978be2 .p2align 2, 0x0 -L_OBJC_IMAGE_INFO_8dd788dbcc16b9bc: +L_OBJC_IMAGE_INFO_d874ee9262978be2: .asciz "\000\000\000\000@\000\000" .section __TEXT,__cstring,cstring_literals - .globl L_OBJC_METH_VAR_NAME_8dd788dbcc16b9bc -L_OBJC_METH_VAR_NAME_8dd788dbcc16b9bc: + .globl L_OBJC_METH_VAR_NAME_d874ee9262978be2 +L_OBJC_METH_VAR_NAME_d874ee9262978be2: .asciz "classMethod" .section __OBJC,__message_refs,literal_pointers,no_dead_strip - .globl L_OBJC_SELECTOR_REFERENCES_8dd788dbcc16b9bc + .globl L_OBJC_SELECTOR_REFERENCES_d874ee9262978be2 .p2align 2, 0x0 -L_OBJC_SELECTOR_REFERENCES_8dd788dbcc16b9bc: - .long L_OBJC_METH_VAR_NAME_8dd788dbcc16b9bc +L_OBJC_SELECTOR_REFERENCES_d874ee9262978be2: + .long L_OBJC_METH_VAR_NAME_d874ee9262978be2 .section __OBJC,__image_info - .globl L_OBJC_IMAGE_INFO_450db9db0953dff5 + .globl L_OBJC_IMAGE_INFO_4539fd1dbda0cddc .p2align 2, 0x0 -L_OBJC_IMAGE_INFO_450db9db0953dff5: +L_OBJC_IMAGE_INFO_4539fd1dbda0cddc: .asciz "\000\000\000\000@\000\000" .section __TEXT,__cstring,cstring_literals - .globl L_OBJC_METH_VAR_NAME_450db9db0953dff5 -L_OBJC_METH_VAR_NAME_450db9db0953dff5: + .globl L_OBJC_METH_VAR_NAME_4539fd1dbda0cddc +L_OBJC_METH_VAR_NAME_4539fd1dbda0cddc: .asciz "method" .section __OBJC,__message_refs,literal_pointers,no_dead_strip - .globl L_OBJC_SELECTOR_REFERENCES_450db9db0953dff5 + .globl L_OBJC_SELECTOR_REFERENCES_4539fd1dbda0cddc .p2align 2, 0x0 -L_OBJC_SELECTOR_REFERENCES_450db9db0953dff5: - .long L_OBJC_METH_VAR_NAME_450db9db0953dff5 +L_OBJC_SELECTOR_REFERENCES_4539fd1dbda0cddc: + .long L_OBJC_METH_VAR_NAME_4539fd1dbda0cddc .section __OBJC,__image_info - .globl L_OBJC_IMAGE_INFO_783b35bc45c6e4a6 + .globl L_OBJC_IMAGE_INFO_2b1b3a94e0ece2e5 .p2align 2, 0x0 -L_OBJC_IMAGE_INFO_783b35bc45c6e4a6: +L_OBJC_IMAGE_INFO_2b1b3a94e0ece2e5: .asciz "\000\000\000\000@\000\000" .section __TEXT,__cstring,cstring_literals - .globl L_OBJC_METH_VAR_NAME_783b35bc45c6e4a6 -L_OBJC_METH_VAR_NAME_783b35bc45c6e4a6: + .globl L_OBJC_METH_VAR_NAME_2b1b3a94e0ece2e5 +L_OBJC_METH_VAR_NAME_2b1b3a94e0ece2e5: .asciz "methodBool:" .section __OBJC,__message_refs,literal_pointers,no_dead_strip - .globl L_OBJC_SELECTOR_REFERENCES_783b35bc45c6e4a6 + .globl L_OBJC_SELECTOR_REFERENCES_2b1b3a94e0ece2e5 .p2align 2, 0x0 -L_OBJC_SELECTOR_REFERENCES_783b35bc45c6e4a6: - .long L_OBJC_METH_VAR_NAME_783b35bc45c6e4a6 +L_OBJC_SELECTOR_REFERENCES_2b1b3a94e0ece2e5: + .long L_OBJC_METH_VAR_NAME_2b1b3a94e0ece2e5 .section __OBJC,__image_info - .globl L_OBJC_IMAGE_INFO_828e9fbc6d0b4498 + .globl L_OBJC_IMAGE_INFO_f7f521670860b0ce .p2align 2, 0x0 -L_OBJC_IMAGE_INFO_828e9fbc6d0b4498: +L_OBJC_IMAGE_INFO_f7f521670860b0ce: .asciz "\000\000\000\000@\000\000" .section __TEXT,__cstring,cstring_literals - .globl L_OBJC_METH_VAR_NAME_828e9fbc6d0b4498 -L_OBJC_METH_VAR_NAME_828e9fbc6d0b4498: + .globl L_OBJC_METH_VAR_NAME_f7f521670860b0ce +L_OBJC_METH_VAR_NAME_f7f521670860b0ce: .asciz "methodId" .section __OBJC,__message_refs,literal_pointers,no_dead_strip - .globl L_OBJC_SELECTOR_REFERENCES_828e9fbc6d0b4498 + .globl L_OBJC_SELECTOR_REFERENCES_f7f521670860b0ce .p2align 2, 0x0 -L_OBJC_SELECTOR_REFERENCES_828e9fbc6d0b4498: - .long L_OBJC_METH_VAR_NAME_828e9fbc6d0b4498 +L_OBJC_SELECTOR_REFERENCES_f7f521670860b0ce: + .long L_OBJC_METH_VAR_NAME_f7f521670860b0ce .section __OBJC,__image_info - .globl L_OBJC_IMAGE_INFO_788cc14ba6a28eb8 + .globl L_OBJC_IMAGE_INFO_6addfcf634c6232f .p2align 2, 0x0 -L_OBJC_IMAGE_INFO_788cc14ba6a28eb8: +L_OBJC_IMAGE_INFO_6addfcf634c6232f: .asciz "\000\000\000\000@\000\000" .section __TEXT,__cstring,cstring_literals - .globl L_OBJC_METH_VAR_NAME_788cc14ba6a28eb8 -L_OBJC_METH_VAR_NAME_788cc14ba6a28eb8: + .globl L_OBJC_METH_VAR_NAME_6addfcf634c6232f +L_OBJC_METH_VAR_NAME_6addfcf634c6232f: .asciz "methodIdWithParam:" .section __OBJC,__message_refs,literal_pointers,no_dead_strip - .globl L_OBJC_SELECTOR_REFERENCES_788cc14ba6a28eb8 + .globl L_OBJC_SELECTOR_REFERENCES_6addfcf634c6232f .p2align 2, 0x0 -L_OBJC_SELECTOR_REFERENCES_788cc14ba6a28eb8: - .long L_OBJC_METH_VAR_NAME_788cc14ba6a28eb8 +L_OBJC_SELECTOR_REFERENCES_6addfcf634c6232f: + .long L_OBJC_METH_VAR_NAME_6addfcf634c6232f .section __OBJC,__image_info - .globl L_OBJC_IMAGE_INFO_f058a81939de2cb9 + .globl L_OBJC_IMAGE_INFO_4a8c690dbc9d8166 .p2align 2, 0x0 -L_OBJC_IMAGE_INFO_f058a81939de2cb9: +L_OBJC_IMAGE_INFO_4a8c690dbc9d8166: .asciz "\000\000\000\000@\000\000" .section __TEXT,__cstring,cstring_literals - .globl L_OBJC_METH_VAR_NAME_f058a81939de2cb9 -L_OBJC_METH_VAR_NAME_f058a81939de2cb9: + .globl L_OBJC_METH_VAR_NAME_4a8c690dbc9d8166 +L_OBJC_METH_VAR_NAME_4a8c690dbc9d8166: .asciz "copyWithZone:" .section __OBJC,__message_refs,literal_pointers,no_dead_strip - .globl L_OBJC_SELECTOR_REFERENCES_f058a81939de2cb9 + .globl L_OBJC_SELECTOR_REFERENCES_4a8c690dbc9d8166 .p2align 2, 0x0 -L_OBJC_SELECTOR_REFERENCES_f058a81939de2cb9: - .long L_OBJC_METH_VAR_NAME_f058a81939de2cb9 +L_OBJC_SELECTOR_REFERENCES_4a8c690dbc9d8166: + .long L_OBJC_METH_VAR_NAME_4a8c690dbc9d8166 .section __IMPORT,__pointers,non_lazy_symbol_pointers LL_OBJC_CLASS_REFERENCES_NSObject$non_lazy_ptr: diff --git a/crates/test-assembly/crates/test_declare_class/expected/apple-x86.s b/crates/test-assembly/crates/test_declare_class/expected/apple-x86.s index 79f70b9c1..fecce8d74 100644 --- a/crates/test-assembly/crates/test_declare_class/expected/apple-x86.s +++ b/crates/test-assembly/crates/test_declare_class/expected/apple-x86.s @@ -88,7 +88,7 @@ L1$pb: push eax push 0 push edi - push dword ptr [esi + L_OBJC_SELECTOR_REFERENCES_8dd788dbcc16b9bc-L1$pb] + push dword ptr [esi + L_OBJC_SELECTOR_REFERENCES_d874ee9262978be2-L1$pb] push ebx call SYM(objc2::declare::ClassBuilder::add_class_method_inner::GENERATED_ID, 0) add esp, 24 @@ -98,7 +98,7 @@ L1$pb: push eax push 0 push edi - push dword ptr [esi + L_OBJC_SELECTOR_REFERENCES_450db9db0953dff5-L1$pb] + push dword ptr [esi + L_OBJC_SELECTOR_REFERENCES_4539fd1dbda0cddc-L1$pb] push ebx call SYM(objc2::declare::ClassBuilder::add_method_inner::GENERATED_ID, 0) add esp, 24 @@ -108,7 +108,7 @@ L1$pb: push ecx push 1 push ecx - push dword ptr [esi + L_OBJC_SELECTOR_REFERENCES_783b35bc45c6e4a6-L1$pb] + push dword ptr [esi + L_OBJC_SELECTOR_REFERENCES_2b1b3a94e0ece2e5-L1$pb] push ebx call SYM(objc2::declare::ClassBuilder::add_method_inner::GENERATED_ID, 0) add esp, 24 @@ -119,7 +119,7 @@ L1$pb: push 0 lea eax, [esi + l_anon.[ID].1-L1$pb] push eax - push dword ptr [esi + L_OBJC_SELECTOR_REFERENCES_828e9fbc6d0b4498-L1$pb] + push dword ptr [esi + L_OBJC_SELECTOR_REFERENCES_f7f521670860b0ce-L1$pb] push ebx call SYM(objc2::declare::ClassBuilder::add_method_inner::GENERATED_ID, 0) add esp, 24 @@ -129,7 +129,7 @@ L1$pb: push 1 lea eax, [esi + l_anon.[ID].4-L1$pb] push eax - push dword ptr [esi + L_OBJC_SELECTOR_REFERENCES_788cc14ba6a28eb8-L1$pb] + push dword ptr [esi + L_OBJC_SELECTOR_REFERENCES_6addfcf634c6232f-L1$pb] push ebx call SYM(objc2::declare::ClassBuilder::add_method_inner::GENERATED_ID, 0) add esp, 24 @@ -142,13 +142,13 @@ L1$pb: push ebx call SYM(objc2::__macro_helpers::::__add_protocol_methods::GENERATED_ID, 0) add esp, 8 - lea ecx, [esi + _copy_with_zone-L1$pb] + lea ecx, [esi + _copyWithZone-L1$pb] lea edx, [esi + l_anon.[ID].7-L1$pb] push ecx push edi push 1 push edx - push dword ptr [esi + L_OBJC_SELECTOR_REFERENCES_f058a81939de2cb9-L1$pb] + push dword ptr [esi + L_OBJC_SELECTOR_REFERENCES_4a8c690dbc9d8166-L1$pb] push eax call SYM(objc2::declare::ClassBuilder::add_method_inner::GENERATED_ID, 0) add esp, 20 @@ -629,9 +629,9 @@ LBB14_5: pop ebp ret - .globl _copy_with_zone + .globl _copyWithZone .p2align 4, 0x90 -_copy_with_zone: +_copyWithZone: push ebp mov ebp, esp push ebx @@ -802,7 +802,7 @@ l_anon.[ID].14: .p2align 2, 0x0 l_anon.[ID].15: .long l_anon.[ID].14 - .asciz "5\000\000\000\013\000\000\000\001\000\000" + .asciz "5\000\000\000\f\000\000\000\001\000\000" .section __TEXT,__const l_anon.[ID].16: @@ -832,106 +832,106 @@ l_anon.[ID].21: .asciz "\017\000\000" .section __DATA,__objc_imageinfo,regular,no_dead_strip - .globl L_OBJC_IMAGE_INFO_8dd788dbcc16b9bc + .globl L_OBJC_IMAGE_INFO_d874ee9262978be2 .p2align 2, 0x0 -L_OBJC_IMAGE_INFO_8dd788dbcc16b9bc: +L_OBJC_IMAGE_INFO_d874ee9262978be2: .asciz "\000\000\000\000@\000\000" .section __TEXT,__objc_methname,cstring_literals - .globl L_OBJC_METH_VAR_NAME_8dd788dbcc16b9bc -L_OBJC_METH_VAR_NAME_8dd788dbcc16b9bc: + .globl L_OBJC_METH_VAR_NAME_d874ee9262978be2 +L_OBJC_METH_VAR_NAME_d874ee9262978be2: .asciz "classMethod" .section __DATA,__objc_selrefs,literal_pointers,no_dead_strip - .globl L_OBJC_SELECTOR_REFERENCES_8dd788dbcc16b9bc + .globl L_OBJC_SELECTOR_REFERENCES_d874ee9262978be2 .p2align 2, 0x0 -L_OBJC_SELECTOR_REFERENCES_8dd788dbcc16b9bc: - .long L_OBJC_METH_VAR_NAME_8dd788dbcc16b9bc +L_OBJC_SELECTOR_REFERENCES_d874ee9262978be2: + .long L_OBJC_METH_VAR_NAME_d874ee9262978be2 .section __DATA,__objc_imageinfo,regular,no_dead_strip - .globl L_OBJC_IMAGE_INFO_450db9db0953dff5 + .globl L_OBJC_IMAGE_INFO_4539fd1dbda0cddc .p2align 2, 0x0 -L_OBJC_IMAGE_INFO_450db9db0953dff5: +L_OBJC_IMAGE_INFO_4539fd1dbda0cddc: .asciz "\000\000\000\000@\000\000" .section __TEXT,__objc_methname,cstring_literals - .globl L_OBJC_METH_VAR_NAME_450db9db0953dff5 -L_OBJC_METH_VAR_NAME_450db9db0953dff5: + .globl L_OBJC_METH_VAR_NAME_4539fd1dbda0cddc +L_OBJC_METH_VAR_NAME_4539fd1dbda0cddc: .asciz "method" .section __DATA,__objc_selrefs,literal_pointers,no_dead_strip - .globl L_OBJC_SELECTOR_REFERENCES_450db9db0953dff5 + .globl L_OBJC_SELECTOR_REFERENCES_4539fd1dbda0cddc .p2align 2, 0x0 -L_OBJC_SELECTOR_REFERENCES_450db9db0953dff5: - .long L_OBJC_METH_VAR_NAME_450db9db0953dff5 +L_OBJC_SELECTOR_REFERENCES_4539fd1dbda0cddc: + .long L_OBJC_METH_VAR_NAME_4539fd1dbda0cddc .section __DATA,__objc_imageinfo,regular,no_dead_strip - .globl L_OBJC_IMAGE_INFO_783b35bc45c6e4a6 + .globl L_OBJC_IMAGE_INFO_2b1b3a94e0ece2e5 .p2align 2, 0x0 -L_OBJC_IMAGE_INFO_783b35bc45c6e4a6: +L_OBJC_IMAGE_INFO_2b1b3a94e0ece2e5: .asciz "\000\000\000\000@\000\000" .section __TEXT,__objc_methname,cstring_literals - .globl L_OBJC_METH_VAR_NAME_783b35bc45c6e4a6 -L_OBJC_METH_VAR_NAME_783b35bc45c6e4a6: + .globl L_OBJC_METH_VAR_NAME_2b1b3a94e0ece2e5 +L_OBJC_METH_VAR_NAME_2b1b3a94e0ece2e5: .asciz "methodBool:" .section __DATA,__objc_selrefs,literal_pointers,no_dead_strip - .globl L_OBJC_SELECTOR_REFERENCES_783b35bc45c6e4a6 + .globl L_OBJC_SELECTOR_REFERENCES_2b1b3a94e0ece2e5 .p2align 2, 0x0 -L_OBJC_SELECTOR_REFERENCES_783b35bc45c6e4a6: - .long L_OBJC_METH_VAR_NAME_783b35bc45c6e4a6 +L_OBJC_SELECTOR_REFERENCES_2b1b3a94e0ece2e5: + .long L_OBJC_METH_VAR_NAME_2b1b3a94e0ece2e5 .section __DATA,__objc_imageinfo,regular,no_dead_strip - .globl L_OBJC_IMAGE_INFO_828e9fbc6d0b4498 + .globl L_OBJC_IMAGE_INFO_f7f521670860b0ce .p2align 2, 0x0 -L_OBJC_IMAGE_INFO_828e9fbc6d0b4498: +L_OBJC_IMAGE_INFO_f7f521670860b0ce: .asciz "\000\000\000\000@\000\000" .section __TEXT,__objc_methname,cstring_literals - .globl L_OBJC_METH_VAR_NAME_828e9fbc6d0b4498 -L_OBJC_METH_VAR_NAME_828e9fbc6d0b4498: + .globl L_OBJC_METH_VAR_NAME_f7f521670860b0ce +L_OBJC_METH_VAR_NAME_f7f521670860b0ce: .asciz "methodId" .section __DATA,__objc_selrefs,literal_pointers,no_dead_strip - .globl L_OBJC_SELECTOR_REFERENCES_828e9fbc6d0b4498 + .globl L_OBJC_SELECTOR_REFERENCES_f7f521670860b0ce .p2align 2, 0x0 -L_OBJC_SELECTOR_REFERENCES_828e9fbc6d0b4498: - .long L_OBJC_METH_VAR_NAME_828e9fbc6d0b4498 +L_OBJC_SELECTOR_REFERENCES_f7f521670860b0ce: + .long L_OBJC_METH_VAR_NAME_f7f521670860b0ce .section __DATA,__objc_imageinfo,regular,no_dead_strip - .globl L_OBJC_IMAGE_INFO_788cc14ba6a28eb8 + .globl L_OBJC_IMAGE_INFO_6addfcf634c6232f .p2align 2, 0x0 -L_OBJC_IMAGE_INFO_788cc14ba6a28eb8: +L_OBJC_IMAGE_INFO_6addfcf634c6232f: .asciz "\000\000\000\000@\000\000" .section __TEXT,__objc_methname,cstring_literals - .globl L_OBJC_METH_VAR_NAME_788cc14ba6a28eb8 -L_OBJC_METH_VAR_NAME_788cc14ba6a28eb8: + .globl L_OBJC_METH_VAR_NAME_6addfcf634c6232f +L_OBJC_METH_VAR_NAME_6addfcf634c6232f: .asciz "methodIdWithParam:" .section __DATA,__objc_selrefs,literal_pointers,no_dead_strip - .globl L_OBJC_SELECTOR_REFERENCES_788cc14ba6a28eb8 + .globl L_OBJC_SELECTOR_REFERENCES_6addfcf634c6232f .p2align 2, 0x0 -L_OBJC_SELECTOR_REFERENCES_788cc14ba6a28eb8: - .long L_OBJC_METH_VAR_NAME_788cc14ba6a28eb8 +L_OBJC_SELECTOR_REFERENCES_6addfcf634c6232f: + .long L_OBJC_METH_VAR_NAME_6addfcf634c6232f .section __DATA,__objc_imageinfo,regular,no_dead_strip - .globl L_OBJC_IMAGE_INFO_f058a81939de2cb9 + .globl L_OBJC_IMAGE_INFO_4a8c690dbc9d8166 .p2align 2, 0x0 -L_OBJC_IMAGE_INFO_f058a81939de2cb9: +L_OBJC_IMAGE_INFO_4a8c690dbc9d8166: .asciz "\000\000\000\000@\000\000" .section __TEXT,__objc_methname,cstring_literals - .globl L_OBJC_METH_VAR_NAME_f058a81939de2cb9 -L_OBJC_METH_VAR_NAME_f058a81939de2cb9: + .globl L_OBJC_METH_VAR_NAME_4a8c690dbc9d8166 +L_OBJC_METH_VAR_NAME_4a8c690dbc9d8166: .asciz "copyWithZone:" .section __DATA,__objc_selrefs,literal_pointers,no_dead_strip - .globl L_OBJC_SELECTOR_REFERENCES_f058a81939de2cb9 + .globl L_OBJC_SELECTOR_REFERENCES_4a8c690dbc9d8166 .p2align 2, 0x0 -L_OBJC_SELECTOR_REFERENCES_f058a81939de2cb9: - .long L_OBJC_METH_VAR_NAME_f058a81939de2cb9 +L_OBJC_SELECTOR_REFERENCES_4a8c690dbc9d8166: + .long L_OBJC_METH_VAR_NAME_4a8c690dbc9d8166 .section __IMPORT,__pointers,non_lazy_symbol_pointers LL_OBJC_CLASSLIST_REFERENCES_$_NSObject$non_lazy_ptr: diff --git a/crates/test-assembly/crates/test_declare_class/expected/apple-x86_64.s b/crates/test-assembly/crates/test_declare_class/expected/apple-x86_64.s index e0e3d301f..824f146dd 100644 --- a/crates/test-assembly/crates/test_declare_class/expected/apple-x86_64.s +++ b/crates/test-assembly/crates/test_declare_class/expected/apple-x86_64.s @@ -62,21 +62,21 @@ SYM(::call_once::<::call_once::<::call_once::<::__add_protocol_methods::GENERATED_ID, 0) - mov rsi, qword ptr [rip + L_OBJC_SELECTOR_REFERENCES_f058a81939de2cb9] + mov rsi, qword ptr [rip + L_OBJC_SELECTOR_REFERENCES_4a8c690dbc9d8166] lea rdx, [rip + l_anon.[ID].7] - lea r9, [rip + _copy_with_zone] + lea r9, [rip + _copyWithZone] mov ecx, 1 mov rdi, rax mov r8, r14 @@ -464,9 +464,9 @@ LBB14_5: pop rbp jmp _objc_autoreleaseReturnValue - .globl _copy_with_zone + .globl _copyWithZone .p2align 4, 0x90 -_copy_with_zone: +_copyWithZone: push rbp mov rbp, rsp push r15 @@ -616,7 +616,7 @@ l_anon.[ID].14: .p2align 3, 0x0 l_anon.[ID].15: .quad l_anon.[ID].14 - .asciz "5\000\000\000\000\000\000\000\013\000\000\000\001\000\000" + .asciz "5\000\000\000\000\000\000\000\f\000\000\000\001\000\000" .section __TEXT,__const l_anon.[ID].16: @@ -646,105 +646,105 @@ l_anon.[ID].21: .asciz "\017\000\000\000\000\000\000" .section __DATA,__objc_imageinfo,regular,no_dead_strip - .globl L_OBJC_IMAGE_INFO_8dd788dbcc16b9bc + .globl L_OBJC_IMAGE_INFO_d874ee9262978be2 .p2align 2, 0x0 -L_OBJC_IMAGE_INFO_8dd788dbcc16b9bc: +L_OBJC_IMAGE_INFO_d874ee9262978be2: .asciz "\000\000\000\000@\000\000" .section __TEXT,__objc_methname,cstring_literals - .globl L_OBJC_METH_VAR_NAME_8dd788dbcc16b9bc -L_OBJC_METH_VAR_NAME_8dd788dbcc16b9bc: + .globl L_OBJC_METH_VAR_NAME_d874ee9262978be2 +L_OBJC_METH_VAR_NAME_d874ee9262978be2: .asciz "classMethod" .section __DATA,__objc_selrefs,literal_pointers,no_dead_strip - .globl L_OBJC_SELECTOR_REFERENCES_8dd788dbcc16b9bc + .globl L_OBJC_SELECTOR_REFERENCES_d874ee9262978be2 .p2align 3, 0x0 -L_OBJC_SELECTOR_REFERENCES_8dd788dbcc16b9bc: - .quad L_OBJC_METH_VAR_NAME_8dd788dbcc16b9bc +L_OBJC_SELECTOR_REFERENCES_d874ee9262978be2: + .quad L_OBJC_METH_VAR_NAME_d874ee9262978be2 .section __DATA,__objc_imageinfo,regular,no_dead_strip - .globl L_OBJC_IMAGE_INFO_450db9db0953dff5 + .globl L_OBJC_IMAGE_INFO_4539fd1dbda0cddc .p2align 2, 0x0 -L_OBJC_IMAGE_INFO_450db9db0953dff5: +L_OBJC_IMAGE_INFO_4539fd1dbda0cddc: .asciz "\000\000\000\000@\000\000" .section __TEXT,__objc_methname,cstring_literals - .globl L_OBJC_METH_VAR_NAME_450db9db0953dff5 -L_OBJC_METH_VAR_NAME_450db9db0953dff5: + .globl L_OBJC_METH_VAR_NAME_4539fd1dbda0cddc +L_OBJC_METH_VAR_NAME_4539fd1dbda0cddc: .asciz "method" .section __DATA,__objc_selrefs,literal_pointers,no_dead_strip - .globl L_OBJC_SELECTOR_REFERENCES_450db9db0953dff5 + .globl L_OBJC_SELECTOR_REFERENCES_4539fd1dbda0cddc .p2align 3, 0x0 -L_OBJC_SELECTOR_REFERENCES_450db9db0953dff5: - .quad L_OBJC_METH_VAR_NAME_450db9db0953dff5 +L_OBJC_SELECTOR_REFERENCES_4539fd1dbda0cddc: + .quad L_OBJC_METH_VAR_NAME_4539fd1dbda0cddc .section __DATA,__objc_imageinfo,regular,no_dead_strip - .globl L_OBJC_IMAGE_INFO_783b35bc45c6e4a6 + .globl L_OBJC_IMAGE_INFO_2b1b3a94e0ece2e5 .p2align 2, 0x0 -L_OBJC_IMAGE_INFO_783b35bc45c6e4a6: +L_OBJC_IMAGE_INFO_2b1b3a94e0ece2e5: .asciz "\000\000\000\000@\000\000" .section __TEXT,__objc_methname,cstring_literals - .globl L_OBJC_METH_VAR_NAME_783b35bc45c6e4a6 -L_OBJC_METH_VAR_NAME_783b35bc45c6e4a6: + .globl L_OBJC_METH_VAR_NAME_2b1b3a94e0ece2e5 +L_OBJC_METH_VAR_NAME_2b1b3a94e0ece2e5: .asciz "methodBool:" .section __DATA,__objc_selrefs,literal_pointers,no_dead_strip - .globl L_OBJC_SELECTOR_REFERENCES_783b35bc45c6e4a6 + .globl L_OBJC_SELECTOR_REFERENCES_2b1b3a94e0ece2e5 .p2align 3, 0x0 -L_OBJC_SELECTOR_REFERENCES_783b35bc45c6e4a6: - .quad L_OBJC_METH_VAR_NAME_783b35bc45c6e4a6 +L_OBJC_SELECTOR_REFERENCES_2b1b3a94e0ece2e5: + .quad L_OBJC_METH_VAR_NAME_2b1b3a94e0ece2e5 .section __DATA,__objc_imageinfo,regular,no_dead_strip - .globl L_OBJC_IMAGE_INFO_828e9fbc6d0b4498 + .globl L_OBJC_IMAGE_INFO_f7f521670860b0ce .p2align 2, 0x0 -L_OBJC_IMAGE_INFO_828e9fbc6d0b4498: +L_OBJC_IMAGE_INFO_f7f521670860b0ce: .asciz "\000\000\000\000@\000\000" .section __TEXT,__objc_methname,cstring_literals - .globl L_OBJC_METH_VAR_NAME_828e9fbc6d0b4498 -L_OBJC_METH_VAR_NAME_828e9fbc6d0b4498: + .globl L_OBJC_METH_VAR_NAME_f7f521670860b0ce +L_OBJC_METH_VAR_NAME_f7f521670860b0ce: .asciz "methodId" .section __DATA,__objc_selrefs,literal_pointers,no_dead_strip - .globl L_OBJC_SELECTOR_REFERENCES_828e9fbc6d0b4498 + .globl L_OBJC_SELECTOR_REFERENCES_f7f521670860b0ce .p2align 3, 0x0 -L_OBJC_SELECTOR_REFERENCES_828e9fbc6d0b4498: - .quad L_OBJC_METH_VAR_NAME_828e9fbc6d0b4498 +L_OBJC_SELECTOR_REFERENCES_f7f521670860b0ce: + .quad L_OBJC_METH_VAR_NAME_f7f521670860b0ce .section __DATA,__objc_imageinfo,regular,no_dead_strip - .globl L_OBJC_IMAGE_INFO_788cc14ba6a28eb8 + .globl L_OBJC_IMAGE_INFO_6addfcf634c6232f .p2align 2, 0x0 -L_OBJC_IMAGE_INFO_788cc14ba6a28eb8: +L_OBJC_IMAGE_INFO_6addfcf634c6232f: .asciz "\000\000\000\000@\000\000" .section __TEXT,__objc_methname,cstring_literals - .globl L_OBJC_METH_VAR_NAME_788cc14ba6a28eb8 -L_OBJC_METH_VAR_NAME_788cc14ba6a28eb8: + .globl L_OBJC_METH_VAR_NAME_6addfcf634c6232f +L_OBJC_METH_VAR_NAME_6addfcf634c6232f: .asciz "methodIdWithParam:" .section __DATA,__objc_selrefs,literal_pointers,no_dead_strip - .globl L_OBJC_SELECTOR_REFERENCES_788cc14ba6a28eb8 + .globl L_OBJC_SELECTOR_REFERENCES_6addfcf634c6232f .p2align 3, 0x0 -L_OBJC_SELECTOR_REFERENCES_788cc14ba6a28eb8: - .quad L_OBJC_METH_VAR_NAME_788cc14ba6a28eb8 +L_OBJC_SELECTOR_REFERENCES_6addfcf634c6232f: + .quad L_OBJC_METH_VAR_NAME_6addfcf634c6232f .section __DATA,__objc_imageinfo,regular,no_dead_strip - .globl L_OBJC_IMAGE_INFO_f058a81939de2cb9 + .globl L_OBJC_IMAGE_INFO_4a8c690dbc9d8166 .p2align 2, 0x0 -L_OBJC_IMAGE_INFO_f058a81939de2cb9: +L_OBJC_IMAGE_INFO_4a8c690dbc9d8166: .asciz "\000\000\000\000@\000\000" .section __TEXT,__objc_methname,cstring_literals - .globl L_OBJC_METH_VAR_NAME_f058a81939de2cb9 -L_OBJC_METH_VAR_NAME_f058a81939de2cb9: + .globl L_OBJC_METH_VAR_NAME_4a8c690dbc9d8166 +L_OBJC_METH_VAR_NAME_4a8c690dbc9d8166: .asciz "copyWithZone:" .section __DATA,__objc_selrefs,literal_pointers,no_dead_strip - .globl L_OBJC_SELECTOR_REFERENCES_f058a81939de2cb9 + .globl L_OBJC_SELECTOR_REFERENCES_4a8c690dbc9d8166 .p2align 3, 0x0 -L_OBJC_SELECTOR_REFERENCES_f058a81939de2cb9: - .quad L_OBJC_METH_VAR_NAME_f058a81939de2cb9 +L_OBJC_SELECTOR_REFERENCES_4a8c690dbc9d8166: + .quad L_OBJC_METH_VAR_NAME_4a8c690dbc9d8166 .subsections_via_symbols diff --git a/crates/test-assembly/crates/test_declare_class/lib.rs b/crates/test-assembly/crates/test_declare_class/lib.rs index cdaf26188..ea181ca05 100644 --- a/crates/test-assembly/crates/test_declare_class/lib.rs +++ b/crates/test-assembly/crates/test_declare_class/lib.rs @@ -3,9 +3,10 @@ #![cfg(feature = "apple")] use core::ptr::{self}; +use icrate::Foundation::{NSCopying, NSObject}; use objc2::declare::{Ivar, IvarDrop, IvarEncode}; use objc2::rc::Id; -use objc2::runtime::{AnyClass, NSObject, NSZone, __NSCopying as NSCopying}; +use objc2::runtime::{AnyClass, NSZone}; use objc2::{declare_class, msg_send, msg_send_id, mutability, ClassType}; declare_class!( @@ -75,7 +76,7 @@ declare_class!( unsafe impl NSCopying for Custom { #[no_mangle] #[method_id(copyWithZone:)] - fn copy_with_zone(&self, _zone: *const NSZone) -> Option> { + fn copyWithZone(&self, _zone: *const NSZone) -> Option> { get_obj().map(|new| { let hack = Id::as_ptr(&new) as *mut Self; let hack = unsafe { &mut *hack }; diff --git a/crates/test-ui/Cargo.toml b/crates/test-ui/Cargo.toml index 244b0b684..a61d07a3e 100644 --- a/crates/test-ui/Cargo.toml +++ b/crates/test-ui/Cargo.toml @@ -21,6 +21,7 @@ default = [ "icrate/Foundation_NSArray", "icrate/Foundation_NSMutableArray", "icrate/Foundation_NSValue", + "icrate/Foundation_NSSet", "objc2/unstable-msg-send-always-comma", ] std = ["block2/std", "objc2/std", "icrate/std"] diff --git a/crates/test-ui/ui/msg_send_invalid_error.stderr b/crates/test-ui/ui/msg_send_invalid_error.stderr index be3b2a06e..00ee6e294 100644 --- a/crates/test-ui/ui/msg_send_invalid_error.stderr +++ b/crates/test-ui/ui/msg_send_invalid_error.stderr @@ -42,7 +42,7 @@ error[E0277]: the trait bound `i32: Message` is not satisfied NSMutableArray NSDictionary NSMutableDictionary - NSEnumerator + NSSet and $N others note: required by a bound in `__send_message_error` --> $WORKSPACE/crates/objc2/src/message/mod.rs diff --git a/crates/test-ui/ui/nsset_from_nsobject.rs b/crates/test-ui/ui/nsset_from_nsobject.rs new file mode 100644 index 000000000..955e2a08a --- /dev/null +++ b/crates/test-ui/ui/nsset_from_nsobject.rs @@ -0,0 +1,6 @@ +//! Test that `NSSet` can't be created from types with an unknown stable hash. +use icrate::Foundation::{NSObject, NSSet}; + +fn main() { + let _ = NSSet::from_vec(vec![NSObject::new()]); +} diff --git a/crates/test-ui/ui/nsset_from_nsobject.stderr b/crates/test-ui/ui/nsset_from_nsobject.stderr new file mode 100644 index 000000000..3fb60164a --- /dev/null +++ b/crates/test-ui/ui/nsset_from_nsobject.stderr @@ -0,0 +1,22 @@ +error[E0277]: the trait bound `Root: mutability::private::MutabilityHashIsStable` is not satisfied + --> ui/nsset_from_nsobject.rs + | + | let _ = NSSet::from_vec(vec![NSObject::new()]); + | --------------- ^^^^^^^^^^^^^^^^^^^^^ the trait `mutability::private::MutabilityHashIsStable` is not implemented for `Root` + | | + | required by a bound introduced by this call + | + = help: the following other types implement trait `mutability::private::MutabilityHashIsStable`: + Immutable + Mutable + ImmutableWithMutableSubclass + MutableWithImmutableSuperclass + = note: required for `NSObject` to implement `HasStableHash` +note: required by a bound in `set::>::from_vec` + --> $WORKSPACE/crates/icrate/src/generated/Foundation/../../additions/Foundation/set.rs + | + | pub fn from_vec(mut vec: Vec>) -> Id + | -------- required by a bound in this associated function + | where + | T: HasStableHash, + | ^^^^^^^^^^^^^ required by this bound in `set::>::from_vec` diff --git a/crates/tests/Cargo.toml b/crates/tests/Cargo.toml index d066da5dd..773354db5 100644 --- a/crates/tests/Cargo.toml +++ b/crates/tests/Cargo.toml @@ -14,6 +14,7 @@ default = ["apple", "std", "Foundation_all"] std = ["block2/std", "objc2/std", "icrate/std"] exception = ["objc2/exception", "Foundation_all"] catch-all = ["objc2/catch-all", "exception"] +verify = ["objc2/verify"] # TODO: Fix this Foundation_all = [ "icrate/Foundation", diff --git a/crates/tests/src/lib.rs b/crates/tests/src/lib.rs index 435876c60..d5c70c559 100644 --- a/crates/tests/src/lib.rs +++ b/crates/tests/src/lib.rs @@ -11,6 +11,8 @@ extern crate std; mod exception; pub mod ffi; #[cfg(test)] +mod test_declare_class_protocol; +#[cfg(test)] mod test_encode_utils; #[cfg(test)] mod test_object; diff --git a/crates/tests/src/test_declare_class_protocol.rs b/crates/tests/src/test_declare_class_protocol.rs new file mode 100644 index 000000000..e408e296a --- /dev/null +++ b/crates/tests/src/test_declare_class_protocol.rs @@ -0,0 +1,159 @@ +#![cfg(feature = "Foundation_all")] +use icrate::Foundation::NSCopying; +use objc2::mutability::Immutable; +use objc2::rc::Id; +use objc2::runtime::{NSObject, NSZone}; +use objc2::{declare_class, ClassType, ProtocolType}; + +#[test] +#[should_panic = "could not create new class TestDeclareClassDuplicate. Perhaps a class with that name already exists?"] +fn test_declare_class_duplicate() { + declare_class!( + struct Custom1; + + unsafe impl ClassType for Custom1 { + type Super = NSObject; + type Mutability = Immutable; + const NAME: &'static str = "TestDeclareClassDuplicate"; + } + ); + + declare_class!( + struct Custom2; + + unsafe impl ClassType for Custom2 { + type Super = NSObject; + type Mutability = Immutable; + const NAME: &'static str = "TestDeclareClassDuplicate"; + } + ); + + let _cls = Custom1::class(); + // Should panic + let _cls = Custom2::class(); +} + +#[test] +fn test_declare_class_protocol() { + declare_class!( + struct Custom; + + unsafe impl ClassType for Custom { + type Super = NSObject; + type Mutability = Immutable; + const NAME: &'static str = "TestDeclareClassProtocolNotFound"; + } + + unsafe impl NSCopying for Custom { + #[method_id(copyWithZone:)] + fn copy_with_zone(&self, _zone: *const NSZone) -> Id { + unimplemented!() + } + } + ); + + let cls = Custom::class(); + assert!(cls.conforms_to(::protocol().unwrap())); +} + +#[test] +#[cfg_attr( + debug_assertions, + should_panic = "declared invalid method -[TestDeclareClassInvalidMethod description]: expected return to have type code '@', but found 'v'" +)] +fn test_declare_class_invalid_method() { + declare_class!( + struct Custom; + + unsafe impl ClassType for Custom { + type Super = NSObject; + type Mutability = Immutable; + const NAME: &'static str = "TestDeclareClassInvalidMethod"; + } + + unsafe impl Custom { + // Override `description` with a bad return type + #[method(description)] + fn description(&self) {} + } + ); + + let _cls = Custom::class(); +} + +#[test] +#[cfg_attr( + all(debug_assertions, feature = "verify"), + should_panic = "must implement required protocol method -[NSCopying copyWithZone:]" +)] +fn test_declare_class_missing_protocol_method() { + declare_class!( + struct Custom; + + unsafe impl ClassType for Custom { + type Super = NSObject; + type Mutability = Immutable; + const NAME: &'static str = "TestDeclareClassMissingProtocolMethod"; + } + + unsafe impl NSCopying for Custom { + // Missing required method + } + ); + + let _cls = Custom::class(); +} + +#[test] +// #[cfg_attr(all(debug_assertions, feature = "verify"), should_panic = "...")] +fn test_declare_class_invalid_protocol_method() { + declare_class!( + struct Custom; + + unsafe impl ClassType for Custom { + type Super = NSObject; + type Mutability = Immutable; + const NAME: &'static str = "TestDeclareClassInvalidProtocolMethod"; + } + + unsafe impl NSCopying for Custom { + // Override with a bad return type + #[method(copyWithZone:)] + fn copy_with_zone(&self, _zone: *const NSZone) -> u8 { + 42 + } + } + ); + + let _cls = Custom::class(); +} + +#[test] +#[cfg_attr( + all(debug_assertions, feature = "verify"), + should_panic = "failed overriding protocol method -[NSCopying someOtherMethod]: method not found" +)] +fn test_declare_class_extra_protocol_method() { + declare_class!( + struct Custom; + + unsafe impl ClassType for Custom { + type Super = NSObject; + type Mutability = Immutable; + const NAME: &'static str = "TestDeclareClassExtraProtocolMethod"; + } + + unsafe impl NSCopying for Custom { + #[method_id(copyWithZone:)] + fn copy_with_zone(&self, _zone: *const NSZone) -> Id { + unimplemented!() + } + + // This doesn't exist on the protocol + #[method(someOtherMethod)] + fn some_other_method(&self) {} + } + ); + + let _cls = Custom::class(); +}