diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 39ff86ae0..e150e8659 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -154,7 +154,7 @@ jobs: # Use --no-fail-fast, except with dinghy TESTARGS: ${{ matrix.dinghy && ' ' || '--no-fail-fast' }} ${{ matrix.test-args }} FEATURES: ${{ matrix.features || 'malloc,block,exception,catch_all,verify_message' }} - UNSTABLE_FEATURES: ${{ matrix.unstable-features || 'unstable-autoreleasesafe' }} + UNSTABLE_FEATURES: ${{ matrix.unstable-features || 'unstable-autoreleasesafe,unstable-id-fundamental' }} runs-on: ${{ matrix.os }} diff --git a/objc2-foundation/examples/basic_usage.rs b/objc2-foundation/examples/basic_usage.rs index e1fd02f39..261fc0d7c 100644 --- a/objc2-foundation/examples/basic_usage.rs +++ b/objc2-foundation/examples/basic_usage.rs @@ -1,4 +1,4 @@ -use objc2::rc::autoreleasepool; +use objc2::rc::{autoreleasepool, Id}; use objc2_foundation::{NSArray, NSCopying, NSDictionary, NSObject, NSString}; fn main() { @@ -14,14 +14,14 @@ fn main() { // Create an NSArray from a Vec let objs = vec![obj, obj2]; - let array = NSArray::from_vec(objs); + let array: Id, _> = objs.into(); for obj in array.iter() { println!("{:?}", obj); } println!("{}", array.len()); // Turn the NSArray back into a Vec - let mut objs = NSArray::into_vec(array); + let mut objs = Vec::from(array); let obj = objs.pop().unwrap(); // Create an NSString from a str slice diff --git a/objc2-foundation/src/array.rs b/objc2-foundation/src/array.rs index 42aaa287a..f3eb8ffe1 100644 --- a/objc2-foundation/src/array.rs +++ b/objc2-foundation/src/array.rs @@ -215,6 +215,37 @@ impl DefaultId for NSArray { } } +impl From, Owned>> for Vec> { + fn from(array: Id, Owned>) -> Self { + let vec: Vec<&T> = (&*array).into(); + vec.into_iter() + .map(|obj| unsafe { Id::retain(obj.into()) }) + .collect() + } +} + +impl From>> for Id, Owned> { + fn from(vec: Vec>) -> Self { + unsafe { from_refs(vec.as_slice_ref()) } + } +} + +impl<'a, T: Message, O: Ownership> From<&'a NSArray> for Vec<&'a T> { + fn from(array: &'a NSArray) -> Self { + array.objects_in_range(0..array.count()) + } +} + +impl From<&'_ NSArray> for Vec> { + fn from(array: &NSArray) -> Self { + array + .objects_in_range(0..array.count()) + .into_iter() + .map(|obj| unsafe { Id::retain(obj.into()) }) + .collect() + } +} + impl NSMutableArray { unsafe_def_fn!(pub fn new -> Owned); @@ -378,6 +409,12 @@ impl DefaultId for NSMutableArray { } } +impl From>> for Id, Owned> { + fn from(vec: Vec>) -> Self { + unsafe { from_refs(vec.as_slice_ref()) } + } +} + #[cfg(test)] mod tests { use alloc::format; @@ -395,7 +432,7 @@ mod tests { for _ in 0..len { vec.push(NSObject::new()); } - NSArray::from_vec(vec) + vec.into() } fn sample_number_array(len: u8) -> Id, Shared>, Shared> { @@ -517,7 +554,7 @@ mod tests { fn test_into_vec() { let array = sample_array(4); - let vec = NSArray::into_vec(array); + let vec = Vec::from(array); assert_eq!(vec.len(), 4); } @@ -566,7 +603,7 @@ mod tests { #[test] fn test_sort() { let strings = vec![NSString::from_str("hello"), NSString::from_str("hi")]; - let mut strings = NSMutableArray::from_vec(strings); + let mut strings: Id, Owned> = strings.into(); autoreleasepool(|pool| { strings.sort_by(|s1, s2| s1.as_str(pool).len().cmp(&s2.as_str(pool).len())); diff --git a/objc2-foundation/src/enumerator.rs b/objc2-foundation/src/enumerator.rs index 4f6415f32..f3b081547 100644 --- a/objc2-foundation/src/enumerator.rs +++ b/objc2-foundation/src/enumerator.rs @@ -167,13 +167,16 @@ impl<'a, C: NSFastEnumeration + ?Sized> Iterator for NSFastEnumerator<'a, C> { #[cfg(test)] mod tests { + use alloc::vec::Vec; + use objc2::rc::Id; + use super::NSFastEnumeration; use crate::{NSArray, NSValue}; #[test] fn test_enumerator() { - let vec = (0usize..4).map(NSValue::new).collect(); - let array = NSArray::from_vec(vec); + let vec: Vec<_> = (0usize..4).map(NSValue::new).collect(); + let array: Id, _> = vec.into(); let enumerator = array.iter(); assert_eq!(enumerator.count(), 4); @@ -184,8 +187,8 @@ mod tests { #[test] fn test_fast_enumerator() { - let vec = (0usize..4).map(NSValue::new).collect(); - let array = NSArray::from_vec(vec); + let vec: Vec<_> = (0usize..4).map(NSValue::new).collect(); + let array: Id, _> = vec.into(); let enumerator = array.iter_fast(); assert_eq!(enumerator.count(), 4); diff --git a/objc2/Cargo.toml b/objc2/Cargo.toml index 49c10ad14..9a0199144 100644 --- a/objc2/Cargo.toml +++ b/objc2/Cargo.toml @@ -40,6 +40,9 @@ malloc = ["malloc_buf"] # Uses nightly features to make AutoreleasePool zero-cost even in debug mode unstable-autoreleasesafe = [] +# Marks `rc::Id` with nightly `fundamental` feature. +unstable-id-fundamental = [] + # Runtime selection. See `objc-sys` for details. apple = ["objc-sys/apple"] gnustep-1-7 = ["objc-sys/gnustep-1-7"] diff --git a/objc2/src/lib.rs b/objc2/src/lib.rs index ad14b3b71..6416d688e 100644 --- a/objc2/src/lib.rs +++ b/objc2/src/lib.rs @@ -168,6 +168,7 @@ feature = "unstable-autoreleasesafe", feature(negative_impls, auto_traits) )] +#![cfg_attr(feature = "unstable-id-fundamental", feature(fundamental))] #![warn(elided_lifetimes_in_paths)] #![warn(missing_docs)] #![deny(non_ascii_idents)] diff --git a/objc2/src/rc/id.rs b/objc2/src/rc/id.rs index 2acd4b960..9f13a4fb0 100644 --- a/objc2/src/rc/id.rs +++ b/objc2/src/rc/id.rs @@ -96,6 +96,7 @@ use crate::Message; /// let cloned: Id = shared.clone(); /// // Do something with `&T` here /// ``` +#[cfg_attr(feature = "unstable-id-fundamental", fundamental)] #[repr(transparent)] // TODO: Figure out if `Message` bound on `T` would be better here? // TODO: Add `ptr::Thin` bound on `T` to allow for only extern types