From 5a52c832475a5f2a816907ccd5a7150ab6041a64 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Mon, 28 Feb 2022 18:16:24 +0100 Subject: [PATCH 1/2] Change null handling when creating Ids --- .../examples/class_with_lifetime.rs | 3 +- objc2-foundation/examples/custom_class.rs | 3 +- objc2-foundation/src/array.rs | 28 ++++--- objc2-foundation/src/attributed_string.rs | 6 +- objc2-foundation/src/copying.rs | 6 +- objc2-foundation/src/data.rs | 28 ++++--- objc2-foundation/src/dictionary.rs | 9 +-- objc2-foundation/src/enumerator.rs | 4 +- objc2-foundation/src/macros.rs | 2 +- .../src/mutable_attributed_string.rs | 6 +- objc2-foundation/src/mutable_string.rs | 7 +- objc2-foundation/src/object.rs | 4 +- objc2-foundation/src/process_info.rs | 9 +-- objc2-foundation/src/string.rs | 9 +-- objc2-foundation/src/thread.rs | 11 +-- objc2-foundation/src/uuid.rs | 6 +- objc2-foundation/src/value.rs | 2 +- objc2/CHANGELOG.md | 18 ++++- objc2/README.md | 3 +- objc2/benches/autorelease.rs | 9 +-- objc2/examples/introspection.rs | 6 +- objc2/examples/talk_to_me.rs | 7 +- objc2/src/exception.rs | 8 +- objc2/src/lib.rs | 6 +- objc2/src/rc/id.rs | 78 +++++++------------ objc2/src/rc/mod.rs | 2 +- objc2/src/rc/weak_id.rs | 8 +- 27 files changed, 122 insertions(+), 166 deletions(-) diff --git a/objc2-foundation/examples/class_with_lifetime.rs b/objc2-foundation/examples/class_with_lifetime.rs index d3abc8c40..a9ebded0f 100644 --- a/objc2-foundation/examples/class_with_lifetime.rs +++ b/objc2-foundation/examples/class_with_lifetime.rs @@ -1,5 +1,4 @@ use std::marker::PhantomData; -use std::ptr::NonNull; use std::sync::Once; use objc2::declare::ClassDecl; @@ -30,7 +29,7 @@ impl<'a> MyObject<'a> { unsafe { let obj: *mut Self = msg_send![Self::class(), alloc]; let obj: *mut Self = msg_send![obj, initWithPtr: number_ptr]; - Id::new(NonNull::new_unchecked(obj)) + Id::new(obj).unwrap() } } diff --git a/objc2-foundation/examples/custom_class.rs b/objc2-foundation/examples/custom_class.rs index 771eebffb..140536cd8 100644 --- a/objc2-foundation/examples/custom_class.rs +++ b/objc2-foundation/examples/custom_class.rs @@ -1,4 +1,3 @@ -use std::ptr::NonNull; use std::sync::Once; use objc2::declare::ClassDecl; @@ -26,7 +25,7 @@ static MYOBJECT_REGISTER_CLASS: Once = Once::new(); impl MYObject { fn new() -> Id { let cls = Self::class(); - unsafe { Id::new(NonNull::new_unchecked(msg_send![cls, new])) } + unsafe { Id::new(msg_send![cls, new]).unwrap() } } fn number(&self) -> u32 { diff --git a/objc2-foundation/src/array.rs b/objc2-foundation/src/array.rs index d84015725..ad36a9852 100644 --- a/objc2-foundation/src/array.rs +++ b/objc2-foundation/src/array.rs @@ -3,7 +3,6 @@ use core::cmp::Ordering; use core::ffi::c_void; use core::marker::PhantomData; use core::ops::{Index, IndexMut, Range}; -use core::ptr::NonNull; use objc2::msg_send; use objc2::rc::{DefaultId, Id, Owned, Ownership, Shared, SliceId}; @@ -47,16 +46,15 @@ object! { unsafe pub struct NSMutableArray: NSArray {} } -unsafe fn from_refs(cls: &Class, refs: &[&T]) -> NonNull { +unsafe fn from_refs(cls: &Class, refs: &[&T]) -> *mut Object { let obj: *mut Object = unsafe { msg_send![cls, alloc] }; - let obj: *mut Object = unsafe { + unsafe { msg_send![ obj, initWithObjects: refs.as_ptr(), count: refs.len(), ] - }; - unsafe { NonNull::new_unchecked(obj) } + } } impl NSArray { @@ -106,7 +104,7 @@ impl NSArray { } pub fn from_vec(vec: Vec>) -> Id { - unsafe { Id::new(from_refs(Self::class(), vec.as_slice_ref()).cast()) } + unsafe { Id::new(from_refs(Self::class(), vec.as_slice_ref()).cast()).unwrap() } } pub fn objects_in_range(&self, range: Range) -> Vec<&T> { @@ -128,27 +126,27 @@ impl NSArray { array .to_vec() .into_iter() - .map(|obj| unsafe { Id::retain(obj.into()) }) + .map(|obj| unsafe { Id::retain(obj as *const T as *mut T).unwrap_unchecked() }) .collect() } } impl NSArray { pub fn from_slice(slice: &[Id]) -> Id { - unsafe { Id::new(from_refs(Self::class(), slice.as_slice_ref()).cast()) } + unsafe { Id::new(from_refs(Self::class(), slice.as_slice_ref()).cast()).unwrap() } } #[doc(alias = "objectAtIndex:")] pub fn get_retained(&self, index: usize) -> Id { let obj = self.get(index).unwrap(); // SAFETY: The object is originally shared (see `where` bound). - unsafe { Id::retain(obj.into()) } + unsafe { Id::retain(obj as *const T as *mut T).unwrap_unchecked() } } pub fn to_shared_vec(&self) -> Vec> { self.to_vec() .into_iter() - .map(|obj| unsafe { Id::retain(obj.into()) }) + .map(|obj| unsafe { Id::retain(obj as *const T as *mut T).unwrap_unchecked() }) .collect() } } @@ -212,13 +210,13 @@ impl NSMutableArray { unsafe_def_fn!(pub fn new -> Owned); pub fn from_vec(vec: Vec>) -> Id { - unsafe { Id::new(from_refs(Self::class(), vec.as_slice_ref()).cast()) } + unsafe { Id::new(from_refs(Self::class(), vec.as_slice_ref()).cast()).unwrap() } } } impl NSMutableArray { pub fn from_slice(slice: &[Id]) -> Id { - unsafe { Id::new(from_refs(Self::class(), slice.as_slice_ref()).cast()) } + unsafe { Id::new(from_refs(Self::class(), slice.as_slice_ref()).cast()).unwrap() } } } @@ -249,7 +247,7 @@ impl NSMutableArray { pub fn replace(&mut self, index: usize, obj: Id) -> Id { let old_obj = unsafe { let obj = self.get(index).unwrap(); - Id::retain(obj.into()) + Id::retain(obj as *const T as *mut T).unwrap_unchecked() }; unsafe { let _: () = msg_send![ @@ -264,7 +262,7 @@ impl NSMutableArray { #[doc(alias = "removeObjectAtIndex:")] pub fn remove(&mut self, index: usize) -> Id { let obj = if let Some(obj) = self.get(index) { - unsafe { Id::retain(obj.into()) } + unsafe { Id::retain(obj as *const T as *mut T).unwrap_unchecked() } } else { panic!("removal index should be < len"); }; @@ -277,7 +275,7 @@ impl NSMutableArray { #[doc(alias = "removeLastObject")] pub fn pop(&mut self) -> Option> { self.last().map(|obj| { - let obj = unsafe { Id::retain(obj.into()) }; + let obj = unsafe { Id::retain(obj as *const T as *mut T).unwrap_unchecked() }; unsafe { let _: () = msg_send![self, removeLastObject]; } diff --git a/objc2-foundation/src/attributed_string.rs b/objc2-foundation/src/attributed_string.rs index e9c263919..6df466507 100644 --- a/objc2-foundation/src/attributed_string.rs +++ b/objc2-foundation/src/attributed_string.rs @@ -1,5 +1,3 @@ -use core::ptr::NonNull; - use objc2::msg_send; use objc2::rc::{DefaultId, Id, Shared}; use objc2::runtime::Object; @@ -51,7 +49,7 @@ impl NSAttributedString { unsafe { let obj: *mut Self = msg_send![Self::class(), alloc]; let obj: *mut Self = msg_send![obj, initWithString: string, attributes: attributes]; - Id::new(NonNull::new_unchecked(obj)) + Id::new(obj).unwrap() } } @@ -61,7 +59,7 @@ impl NSAttributedString { unsafe { let obj: *mut Self = msg_send![Self::class(), alloc]; let obj: *mut Self = msg_send![obj, initWithString: string]; - Id::new(NonNull::new_unchecked(obj)) + Id::new(obj).unwrap() } } } diff --git a/objc2-foundation/src/copying.rs b/objc2-foundation/src/copying.rs index edb330564..c0fcbc795 100644 --- a/objc2-foundation/src/copying.rs +++ b/objc2-foundation/src/copying.rs @@ -1,5 +1,3 @@ -use core::ptr::NonNull; - use objc2::rc::{Id, Owned, Ownership}; use objc2::{msg_send, Message}; @@ -35,7 +33,7 @@ pub unsafe trait NSCopying: Message { fn copy(&self) -> Id { unsafe { let obj: *mut Self::Output = msg_send![self, copy]; - Id::new(NonNull::new_unchecked(obj)) + Id::new(obj).unwrap() } } } @@ -50,7 +48,7 @@ pub unsafe trait NSMutableCopying: Message { fn mutable_copy(&self) -> Id { unsafe { let obj: *mut Self::Output = msg_send![self, mutableCopy]; - Id::new(NonNull::new_unchecked(obj)) + Id::new(obj).unwrap() } } } diff --git a/objc2-foundation/src/data.rs b/objc2-foundation/src/data.rs index 72b7932ff..0816faaeb 100644 --- a/objc2-foundation/src/data.rs +++ b/objc2-foundation/src/data.rs @@ -1,8 +1,8 @@ #[cfg(feature = "block")] use alloc::vec::Vec; +use core::ffi::c_void; use core::ops::{Index, IndexMut, Range}; use core::slice::{self, SliceIndex}; -use core::{ffi::c_void, ptr::NonNull}; use std::io; use objc2::msg_send; @@ -62,7 +62,7 @@ impl NSData { } pub fn with_bytes(bytes: &[u8]) -> Id { - unsafe { Id::new(data_with_bytes(Self::class(), bytes).cast()) } + unsafe { Id::new(data_with_bytes(Self::class(), bytes).cast()).unwrap() } } #[cfg(feature = "block")] @@ -79,7 +79,7 @@ impl NSData { #[cfg(not(gnustep))] let cls = Self::class(); - unsafe { Id::new(data_from_vec(cls, bytes).cast()) } + unsafe { Id::new(data_from_vec(cls, bytes).cast()).unwrap() } } } @@ -122,12 +122,12 @@ impl NSMutableData { unsafe_def_fn!(fn new -> Owned); pub fn with_bytes(bytes: &[u8]) -> Id { - unsafe { Id::new(data_with_bytes(Self::class(), bytes).cast()) } + unsafe { Id::new(data_with_bytes(Self::class(), bytes).cast()).unwrap() } } #[cfg(feature = "block")] pub fn from_vec(bytes: Vec) -> Id { - unsafe { Id::new(data_from_vec(Self::class(), bytes).cast()) } + unsafe { Id::new(data_from_vec(Self::class(), bytes).cast()).unwrap() } } // TODO: Use malloc_buf/mbox and `initWithBytesNoCopy:...`? @@ -138,7 +138,7 @@ impl NSMutableData { unsafe { let obj: *mut Self = msg_send![Self::class(), alloc]; let obj: *mut Self = msg_send![obj, initWithData: data]; - Id::new(NonNull::new_unchecked(obj)) + Id::new(obj).unwrap() } } @@ -147,7 +147,7 @@ impl NSMutableData { unsafe { let obj: *mut Self = msg_send![Self::class(), alloc]; let obj: *mut Self = msg_send![obj, initWithCapacity: capacity]; - Id::new(NonNull::new_unchecked(obj)) + Id::new(obj).unwrap() } } } @@ -289,21 +289,20 @@ impl DefaultId for NSMutableData { } } -unsafe fn data_with_bytes(cls: &Class, bytes: &[u8]) -> NonNull { +unsafe fn data_with_bytes(cls: &Class, bytes: &[u8]) -> *mut Object { let bytes_ptr = bytes.as_ptr() as *const c_void; unsafe { let obj: *mut Object = msg_send![cls, alloc]; - let obj: *mut Object = msg_send![ + msg_send![ obj, initWithBytes: bytes_ptr, length: bytes.len(), - ]; - NonNull::new_unchecked(obj) + ] } } #[cfg(feature = "block")] -unsafe fn data_from_vec(cls: &Class, bytes: Vec) -> NonNull { +unsafe fn data_from_vec(cls: &Class, bytes: Vec) -> *mut Object { use core::mem::ManuallyDrop; use block2::{Block, ConcreteBlock}; @@ -321,13 +320,12 @@ unsafe fn data_from_vec(cls: &Class, bytes: Vec) -> NonNull { unsafe { let obj: *mut Object = msg_send![cls, alloc]; - let obj: *mut Object = msg_send![ + msg_send![ obj, initWithBytesNoCopy: bytes.as_mut_ptr() as *mut c_void, length: bytes.len(), deallocator: dealloc, - ]; - NonNull::new_unchecked(obj) + ] } } diff --git a/objc2-foundation/src/dictionary.rs b/objc2-foundation/src/dictionary.rs index c5aebf23a..fcb39a0d3 100644 --- a/objc2-foundation/src/dictionary.rs +++ b/objc2-foundation/src/dictionary.rs @@ -2,7 +2,7 @@ use alloc::vec::Vec; use core::cmp::min; use core::marker::PhantomData; use core::ops::Index; -use core::ptr::{self, NonNull}; +use core::ptr; use objc2::rc::{DefaultId, Id, Owned, Shared, SliceId}; use objc2::{msg_send, Message}; @@ -103,7 +103,7 @@ impl NSDictionary { pub fn keys_array(&self) -> Id, Shared> { unsafe { let keys = msg_send![self, allKeys]; - Id::retain(NonNull::new_unchecked(keys)) + Id::retain(keys).unwrap() } } @@ -124,14 +124,13 @@ impl NSDictionary { count: count, ] }; - let obj = unsafe { NonNull::new_unchecked(obj) }; - unsafe { Id::new(obj) } + unsafe { Id::new(obj).unwrap() } } pub fn into_values_array(dict: Id) -> Id, Shared> { unsafe { let vals = msg_send![dict, allValues]; - Id::retain(NonNull::new_unchecked(vals)) + Id::retain(vals).unwrap() } } } diff --git a/objc2-foundation/src/enumerator.rs b/objc2-foundation/src/enumerator.rs index 5eb6ea82c..60422c1a8 100644 --- a/objc2-foundation/src/enumerator.rs +++ b/objc2-foundation/src/enumerator.rs @@ -1,7 +1,6 @@ use core::marker::PhantomData; use core::mem; use core::ptr; -use core::ptr::NonNull; use core::slice; use std::os::raw::c_ulong; @@ -23,9 +22,8 @@ impl<'a, T: Message> NSEnumerator<'a, T> { /// The object pointer must be a valid `NSEnumerator` with `Owned` /// ownership. pub unsafe fn from_ptr(ptr: *mut Object) -> Self { - let ptr = NonNull::new(ptr).unwrap(); Self { - id: unsafe { Id::retain(ptr) }, + id: unsafe { Id::retain(ptr) }.unwrap(), item: PhantomData, } } diff --git a/objc2-foundation/src/macros.rs b/objc2-foundation/src/macros.rs index cf389d6c7..994a610ba 100644 --- a/objc2-foundation/src/macros.rs +++ b/objc2-foundation/src/macros.rs @@ -156,7 +156,7 @@ macro_rules! unsafe_def_fn { $(#[$m])* $v fn new() -> Id { let cls = Self::class(); - unsafe { Id::new(NonNull::new_unchecked(msg_send![cls, new])) } + unsafe { Id::new(msg_send![cls, new]).unwrap() } } }; } diff --git a/objc2-foundation/src/mutable_attributed_string.rs b/objc2-foundation/src/mutable_attributed_string.rs index fa50333d1..0be87e14f 100644 --- a/objc2-foundation/src/mutable_attributed_string.rs +++ b/objc2-foundation/src/mutable_attributed_string.rs @@ -1,5 +1,3 @@ -use core::ptr::NonNull; - use objc2::msg_send; use objc2::rc::{DefaultId, Id, Owned, Shared}; @@ -30,7 +28,7 @@ impl NSMutableAttributedString { unsafe { let obj: *mut Self = msg_send![Self::class(), alloc]; let obj: *mut Self = msg_send![obj, initWithString: string]; - Id::new(NonNull::new_unchecked(obj)) + Id::new(obj).unwrap() } } @@ -39,7 +37,7 @@ impl NSMutableAttributedString { unsafe { let obj: *mut Self = msg_send![Self::class(), alloc]; let obj: *mut Self = msg_send![obj, initWithAttributedString: attributed_string]; - Id::new(NonNull::new_unchecked(obj)) + Id::new(obj).unwrap() } } } diff --git a/objc2-foundation/src/mutable_string.rs b/objc2-foundation/src/mutable_string.rs index c50c1f77d..b8dde2607 100644 --- a/objc2-foundation/src/mutable_string.rs +++ b/objc2-foundation/src/mutable_string.rs @@ -1,7 +1,6 @@ use core::cmp; use core::fmt; use core::ops::AddAssign; -use core::ptr::NonNull; use core::str; use objc2::msg_send; @@ -32,7 +31,7 @@ impl NSMutableString { pub fn from_str(string: &str) -> Id { unsafe { let obj = super::string::from_str(Self::class(), string); - Id::new(obj.cast()) + Id::new(obj.cast()).unwrap() } } @@ -42,7 +41,7 @@ impl NSMutableString { unsafe { let obj: *mut Self = msg_send![Self::class(), alloc]; let obj: *mut Self = msg_send![obj, initWithString: string]; - Id::new(NonNull::new_unchecked(obj)) + Id::new(obj).unwrap() } } @@ -51,7 +50,7 @@ impl NSMutableString { unsafe { let obj: *mut Self = msg_send![Self::class(), alloc]; let obj: *mut Self = msg_send![obj, initWithCapacity: capacity]; - Id::new(NonNull::new_unchecked(obj)) + Id::new(obj).unwrap() } } } diff --git a/objc2-foundation/src/object.rs b/objc2-foundation/src/object.rs index 671fe8de7..e913741dc 100644 --- a/objc2-foundation/src/object.rs +++ b/objc2-foundation/src/object.rs @@ -1,5 +1,3 @@ -use core::ptr::NonNull; - use objc2::msg_send; use objc2::rc::{DefaultId, Id, Owned, Shared}; use objc2::runtime::{Bool, Class, Object}; @@ -26,7 +24,7 @@ impl NSObject { unsafe { let result: *mut NSString = msg_send![self, description]; // TODO: Verify that description always returns a non-null string - Id::retain(NonNull::new_unchecked(result)) + Id::retain(result).unwrap() } } diff --git a/objc2-foundation/src/process_info.rs b/objc2-foundation/src/process_info.rs index d18edf676..3abb37008 100644 --- a/objc2-foundation/src/process_info.rs +++ b/objc2-foundation/src/process_info.rs @@ -1,5 +1,3 @@ -use core::ptr::NonNull; - use objc2::msg_send; use objc2::rc::{Id, Shared}; @@ -23,13 +21,12 @@ impl NSProcessInfo { pub fn process_info() -> Id { // currentThread is @property(strong), what does that mean? let obj: *mut Self = unsafe { msg_send![Self::class(), processInfo] }; - let obj = unsafe { NonNull::new_unchecked(obj) }; - unsafe { Id::retain(obj) } + // TODO: Always available? + unsafe { Id::retain(obj).unwrap() } } pub fn process_name(&self) -> Id { let obj: *mut NSString = unsafe { msg_send![Self::class(), processName] }; - let obj = NonNull::new(obj).unwrap(); - unsafe { Id::retain(obj) } + unsafe { Id::retain(obj).unwrap() } } } diff --git a/objc2-foundation/src/string.rs b/objc2-foundation/src/string.rs index 145dc565c..49572b6ce 100644 --- a/objc2-foundation/src/string.rs +++ b/objc2-foundation/src/string.rs @@ -165,7 +165,7 @@ impl NSString { pub fn from_str(string: &str) -> Id { unsafe { let obj = from_str(Self::class(), string); - Id::new(obj.cast()) + Id::new(obj.cast()).unwrap() } } @@ -200,17 +200,16 @@ impl NSString { // https://developer.apple.com/documentation/foundation/1415155-nsstringfromrange?language=objc } -pub(crate) fn from_str(cls: &Class, string: &str) -> NonNull { +pub(crate) fn from_str(cls: &Class, string: &str) -> *mut Object { let bytes = string.as_ptr() as *const c_void; unsafe { let obj: *mut Object = msg_send![cls, alloc]; - let obj: *mut Object = msg_send![ + msg_send![ obj, initWithBytes: bytes, length: string.len(), encoding: UTF8_ENCODING, - ]; - NonNull::new_unchecked(obj) + ] } } diff --git a/objc2-foundation/src/thread.rs b/objc2-foundation/src/thread.rs index 7b5f200ed..66a401873 100644 --- a/objc2-foundation/src/thread.rs +++ b/objc2-foundation/src/thread.rs @@ -1,5 +1,3 @@ -use core::ptr::NonNull; - use objc2::msg_send; use objc2::rc::{Id, Shared}; use objc2::runtime::Bool; @@ -21,8 +19,8 @@ impl NSThread { pub fn current() -> Id { // TODO: currentThread is @property(strong), what does that mean? let obj: *mut Self = unsafe { msg_send![Self::class(), currentThread] }; - let obj = unsafe { NonNull::new_unchecked(obj) }; - unsafe { Id::retain(obj) } + // TODO: Always available? + unsafe { Id::retain(obj).unwrap() } } /// Returns the [`NSThread`] object representing the main thread. @@ -31,8 +29,7 @@ impl NSThread { let obj: *mut Self = unsafe { msg_send![Self::class(), mainThread] }; // The main thread static may not have been initialized // This can at least fail in GNUStep! - let obj = NonNull::new(obj).expect("Could not retrieve main thread."); - unsafe { Id::retain(obj) } + unsafe { Id::retain(obj).expect("Could not retrieve main thread.") } } /// Returns `true` if the thread is the main thread. @@ -44,7 +41,7 @@ impl NSThread { /// The name of the thread. pub fn name(&self) -> Option> { let obj: *mut NSString = unsafe { msg_send![self, name] }; - unsafe { Id::retain_null(obj) } + unsafe { Id::retain(obj) } } } diff --git a/objc2-foundation/src/uuid.rs b/objc2-foundation/src/uuid.rs index 9d7d6df95..9db48fd1a 100644 --- a/objc2-foundation/src/uuid.rs +++ b/objc2-foundation/src/uuid.rs @@ -1,5 +1,3 @@ -use core::ptr::NonNull; - use objc2::rc::{Id, Shared}; use objc2::{msg_send, Encode, Encoding, RefEncode}; @@ -37,7 +35,7 @@ impl NSUUID { unsafe { let obj: *mut Self = msg_send![Self::class(), alloc]; let obj: *mut Self = msg_send![obj, init]; - Id::new(NonNull::new_unchecked(obj)) + Id::new(obj).unwrap() } } @@ -46,7 +44,7 @@ impl NSUUID { unsafe { let obj: *mut Self = msg_send![Self::class(), alloc]; let obj: *mut Self = msg_send![obj, initWithUUIDBytes: &bytes]; - Id::new(NonNull::new_unchecked(obj)) + Id::new(obj).unwrap() } } diff --git a/objc2-foundation/src/value.rs b/objc2-foundation/src/value.rs index 970c35e6c..a79a3f30c 100644 --- a/objc2-foundation/src/value.rs +++ b/objc2-foundation/src/value.rs @@ -73,7 +73,7 @@ impl NSValue { initWithBytes: bytes, objCType: encoding.as_ptr(), ]; - Id::new(NonNull::new_unchecked(obj)) + Id::new(obj).unwrap() } } } diff --git a/objc2/CHANGELOG.md b/objc2/CHANGELOG.md index e71b4c80a..b6b83c452 100644 --- a/objc2/CHANGELOG.md +++ b/objc2/CHANGELOG.md @@ -11,10 +11,24 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). upgrading easier. * Allow using `From`/`TryFrom` to convert between `rc::Id` and `rc::WeakId`. * Added `Bool::as_bool` (more descriptive name than `Bool::is_true`). -* Added convenience methods `Id::new_null`, `Id::as_ptr` and - `Id::retain_null`. +* Added convenience method `Id::as_ptr`. * The `objc2-encode` dependency is now exposed as `objc2::encode`. +### Changed +* **BREAKING**: Changed signature of `Id::new` and `Id::retain` from + `fn(NonNull) -> Id` to `fn(*mut T) -> Option>`. + + Concretely, you will have to change your code as follows. + ```rust + // Before + let obj: *mut Object = unsafe { msg_send![class!(NSObject), new] }; + let obj = NonNull::new(obj).expect("Failed to allocate object."); + let obj = unsafe { Id::new(obj) }; + // After + let obj: *mut Object = unsafe { msg_send![class!(NSObject), new] }; + let obj = unsafe { Id::new(obj) }.expect("Failed to allocate object."); + ``` + ## 0.3.0-alpha.6 - 2022-01-03 diff --git a/objc2/README.md b/objc2/README.md index cf818d105..8b215a7d0 100644 --- a/objc2/README.md +++ b/objc2/README.md @@ -13,14 +13,13 @@ written in Objective-C; this crate enables you to interract with those. ## Example ```rust -use std::ptr::NonNull; use objc2::{class, msg_send}; use objc2::rc::{Id, Owned}; use objc2::runtime::{Class, Object}; let cls = class!(NSObject); let obj: *mut Object = unsafe { msg_send![cls, new] }; -let obj: Id = unsafe { Id::new(NonNull::new(obj).unwrap()) }; +let obj: Id = unsafe { Id::new(obj).unwrap() }; // TODO // let isa = unsafe { obj.ivar::("isa") }; diff --git a/objc2/benches/autorelease.rs b/objc2/benches/autorelease.rs index ec6b45a7d..f220ab88f 100644 --- a/objc2/benches/autorelease.rs +++ b/objc2/benches/autorelease.rs @@ -1,6 +1,5 @@ use core::ffi::c_void; use std::mem::ManuallyDrop; -use std::ptr::NonNull; use objc2::ffi; use objc2::rc::{autoreleasepool, Id, Shared}; @@ -47,7 +46,7 @@ fn alloc_nsobject() -> *mut Object { fn new_nsobject() -> Id { let obj = alloc_nsobject(); let obj: *mut Object = unsafe { msg_send![obj, init] }; - unsafe { Id::new(NonNull::new_unchecked(obj)) } + unsafe { Id::new(obj).unwrap_unchecked() } } fn new_nsdata() -> Id { @@ -60,7 +59,7 @@ fn new_nsdata() -> Id { length: BYTES.len(), ] }; - unsafe { Id::new(NonNull::new_unchecked(obj)) } + unsafe { Id::new(obj).unwrap_unchecked() } } fn new_leaked_nsdata() -> *mut Object { @@ -82,7 +81,7 @@ fn autoreleased_nsdata() -> *mut Object { fn new_nsstring() -> Id { let obj: *mut Object = unsafe { msg_send![class!(NSString), alloc] }; let obj: *mut Object = unsafe { msg_send![obj, init] }; - unsafe { Id::new(NonNull::new_unchecked(obj)) } + unsafe { Id::new(obj).unwrap_unchecked() } } fn new_leaked_nsstring() -> *mut Object { @@ -96,7 +95,7 @@ fn autoreleased_nsstring() -> *mut Object { fn retain_autoreleased(obj: *mut Object) -> Id { let obj = unsafe { ffi::objc_retainAutoreleasedReturnValue(obj.cast()) }; - unsafe { Id::new(NonNull::new_unchecked(obj).cast()) } + unsafe { Id::new(obj.cast()).unwrap_unchecked() } } fn autoreleased_nsdata_pool_cleanup() -> *mut Object { diff --git a/objc2/examples/introspection.rs b/objc2/examples/introspection.rs index 5a10b2736..51d7a31d0 100644 --- a/objc2/examples/introspection.rs +++ b/objc2/examples/introspection.rs @@ -1,5 +1,3 @@ -use core::ptr::NonNull; - use objc2::rc::{Id, Owned}; use objc2::runtime::{Class, Object}; use objc2::{class, msg_send}; @@ -23,8 +21,8 @@ fn main() { // Allocate an instance let obj: Id = unsafe { let obj: *mut Object = msg_send![cls, alloc]; - let obj: NonNull = msg_send![obj, init]; - Id::new(obj) + let obj: *mut Object = msg_send![obj, init]; + Id::new(obj).unwrap() }; println!("NSObject address: {:p}", obj); diff --git a/objc2/examples/talk_to_me.rs b/objc2/examples/talk_to_me.rs index 3109db9f0..9285fcf0a 100644 --- a/objc2/examples/talk_to_me.rs +++ b/objc2/examples/talk_to_me.rs @@ -3,7 +3,6 @@ use objc2::rc::{Id, Owned, Shared}; use objc2::runtime::Object; use objc2::{class, msg_send}; use std::ffi::c_void; -use std::ptr::NonNull; #[cfg(apple)] // Does not work on GNUStep #[link(name = "AVFoundation", kind = "framework")] @@ -22,14 +21,14 @@ fn main() { encoding: 4 as NSUInteger, // UTF8_ENCODING on macOS / iOS ] }; - let string: Id = unsafe { Id::new(NonNull::new(string).unwrap()) }; + let string: Id = unsafe { Id::new(string).unwrap() }; let synthesizer: *mut Object = unsafe { msg_send![class!(AVSpeechSynthesizer), new] }; - let synthesizer: Id = unsafe { Id::new(NonNull::new(synthesizer).unwrap()) }; + let synthesizer: Id = unsafe { Id::new(synthesizer).unwrap() }; let utterance: *mut Object = unsafe { msg_send![class!(AVSpeechUtterance), alloc] }; let utterance: *mut Object = unsafe { msg_send![utterance, initWithString: &*string] }; - let utterance: Id = unsafe { Id::new(NonNull::new(utterance).unwrap()) }; + let utterance: Id = unsafe { Id::new(utterance).unwrap() }; // let _: () = unsafe { msg_send![utterance, setVolume: 90.0f32 }; // let _: () = unsafe { msg_send![utterance, setRate: 0.50f32 }; diff --git a/objc2/src/exception.rs b/objc2/src/exception.rs index 40a300b84..0ec9df64d 100644 --- a/objc2/src/exception.rs +++ b/objc2/src/exception.rs @@ -20,7 +20,6 @@ use core::ffi::c_void; use core::mem; use core::ptr; -use core::ptr::NonNull; use std::os::raw::c_uchar; use crate::ffi; @@ -94,15 +93,14 @@ unsafe fn try_no_ret(closure: F) -> Result<(), Option = unsafe { Id::new(msg_send![class!(NSObject), new]) }; + let obj: Id = unsafe { Id::new(msg_send![class!(NSObject), new]).unwrap() }; let result = unsafe { catch(|| throw(Some(&obj))) }; let e = result.unwrap_err().unwrap(); diff --git a/objc2/src/lib.rs b/objc2/src/lib.rs index e1a3aa152..e9c13a896 100644 --- a/objc2/src/lib.rs +++ b/objc2/src/lib.rs @@ -29,7 +29,6 @@ //! #![cfg_attr(apple, doc = "```")] #![cfg_attr(not(apple), doc = "```no_run")] -//! use core::ptr::NonNull; //! use objc2::{class, msg_send}; //! use objc2::ffi::NSUInteger; //! use objc2::rc::{Id, Owned}; @@ -38,8 +37,9 @@ //! // Creation //! let cls = class!(NSObject); //! let obj: *mut Object = unsafe { msg_send![cls, new] }; -//! let obj = NonNull::new(obj).expect("Failed allocating object"); -//! let obj: Id = unsafe { Id::new(obj) }; +//! let obj: Id = unsafe { +//! Id::new(obj).expect("Failed allocating object") +//! }; //! //! // Usage //! let hash: NSUInteger = unsafe { msg_send![obj, hash] }; diff --git a/objc2/src/rc/id.rs b/objc2/src/rc/id.rs index d0edfcf55..c2790f89a 100644 --- a/objc2/src/rc/id.rs +++ b/objc2/src/rc/id.rs @@ -65,7 +65,7 @@ use crate::Message; /// /// let cls = Class::get("NSObject").unwrap(); /// let obj: Id = unsafe { -/// Id::new(msg_send![cls, new]) +/// Id::new(msg_send![cls, new]).unwrap() /// }; /// // obj will be released when it goes out of scope /// @@ -88,7 +88,7 @@ use crate::Message; /// # use objc2::rc::{Id, Owned, Shared}; /// # type T = Object; /// let mut owned: Id; -/// # owned = unsafe { Id::new(msg_send![class!(NSObject), new]) }; +/// # owned = unsafe { Id::new(msg_send![class!(NSObject), new]).unwrap() }; /// let mut_ref: &mut T = &mut *owned; /// // Do something with `&mut T` here /// @@ -138,6 +138,8 @@ impl Id { /// But some immutable objects (like `NSString`) don't always return /// unique references, so in those case you would use [`Shared`]. /// + /// Returns `None` if the pointer was null. + /// /// # Safety /// /// The caller must ensure the given object has +1 retain count, and that @@ -153,9 +155,9 @@ impl Id { /// let cls: &Class; /// # let cls = class!(NSObject); /// let obj: &mut Object = unsafe { msg_send![cls, alloc] }; - /// let obj: Id = unsafe { Id::new(msg_send![obj, init]) }; + /// let obj: Id = unsafe { Id::new(msg_send![obj, init]).unwrap() }; /// // Or in this case simply just: - /// let obj: Id = unsafe { Id::new(msg_send![cls, new]) }; + /// let obj: Id = unsafe { Id::new(msg_send![cls, new]).unwrap() }; /// ``` /// /// ```no_run @@ -165,13 +167,19 @@ impl Id { /// # type NSString = Object; /// let cls = class!(NSString); /// // NSString is immutable, so don't create an owned reference to it - /// let obj: Id = unsafe { Id::new(msg_send![cls, new]) }; + /// let obj: Id = unsafe { Id::new(msg_send![cls, new]).unwrap() }; /// ``` #[inline] // Note: We don't take a reference as a parameter since it would be too // easy to accidentally create two aliasing mutable references. - pub unsafe fn new(ptr: NonNull) -> Id { + pub unsafe fn new(ptr: *mut T) -> Option> { + // Should optimize down to nothing. // SAFETY: Upheld by the caller + NonNull::new(ptr).map(|ptr| unsafe { Id::new_nonnull(ptr) }) + } + + #[inline] + unsafe fn new_nonnull(ptr: NonNull) -> Id { Self { ptr, item: PhantomData, @@ -180,20 +188,6 @@ impl Id { } } - /// Constructs an [`Id`] from a pointer that may be null. - /// - /// This is just a convenience wrapper over [`Id::new`] so that you don't - /// need to construct a [`NonNull`] when you know the pointer may be null. - /// - /// # Safety - /// - /// Same as [`Id::new`]. - #[inline] - pub unsafe fn new_null(ptr: *mut T) -> Option> { - // SAFETY: Upheld by the caller - NonNull::new(ptr).map(|ptr| unsafe { Id::new(ptr) }) - } - /// Returns a raw pointer to the object. /// /// The pointer is valid for at least as long as the `Id` is held. @@ -219,6 +213,8 @@ impl Id { /// This is rarely used to construct owned [`Id`]s, see [`Id::new`] for /// that. /// + /// Returns `None` if the pointer was null. + /// /// # Safety /// /// The caller must ensure that the ownership is correct; that is, there @@ -244,32 +240,13 @@ impl Id { // ``` #[doc(alias = "objc_retain")] #[inline] - pub unsafe fn retain(ptr: NonNull) -> Id { - let ptr = ptr.as_ptr() as *mut ffi::objc_object; + pub unsafe fn retain(ptr: *mut T) -> Option> { + let ptr = ptr as *mut ffi::objc_object; // SAFETY: The caller upholds that the pointer is valid let res = unsafe { ffi::objc_retain(ptr) }; debug_assert_eq!(res, ptr, "objc_retain did not return the same pointer"); - // SAFETY: Non-null upheld by the caller, and `objc_retain` always - // returns the same pointer, see: - // https://clang.llvm.org/docs/AutomaticReferenceCounting.html#arc-runtime-objc-retain - let res = unsafe { NonNull::new_unchecked(res as *mut T) }; // SAFETY: We just retained the object, so it has +1 retain count - unsafe { Self::new(res) } - } - - /// Retains an object pointer that may be null. - /// - /// This is just a convenience wrapper over [`Id::retain`] so that you - /// don't need to construct a [`NonNull`] when you know the pointer may - /// be null. - /// - /// # Safety - /// - /// Same as [`Id::retain`]. - #[inline] - pub unsafe fn retain_null(ptr: *mut T) -> Option> { - // SAFETY: Upheld by the caller - NonNull::new(ptr).map(|ptr| unsafe { Id::retain(ptr) }) + unsafe { Self::new(res as *mut T) } } #[inline] @@ -302,7 +279,7 @@ impl Id { // #[cfg(block)] // impl Id { // #[doc(alias = "objc_retainBlock")] -// pub unsafe fn retain_block(block: NonNull) -> Self { +// pub unsafe fn retain_block(block: *mut T) -> Option { // todo!() // } // } @@ -341,7 +318,7 @@ impl Id { let ptr = ManuallyDrop::new(obj).ptr; // SAFETY: The pointer is valid // Ownership rules are upheld by the caller - unsafe { >::new(ptr) } + unsafe { >::new_nonnull(ptr) } } } @@ -369,7 +346,7 @@ impl From> for Id { fn from(obj: Id) -> Self { let ptr = ManuallyDrop::new(obj).ptr; // SAFETY: The pointer is valid, and ownership is simply decreased - unsafe { >::new(ptr) } + unsafe { >::new_nonnull(ptr) } } } @@ -383,7 +360,10 @@ impl Clone for Id { #[inline] fn clone(&self) -> Self { // SAFETY: The pointer is valid - unsafe { Id::retain(self.ptr) } + let obj = unsafe { Id::retain(self.ptr.as_ptr()) }; + // SAFETY: `objc_retain` always returns the same object pointer, and + // the pointer is guaranteed non-null by Id. + unsafe { obj.unwrap_unchecked() } } } @@ -483,8 +463,6 @@ impl UnwindSafe for Id {} #[cfg(test)] mod tests { - use core::ptr::NonNull; - use super::{Id, Owned, Shared}; use crate::rc::autoreleasepool; use crate::runtime::Object; @@ -496,7 +474,7 @@ mod tests { #[test] fn test_autorelease() { - let obj: Id = unsafe { Id::new(msg_send![class!(NSObject), new]) }; + let obj: Id = unsafe { Id::new(msg_send![class!(NSObject), new]).unwrap() }; let cloned = obj.clone(); @@ -516,7 +494,7 @@ mod tests { let obj: Id = unsafe { let obj: *mut Object = msg_send![cls, alloc]; let obj: *mut Object = msg_send![obj, init]; - Id::new(NonNull::new_unchecked(obj)) + Id::new(obj).unwrap() }; assert_eq!(retain_count(&obj), 1); diff --git a/objc2/src/rc/mod.rs b/objc2/src/rc/mod.rs index 78ef4099d..f77d451a8 100644 --- a/objc2/src/rc/mod.rs +++ b/objc2/src/rc/mod.rs @@ -38,7 +38,7 @@ //! //! // Id will release the object when dropped //! let obj: Id = unsafe { -//! Id::new(msg_send![class!(NSObject), new]) +//! Id::new(msg_send![class!(NSObject), new]).unwrap() //! }; //! //! // Cloning retains the object an additional time diff --git a/objc2/src/rc/weak_id.rs b/objc2/src/rc/weak_id.rs index 7dadf6a6f..b6c455450 100644 --- a/objc2/src/rc/weak_id.rs +++ b/objc2/src/rc/weak_id.rs @@ -72,7 +72,7 @@ impl WeakId { pub fn load(&self) -> Option> { let ptr = self.inner.get(); let obj = unsafe { ffi::objc_loadWeakRetained(ptr) } as *mut T; - unsafe { Id::new_null(obj) } + unsafe { Id::new(obj) } } // TODO: Add `autorelease(&self) -> Option<&T>` using `objc_loadWeak`? @@ -151,8 +151,6 @@ impl TryFrom> for Id { #[cfg(test)] mod tests { - use core::ptr::NonNull; - use super::WeakId; use super::{Id, Shared}; use crate::runtime::Object; @@ -164,7 +162,7 @@ mod tests { let obj: Id = unsafe { let obj: *mut Object = msg_send![cls, alloc]; let obj: *mut Object = msg_send![obj, init]; - Id::new(NonNull::new_unchecked(obj)) + Id::new(obj).unwrap() }; let weak = WeakId::new(&obj); @@ -180,7 +178,7 @@ mod tests { #[test] fn test_weak_clone() { - let obj: Id = unsafe { Id::new(msg_send![class!(NSObject), new]) }; + let obj: Id = unsafe { Id::new(msg_send![class!(NSObject), new]).unwrap() }; let weak = WeakId::new(&obj); let weak2 = weak.clone(); From f4e2b0debab1752f6644eea422913b27d6e4a6c3 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Wed, 2 Mar 2022 20:44:53 +0100 Subject: [PATCH 2/2] Always update apt index --- .github/workflows/ci.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d933a705c..5bd803a34 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -189,7 +189,9 @@ jobs: - name: Install Clang & Valgrind if: contains(matrix.os, 'ubuntu') - run: sudo apt-get -y install clang valgrind + run: | + sudo apt-get update + sudo apt-get -y install clang valgrind - name: Install cross compilation tools if: matrix.target == 'i686-unknown-linux-gnu'