Skip to content

Commit

Permalink
Implement mutability marker traits for ProtocolObject as well
Browse files Browse the repository at this point in the history
  • Loading branch information
madsmtm committed Sep 11, 2023
1 parent 2f6e76b commit 2b6d4a2
Show file tree
Hide file tree
Showing 21 changed files with 260 additions and 93 deletions.
20 changes: 10 additions & 10 deletions crates/icrate/src/additions/Foundation/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -391,15 +391,15 @@ __impl_iter! {
pub struct IterMut<'a, T: Message>(iter::IterMut<'a, NSArray<T>>);

__impl_iter! {
impl<'a, T: IsMutable> Iterator<Item = &'a mut T> for IterMut<'a, T> { ... }
impl<'a, T: Message + IsMutable> Iterator<Item = &'a mut T> for IterMut<'a, T> { ... }
}

/// An iterator that retains the items of a `NSArray`.
#[derive(Debug)]
pub struct IterRetained<'a, T: Message>(iter::IterRetained<'a, NSArray<T>>);

__impl_iter! {
impl<'a, T: IsIdCloneable> Iterator<Item = Id<T>> for IterRetained<'a, T> { ... }
impl<'a, T: Message + IsIdCloneable> Iterator<Item = Id<T>> for IterRetained<'a, T> { ... }
}

/// A consuming iterator over the items of a `NSArray`.
Expand All @@ -420,16 +420,16 @@ __impl_into_iter! {
type IntoIter = Iter<'_, T>;
}

