From 9c95e190d2cd4162911fe0864651f3cebcd3bab6 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Fri, 15 Oct 2021 12:36:33 +0100 Subject: [PATCH 1/2] Add initial Id conversion traits --- objc2/src/rc/id_traits.rs | 50 +++++++++++++++++++++++++++++++++++++++ objc2/src/rc/mod.rs | 2 +- 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/objc2/src/rc/id_traits.rs b/objc2/src/rc/id_traits.rs index 4ffaf9252..d27bb2318 100644 --- a/objc2/src/rc/id_traits.rs +++ b/objc2/src/rc/id_traits.rs @@ -1,5 +1,7 @@ //! Helper traits for Id. +use core::convert::Infallible; + use super::{Id, Owned, Ownership}; use crate::Message; @@ -70,3 +72,51 @@ impl Default for Id { T::default_id() } } + +pub trait FromId { + fn from_id(obj: Id) -> Self; +} + +pub trait TryFromId: Sized { + type Error; + fn try_from_id(obj: Id) -> Result; +} + +impl> TryFromId for U { + type Error = Infallible; + + fn try_from_id(obj: Id) -> Result { + Ok(FromId::from_id(obj)) + } +} + +/// TODO. +/// +/// This is similar to [`Into`] in that it is implemented automatically for +/// all [`Id`] that implement [`FromId`]; but you will have to implement this +/// yourself in many more cases! +pub trait IntoId { + fn into_id(self) -> Id; +} + +impl IntoId for Id +where + Id: FromId, +{ + fn into_id(self) -> Id { + FromId::from_id(self) + } +} + +pub trait TryIntoId { + type Error; + fn try_into_id(self) -> Result, Self::Error>; +} + +impl> TryIntoId for U { + type Error = Infallible; + + fn try_into_id(self) -> Result, Self::Error> { + Ok(IntoId::into_id(self)) + } +} diff --git a/objc2/src/rc/mod.rs b/objc2/src/rc/mod.rs index 1d8f75fde..3644f800b 100644 --- a/objc2/src/rc/mod.rs +++ b/objc2/src/rc/mod.rs @@ -35,7 +35,7 @@ mod weak_id; pub use self::autorelease::{autoreleasepool, AutoreleasePool, AutoreleaseSafe}; pub use self::id::Id; -pub use self::id_traits::{DefaultId, SliceId, SliceIdMut}; +pub use self::id_traits::{DefaultId, FromId, IntoId, SliceId, SliceIdMut, TryFromId, TryIntoId}; pub use self::ownership::{Owned, Ownership, Shared}; pub use self::weak_id::WeakId; From 522f93b95ab7b942fe24549ed3440676a23e2a61 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Fri, 15 Oct 2021 13:09:44 +0100 Subject: [PATCH 2/2] Use Id conversion traits on NSArray --- objc2-foundation/examples/basic_usage.rs | 6 +- objc2-foundation/src/array.rs | 89 ++++++++++++++++-------- objc2-foundation/src/enumerator.rs | 11 +-- 3 files changed, 69 insertions(+), 37 deletions(-) diff --git a/objc2-foundation/examples/basic_usage.rs b/objc2-foundation/examples/basic_usage.rs index 5d6617892..2a0229e04 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, FromId, Id, IntoId}; use objc2_foundation::{ INSArray, INSCopying, INSDictionary, INSString, NSArray, NSDictionary, NSObject, NSString, }; @@ -13,14 +13,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_id(); 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_id(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 98f68f0ea..24a4add53 100644 --- a/objc2-foundation/src/array.rs +++ b/objc2-foundation/src/array.rs @@ -112,10 +112,6 @@ pub unsafe trait INSArray: INSObject { } } - fn from_vec(vec: Vec>) -> Id { - unsafe { from_refs(vec.as_slice_ref()) } - } - fn objects_in_range(&self, range: Range) -> Vec<&Self::Item> { let range = NSRange::from(range); let mut vec = Vec::with_capacity(range.length); @@ -126,35 +122,12 @@ pub unsafe trait INSArray: INSObject { vec } - fn to_vec(&self) -> Vec<&Self::Item> { - self.objects_in_range(0..self.len()) - } - - // TODO: Take Id ? - fn into_vec(array: Id) -> Vec> { - array - .to_vec() - .into_iter() - .map(|obj| unsafe { Id::retain(obj.into()) }) - .collect() - } - fn from_slice(slice: &[Id]) -> Id where Self: INSArray, { unsafe { from_refs(slice.as_slice_ref()) } } - - fn to_shared_vec(&self) -> Vec> - where - Self: INSArray, - { - self.to_vec() - .into_iter() - .map(|obj| unsafe { Id::retain(obj.into()) }) - .collect() - } } /// TODO @@ -211,6 +184,52 @@ impl Index for NSArray { } } +impl FromId, Owned> for Vec> +where + T: INSObject, + O: Ownership, +{ + fn from_id(array: Id, Owned>) -> Self { + let vec: Vec<&T> = (&*array).into(); + vec.into_iter() + .map(|obj| unsafe { Id::retain(obj.into()) }) + .collect() + } +} + +impl IntoId, Owned> for Vec> +where + T: INSObject, + O: Ownership, +{ + fn into_id(self) -> Id, Owned> { + unsafe { from_refs(self.as_slice_ref()) } + } +} + +impl<'a, T, O> From<&'a NSArray> for Vec<&'a T> +where + T: INSObject, + O: Ownership, +{ + fn from(array: &'a NSArray) -> Self { + array.objects_in_range(0..array.count()) + } +} + +impl From<&'_ NSArray> for Vec> +where + T: INSObject, +{ + fn from(array: &NSArray) -> Self { + array + .objects_in_range(0..array.count()) + .into_iter() + .map(|obj| unsafe { Id::retain(obj.into()) }) + .collect() + } +} + pub unsafe trait INSMutableArray: INSArray { #[doc(alias = "addObject:")] fn push(&mut self, obj: Id) { @@ -358,6 +377,16 @@ impl Index for NSMutableArray { } } +impl IntoId, Owned> for Vec> +where + T: INSObject, + O: Ownership, +{ + fn into_id(self) -> Id, Owned> { + unsafe { from_refs(self.as_slice_ref()) } + } +} + #[cfg(test)] mod tests { use alloc::vec; @@ -374,7 +403,7 @@ mod tests { for _ in 0..len { vec.push(NSObject::new()); } - NSArray::from_vec(vec) + vec.into_id() } fn retain_count(obj: &T) -> usize { @@ -455,7 +484,7 @@ mod tests { fn test_into_vec() { let array = sample_array(4); - let vec = INSArray::into_vec(array); + let vec = Vec::from_id(array); assert_eq!(vec.len(), 4); } @@ -504,7 +533,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_id(); 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 0f937683a..4764fc403 100644 --- a/objc2-foundation/src/enumerator.rs +++ b/objc2-foundation/src/enumerator.rs @@ -169,13 +169,16 @@ impl<'a, C: INSFastEnumeration> Iterator for NSFastEnumerator<'a, C> { #[cfg(test)] mod tests { + use alloc::vec::Vec; + use objc2::rc::{Id, IntoId}; + use super::INSFastEnumeration; use crate::{INSArray, INSValue, NSArray, NSValue}; #[test] fn test_enumerator() { - let vec = (0u32..4).map(NSValue::new).collect(); - let array = NSArray::from_vec(vec); + let vec: Vec<_> = (0u32..4).map(NSValue::new).collect(); + let array: Id, _> = vec.into_id(); let enumerator = array.iter(); assert!(enumerator.count() == 4); @@ -186,8 +189,8 @@ mod tests { #[test] fn test_fast_enumerator() { - let vec = (0u32..4).map(NSValue::new).collect(); - let array = NSArray::from_vec(vec); + let vec: Vec<_> = (0u32..4).map(NSValue::new).collect(); + let array: Id, _> = vec.into_id(); let enumerator = array.enumerator(); assert!(enumerator.count() == 4);