impl<T: IsMutable> IntoIterator for &mut NSArray<T> {
impl<T: Message + IsMutable> IntoIterator for &mut NSArray<T> {
type IntoIter = IterMut<'_, T>;
}

#[cfg(feature = "Foundation_NSMutableArray")]
impl<T: IsMutable> IntoIterator for &mut NSMutableArray<T> {
impl<T: Message + IsMutable> IntoIterator for &mut NSMutableArray<T> {
type IntoIter = IterMut<'_, T>;
}

impl<T: IsIdCloneable> IntoIterator for Id<NSArray<T>> {
impl<T: Message + IsIdCloneable> IntoIterator for Id<NSArray<T>> {
type IntoIter = IntoIter<T>;
}

Expand All @@ -456,14 +456,14 @@ impl<T: Message> Index<usize> for NSMutableArray<T> {
}
}

impl<T: IsMutable> IndexMut<usize> for NSArray<T> {
impl<T: Message + IsMutable> IndexMut<usize> for NSArray<T> {
fn index_mut(&mut self, index: usize) -> &mut T {
self.get_mut(index).unwrap()
}
}

#[cfg(feature = "Foundation_NSMutableArray")]
impl<T: IsMutable> IndexMut<usize> for NSMutableArray<T> {
impl<T: Message + IsMutable> IndexMut<usize> for NSMutableArray<T> {
fn index_mut(&mut self, index: usize) -> &mut T {
self.get_mut(index).unwrap()
}
Expand All @@ -484,7 +484,7 @@ impl<T: Message> Extend<Id<T>> for NSMutableArray<T> {
}

#[cfg(feature = "Foundation_NSMutableArray")]
impl<'a, T: IsRetainable> Extend<&'a T> for NSMutableArray<T> {
impl<'a, T: Message + IsRetainable> Extend<&'a T> for NSMutableArray<T> {
fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
// SAFETY: Because of the `T: IsRetainable` bound, it is safe for the
// array to retain the object here.
Expand All @@ -493,7 +493,7 @@ impl<'a, T: IsRetainable> Extend<&'a T> for NSMutableArray<T> {
}
}

impl<'a, T: IsRetainable + 'a> IdFromIterator<&'a T> for NSArray<T> {
impl<'a, T: Message + IsRetainable + 'a> IdFromIterator<&'a T> for NSArray<T> {
fn id_from_iter<I: IntoIterator<Item = &'a T>>(iter: I) -> Id<Self> {
let vec = Vec::from_iter(iter);
Self::from_slice(&vec)
Expand All @@ -508,7 +508,7 @@ impl<T: Message> IdFromIterator<Id<T>> for NSArray<T> {
}

#[cfg(feature = "Foundation_NSMutableArray")]
impl<'a, T: IsRetainable + 'a> IdFromIterator<&'a T> for NSMutableArray<T> {
impl<'a, T: Message + IsRetainable + 'a> IdFromIterator<&'a T> for NSMutableArray<T> {
fn id_from_iter<I: IntoIterator<Item = &'a T>>(iter: I) -> Id<Self> {
let vec = Vec::from_iter(iter);
Self::from_slice(&vec)
Expand Down
12 changes: 7 additions & 5 deletions crates/icrate/src/additions/Foundation/dictionary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -516,7 +516,7 @@ mod iter_helpers {
);

__impl_iter! {
impl<'a, K: IsIdCloneable, V: Message> Iterator<Item = Id<K>> for KeysRetained<'a, K, V> { ... }
impl<'a, K: Message + IsIdCloneable, V: Message> Iterator<Item = Id<K>> for KeysRetained<'a, K, V> { ... }
}

/// An iterator over the values of a `NSDictionary`.
Expand All @@ -536,7 +536,7 @@ mod iter_helpers {
);

__impl_iter! {
impl<'a, K: Message, V: IsMutable> Iterator<Item = &'a mut V> for ValuesMut<'a, K, V> { ... }
impl<'a, K: Message, V: Message + IsMutable> Iterator<Item = &'a mut V> for ValuesMut<'a, K, V> { ... }
}

/// A iterator that retains the values of a `NSDictionary`.
Expand All @@ -546,7 +546,7 @@ mod iter_helpers {
);

__impl_iter! {
impl<'a, K: Message, V: IsIdCloneable> Iterator<Item = Id<V>> for ValuesRetained<'a, K, V> { ... }
impl<'a, K: Message, V: Message + IsIdCloneable> Iterator<Item = Id<V>> for ValuesRetained<'a, K, V> { ... }
}

/// A consuming iterator over the values of a `NSDictionary`.
Expand Down Expand Up @@ -580,14 +580,16 @@ impl<'a, K: Message + Eq + Hash, V: Message> Index<&'a K> for NSMutableDictionar
}
}

impl<'a, K: Message + Eq + Hash, V: IsMutable> IndexMut<&'a K> for NSDictionary<K, V> {
impl<'a, K: Message + Eq + Hash, V: Message + IsMutable> IndexMut<&'a K> for NSDictionary<K, V> {
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 + Eq + Hash, V: IsMutable> IndexMut<&'a K> for NSMutableDictionary<K, V> {
impl<'a, K: Message + Eq + Hash, V: Message + IsMutable> IndexMut<&'a K>
for NSMutableDictionary<K, V>
{
fn index_mut<'s>(&'s mut self, index: &'a K) -> &'s mut V {
self.get_mut(index).unwrap()
}
Expand Down
2 changes: 0 additions & 2 deletions crates/icrate/src/additions/Foundation/enumerator.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
//! Utilities for the `NSEnumerator` class.
#![cfg(feature = "Foundation_NSEnumerator")]
use objc2::mutability::{IsIdCloneable, IsMutable};

use super::iter;
use crate::common::*;
use crate::Foundation::NSEnumerator;
Expand Down
16 changes: 8 additions & 8 deletions crates/icrate/src/additions/Foundation/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -428,7 +428,7 @@ impl<C: FastEnumerationHelper> IntoIter<C> {
}
}

pub(crate) fn new_mutable<T: IsMutable + ClassType<Super = C>>(collection: Id<T>) -> Self
pub(crate) fn new_mutable<T: ClassType<Super = C> + IsMutable>(collection: Id<T>) -> Self
where
C: IsIdCloneable,
{
Expand Down Expand Up @@ -648,7 +648,7 @@ where
}
}

pub(crate) unsafe fn new_mutable<T: IsMutable + ClassType<Super = C>>(
pub(crate) unsafe fn new_mutable<T: ClassType<Super = C> + IsMutable>(
collection: Id<T>,
enumerator: Id<E>,
) -> Self
Expand Down Expand Up @@ -696,9 +696,9 @@ where
#[doc(hidden)]
macro_rules! __impl_iter {
(
impl<$($lifetime:lifetime, )? $t1:ident: $bound1:ident $(, $t2:ident: $bound2:ident)?> Iterator<Item = $item:ty> for $for:ty { ... }
impl<$($lifetime:lifetime, )? $t1:ident: $bound1:ident $(+ $bound1_b:ident)? $(, $t2:ident: $bound2:ident $(+ $bound2_b:ident)?)?> Iterator<Item = $item:ty> for $for:ty { ... }
) => {
impl<$($lifetime, )? $t1: $bound1 $(, $t2: $bound2)?> Iterator for $for {
impl<$($lifetime, )? $t1: $bound1 $(+ $bound1_b)? $(, $t2: $bound2 $(+ $bound2_b)?)?> Iterator for $for {
type Item = $item;

#[inline]
Expand Down Expand Up @@ -743,14 +743,14 @@ macro_rules! __impl_into_iter {
};
(
$(#[$m:meta])*
impl<T: IsMutable> IntoIterator for &mut $ty:ident<T> {
impl<T: Message + IsMutable> IntoIterator for &mut $ty:ident<T> {
type IntoIter = $iter_mut:ident<'_, T>;
}

$($rest:tt)*
) => {
$(#[$m])*
impl<'a, T: IsMutable> IntoIterator for &'a mut $ty<T> {
impl<'a, T: Message + IsMutable> IntoIterator for &'a mut $ty<T> {
type Item = &'a mut T;
type IntoIter = $iter_mut<'a, T>;

Expand All @@ -766,14 +766,14 @@ macro_rules! __impl_into_iter {
};
(
$(#[$m:meta])*
impl<T: IsIdCloneable> IntoIterator for Id<$ty:ident<T>> {
impl<T: Message + IsIdCloneable> IntoIterator for Id<$ty:ident<T>> {
type IntoIter = $into_iter:ident<T>;
}

$($rest:tt)*
) => {
$(#[$m])*
impl<T: IsIdCloneable> objc2::rc::IdIntoIterator for $ty<T> {
impl<T: Message + IsIdCloneable> objc2::rc::IdIntoIterator for $ty<T> {
type Item = Id<T>;
type IntoIter = $into_iter<T>;

Expand Down
12 changes: 7 additions & 5 deletions crates/icrate/src/additions/Foundation/set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -501,7 +501,7 @@ __impl_iter! {
pub struct IterRetained<'a, T: Message>(iter::IterRetained<'a, NSSet<T>>);

__impl_iter! {
impl<'a, T: IsIdCloneable> Iterator<Item = Id<T>> for IterRetained<'a, T> { ... }
impl<'a, T: Message + IsIdCloneable> Iterator<Item = Id<T>> for IterRetained<'a, T> { ... }
}

/// A consuming iterator over the items of a `NSSet`.
Expand All @@ -522,7 +522,7 @@ __impl_into_iter! {
type IntoIter = Iter<'_, T>;
}

impl<T: IsIdCloneable> IntoIterator for Id<NSSet<T>> {
impl<T: Message + IsIdCloneable> IntoIterator for Id<NSSet<T>> {
type IntoIter = IntoIter<T>;
}

Expand All @@ -549,15 +549,17 @@ impl<T: Message + Eq + Hash + HasStableHash> Extend<Id<T>> for NSMutableSet<T> {
}

#[cfg(feature = "Foundation_NSMutableSet")]
impl<'a, T: IsRetainable + Eq + Hash + HasStableHash> Extend<&'a T> for NSMutableSet<T> {
impl<'a, T: Message + Eq + Hash + HasStableHash + IsRetainable> Extend<&'a T> for NSMutableSet<T> {
fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
iter.into_iter().for_each(move |item| {
self.insert(item);
})
}
}

impl<'a, T: IsRetainable + Eq + Hash + HasStableHash + 'a> IdFromIterator<&'a T> for NSSet<T> {
impl<'a, T: Message + Eq + Hash + HasStableHash + IsRetainable + 'a> IdFromIterator<&'a T>
for NSSet<T>
{
fn id_from_iter<I: IntoIterator<Item = &'a T>>(iter: I) -> Id<Self> {
let vec = Vec::from_iter(iter);
Self::from_slice(&vec)
Expand All @@ -572,7 +574,7 @@ impl<T: Message + Eq + Hash + HasStableHash> IdFromIterator<Id<T>> for NSSet<T>
}

#[cfg(feature = "Foundation_NSMutableSet")]
impl<'a, T: IsRetainable + Eq + Hash + HasStableHash + 'a> IdFromIterator<&'a T>
impl<'a, T: Message + Eq + Hash + HasStableHash + IsRetainable + 'a> IdFromIterator<&'a T>
for NSMutableSet<T>
{
fn id_from_iter<I: IntoIterator<Item = &'a T>>(iter: I) -> Id<Self> {
Expand Down
2 changes: 1 addition & 1 deletion crates/icrate/src/additions/Foundation/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ pub(crate) fn id_ptr_cast_const<T: ?Sized>(objects: *const Id<T>) -> *mut NonNul
#[inline]
pub(crate) unsafe fn collection_retain_id<T>(obj: &T) -> Id<T>
where
T: IsIdCloneable,
T: Message + IsIdCloneable,
{
// SAFETY: We're allowed to access `&Id<T>` from `&self` in collections,
// and since `T: IsIdCloneable`, we can convert that to `Id<T>`.
Expand Down
8 changes: 4 additions & 4 deletions crates/icrate/src/fixes/Foundation/copy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ use crate::common::*;
use crate::Foundation::{self, NSCopying, NSMutableCopying};

#[cfg(feature = "Foundation_NSArray")]
impl<T: IsIdCloneable> ToOwned for Foundation::NSArray<T> {
impl<T: Message + IsIdCloneable> ToOwned for Foundation::NSArray<T> {
type Owned = Id<Self>;
fn to_owned(&self) -> Self::Owned {
self.copy()
}
}

#[cfg(feature = "Foundation_NSMutableArray")]
impl<T: IsIdCloneable> ToOwned for Foundation::NSMutableArray<T> {
impl<T: Message + IsIdCloneable> ToOwned for Foundation::NSMutableArray<T> {
type Owned = Id<Self>;
fn to_owned(&self) -> Self::Owned {
self.mutableCopy()
Expand Down Expand Up @@ -44,15 +44,15 @@ impl ToOwned for Foundation::NSException {
}

#[cfg(feature = "Foundation_NSSet")]
impl<T: IsIdCloneable> ToOwned for Foundation::NSSet<T> {
impl<T: Message + IsIdCloneable> ToOwned for Foundation::NSSet<T> {
type Owned = Id<Self>;
fn to_owned(&self) -> Self::Owned {
self.copy()
}
}

#[cfg(feature = "Foundation_NSMutableSet")]
impl<T: IsIdCloneable> ToOwned for Foundation::NSMutableSet<T> {
impl<T: Message + IsIdCloneable> ToOwned for Foundation::NSMutableSet<T> {
type Owned = Id<Self>;
fn to_owned(&self) -> Self::Owned {
self.mutableCopy()
Expand Down
25 changes: 23 additions & 2 deletions crates/icrate/tests/array.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
#![cfg(feature = "Foundation_NSArray")]
#![cfg(feature = "Foundation_NSNumber")]
use icrate::Foundation::{NSArray, NSNumber, NSObject};
use objc2::rc::Id;
use objc2::rc::{__RcTestObject, __ThreadTestData};
use objc2::mutability::IsRetainable;
use objc2::rc::{Id, __RcTestObject, __ThreadTestData};
use objc2::runtime::ProtocolObject;
use objc2::{extern_protocol, ProtocolType};

fn sample_array(len: usize) -> Id<NSArray<NSObject>> {
let mut vec = Vec::with_capacity(len);
Expand Down Expand Up @@ -262,3 +264,22 @@ fn test_generic_ownership_traits() {

assert_partialeq::<NSArray<NSObject>>();
}

#[test]
fn test_trait_retainable() {
extern_protocol!(
#[allow(clippy::missing_safety_doc)]
unsafe trait TestProtocol: IsRetainable {}

unsafe impl ProtocolType for dyn TestProtocol {
const NAME: &'static str = "NSObject";
}
);

unsafe impl TestProtocol for NSNumber {}

let obj: Id<ProtocolObject<dyn TestProtocol>> = ProtocolObject::from_id(NSNumber::new_i32(42));
let _ = NSArray::from_slice(&[&*obj, &*obj]);
let _ = NSArray::from_id_slice(&[obj.clone(), obj.clone()]);
let _ = NSArray::from_vec(vec![obj.clone(), obj.clone()]);
}
18 changes: 18 additions & 0 deletions crates/icrate/tests/copying.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#![cfg(feature = "Foundation")]
#![cfg(feature = "Foundation_NSString")]
use icrate::Foundation::{NSCopying, NSMutableCopying, NSString};
use objc2::{rc::Id, runtime::ProtocolObject};

#[test]
fn copy() {
let obj = NSString::new();
let protocol_object: &ProtocolObject<dyn NSCopying> = ProtocolObject::from_ref(&*obj);
let _: Id<ProtocolObject<dyn NSCopying>> = protocol_object.copy();
}

#[test]
fn copy_mutable() {
let obj = NSString::new();
let protocol_object: &ProtocolObject<dyn NSMutableCopying> = ProtocolObject::from_ref(&*obj);
let _: Id<ProtocolObject<dyn NSMutableCopying>> = protocol_object.mutableCopy();
}
7 changes: 7 additions & 0 deletions crates/objc2/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Changed
* **BREAKING**: `AnyClass::verify_sel` now take more well-defined types
`EncodeArguments` and `EncodeReturn`.
* **BREAKING**: Changed how the `mutability` traits work; these no longer have
`ClassType` as a super trait, allowing them to work for `ProtocolObject` as
well.

This effectively means you can now `copy` a `ProtocolObject<dyn NSCopying>`.
* **BREAKING**: Allow implementing `DefaultId` for any type, not just those
who are `IsAllocableAnyThread`.

### Deprecated
* Soft deprecated using `msg_send!` without a comma between arguments (i.e.
Expand Down
10 changes: 5 additions & 5 deletions crates/objc2/src/declare/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,17 +167,17 @@ pub trait MethodImplementation: private::Sealed + Sized {
}

macro_rules! method_decl_impl {
(@<$($l:lifetime),*> T: $t_bound:ident, $r:ident, $f:ty, $($t:ident),*) => {
(@<$($l:lifetime),*> T: $t_bound:ident $(+ $t_bound2:ident)?, $r:ident, $f:ty, $($t:ident),*) => {
impl<$($l,)* T, $r, $($t),*> private::Sealed for $f
where
T: ?Sized + $t_bound,
T: ?Sized + $t_bound $(+ $t_bound2)?,
$r: EncodeReturn,
$($t: EncodeArgument,)*
{}

impl<$($l,)* T, $r, $($t),*> MethodImplementation for $f
where
T: ?Sized + $t_bound,
T: ?Sized + $t_bound $(+ $t_bound2)?,
$r: EncodeReturn,
$($t: EncodeArgument,)*
{
Expand Down Expand Up @@ -244,11 +244,11 @@ macro_rules! method_decl_impl {
};
(# $abi:literal; $($t:ident),*) => {
method_decl_impl!(@<'a> T: Message, R, extern $abi fn(&'a T, Sel $(, $t)*) -> R, $($t),*);
method_decl_impl!(@<'a> T: IsMutable, R, extern $abi fn(&'a mut T, Sel $(, $t)*) -> R, $($t),*);
method_decl_impl!(@<'a> T: Message + IsMutable, R, extern $abi fn(&'a mut T, Sel $(, $t)*) -> R, $($t),*);
method_decl_impl!(@<> T: Message, R, unsafe extern $abi fn(*const T, Sel $(, $t)*) -> R, $($t),*);
method_decl_impl!(@<> T: Message, R, unsafe extern $abi fn(*mut T, Sel $(, $t)*) -> R, $($t),*);
method_decl_impl!(@<'a> T: Message, R, unsafe extern $abi fn(&'a T, Sel $(, $t)*) -> R, $($t),*);
method_decl_impl!(@<'a> T: IsMutable, R, unsafe extern $abi fn(&'a mut T, Sel $(, $t)*) -> R, $($t),*);
method_decl_impl!(@<'a> T: Message + IsMutable, R, unsafe extern $abi fn(&'a mut T, Sel $(, $t)*) -> R, $($t),*);

method_decl_impl!(@<'a> AnyObject, R, extern $abi fn(&'a mut AnyObject, Sel $(, $t)*) -> R, $($t),*);
method_decl_impl!(@<'a> AnyObject, R, unsafe extern $abi fn(&'a mut AnyObject, Sel $(, $t)*) -> R, $($t),*);
Expand Down
Loading

0 comments on commit 2b6d4a2

Please sign in to comment.