Skip to content

Commit 42b847a

Browse files
authored
Merge pull request #158 from madsmtm/foundation-traits
Implement `AsRef`/`AsMut` that forward to objects themselves. Implement `Borrow`/`BorrowMut` for objects. Implement `ToOwned` using `NSCopying`/`NSMutableCopying` where appropriate.
2 parents 378fcea + 5f5ff6c commit 42b847a

File tree

11 files changed

+189
-11
lines changed

11 files changed

+189
-11
lines changed

objc2-foundation/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
2828
* Added `NSPoint`.
2929
* Added `NSSize`.
3030
* Added `NSRect`.
31+
* Implement `Borrow` and `BorrowMut` for all objects.
32+
* Implement `ToOwned` for copyable types.
3133

3234
### Changed
3335
* **BREAKING**: Removed the following helper traits in favor of inherent

objc2-foundation/src/array.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,13 @@ unsafe impl<T: Message> NSMutableCopying for NSArray<T, Shared> {
185185
type Output = NSMutableArray<T, Shared>;
186186
}
187187

188+
impl<T: Message> alloc::borrow::ToOwned for NSArray<T, Shared> {
189+
type Owned = Id<NSArray<T, Shared>, Shared>;
190+
fn to_owned(&self) -> Self::Owned {
191+
self.copy()
192+
}
193+
}
194+
188195
unsafe impl<T: Message, O: Ownership> NSFastEnumeration for NSArray<T, O> {
189196
type Item = T;
190197
}
@@ -334,6 +341,13 @@ unsafe impl<T: Message> NSMutableCopying for NSMutableArray<T, Shared> {
334341
type Output = NSMutableArray<T, Shared>;
335342
}
336343

344+
impl<T: Message> alloc::borrow::ToOwned for NSMutableArray<T, Shared> {
345+
type Owned = Id<NSMutableArray<T, Shared>, Owned>;
346+
fn to_owned(&self) -> Self::Owned {
347+
self.mutable_copy()
348+
}
349+
}
350+
337351
unsafe impl<T: Message, O: Ownership> NSFastEnumeration for NSMutableArray<T, O> {
338352
type Item = T;
339353
}

objc2-foundation/src/attributed_string.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,13 @@ unsafe impl NSMutableCopying for NSAttributedString {
118118
type Output = NSMutableAttributedString;
119119
}
120120

121+
impl alloc::borrow::ToOwned for NSAttributedString {
122+
type Owned = Id<NSAttributedString, Shared>;
123+
fn to_owned(&self) -> Self::Owned {
124+
self.copy()
125+
}
126+
}
127+
121128
#[cfg(test)]
122129
mod tests {
123130
use alloc::string::ToString;

objc2-foundation/src/data.rs

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,12 +92,22 @@ unsafe impl NSMutableCopying for NSData {
9292
type Output = NSMutableData;
9393
}
9494

95+
impl alloc::borrow::ToOwned for NSData {
96+
type Owned = Id<NSData, Shared>;
97+
fn to_owned(&self) -> Self::Owned {
98+
self.copy()
99+
}
100+
}
101+
95102
impl AsRef<[u8]> for NSData {
96103
fn as_ref(&self) -> &[u8] {
97104
self.bytes()
98105
}
99106
}
100107

108+
// Note: We don't implement `Borrow<[u8]>` since we can't guarantee that `Eq`,
109+
// `Ord` and `Hash` are equal for `NSData` vs. `[u8]`!
110+
101111
impl<I: SliceIndex<[u8]>> Index<I> for NSData {
102112
type Output = I::Output;
103113

@@ -217,6 +227,13 @@ unsafe impl NSMutableCopying for NSMutableData {
217227
type Output = NSMutableData;
218228
}
219229

230+
impl alloc::borrow::ToOwned for NSMutableData {
231+
type Owned = Id<NSMutableData, Owned>;
232+
fn to_owned(&self) -> Self::Owned {
233+
self.mutable_copy()
234+
}
235+
}
236+
220237
impl AsRef<[u8]> for NSMutableData {
221238
fn as_ref(&self) -> &[u8] {
222239
self.bytes()
@@ -336,7 +353,7 @@ unsafe fn data_from_vec(cls: &Class, bytes: Vec<u8>) -> *mut Object {
336353

337354
#[cfg(test)]
338355
mod tests {
339-
use super::{NSData, NSMutableData};
356+
use super::*;
340357
#[cfg(feature = "block")]
341358
use alloc::vec;
342359

@@ -431,4 +448,46 @@ mod tests {
431448
data.extend(iter);
432449
assert_eq!(data.bytes(), &[1, 2, 3, 4, 5]);
433450
}
451+
452+
#[test]
453+
fn test_as_ref_borrow() {
454+
use core::borrow::{Borrow, BorrowMut};
455+
456+
fn impls_borrow<T: AsRef<U> + Borrow<U> + ?Sized, U: ?Sized>(_: &T) {}
457+
fn impls_borrow_mut<T: AsMut<U> + BorrowMut<U> + ?Sized, U: ?Sized>(_: &mut T) {}
458+
459+
let mut obj = NSMutableData::new();
460+
impls_borrow::<Id<NSMutableData, Owned>, NSMutableData>(&obj);
461+
impls_borrow_mut::<Id<NSMutableData, Owned>, NSMutableData>(&mut obj);
462+
463+
impls_borrow::<NSMutableData, NSMutableData>(&obj);
464+
impls_borrow_mut::<NSMutableData, NSMutableData>(&mut obj);
465+
impls_borrow::<NSMutableData, NSData>(&obj);
466+
impls_borrow_mut::<NSMutableData, NSData>(&mut obj);
467+
impls_borrow::<NSMutableData, NSObject>(&obj);
468+
impls_borrow_mut::<NSMutableData, NSObject>(&mut obj);
469+
impls_borrow::<NSMutableData, Object>(&obj);
470+
impls_borrow_mut::<NSMutableData, Object>(&mut obj);
471+
472+
impls_borrow::<NSData, NSData>(&obj);
473+
impls_borrow_mut::<NSData, NSData>(&mut obj);
474+
impls_borrow::<NSData, NSObject>(&obj);
475+
impls_borrow_mut::<NSData, NSObject>(&mut obj);
476+
impls_borrow::<NSData, Object>(&obj);
477+
impls_borrow_mut::<NSData, Object>(&mut obj);
478+
479+
fn impls_as_ref<T: AsRef<U> + ?Sized, U: ?Sized>(_: &T) {}
480+
fn impls_as_mut<T: AsMut<U> + ?Sized, U: ?Sized>(_: &mut T) {}
481+
482+
impls_as_ref::<NSMutableData, [u8]>(&obj);
483+
impls_as_mut::<NSMutableData, [u8]>(&mut obj);
484+
impls_as_ref::<NSData, [u8]>(&obj);
485+
486+
let obj: &mut NSMutableData = &mut *obj;
487+
let _: &[u8] = obj.as_ref();
488+
let _: &mut [u8] = obj.as_mut();
489+
490+
let obj: &mut NSData = &mut **obj;
491+
let _: &[u8] = obj.as_ref();
492+
}
434493
}

objc2-foundation/src/macros.rs

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,45 @@
1-
macro_rules! __impl_as_ref_as_mut {
1+
macro_rules! __impl_as_ref_borrow {
22
($name:ident<$($t:ident $(: $b:ident)?),*>,) => {};
33
($name:ident<$($t:ident $(: $b:ident)?),*>, $item:ty, $($tail:ty,)*) => {
44
impl<$($t $(: $b)?),*> AsRef<$item> for $name<$($t),*> {
55
#[inline]
66
fn as_ref(&self) -> &$item {
7-
&**self
7+
// Triggers Deref coercion depending on return type
8+
&*self
89
}
910
}
1011

1112
impl<$($t $(: $b)?),*> AsMut<$item> for $name<$($t),*> {
1213
#[inline]
1314
fn as_mut(&mut self) -> &mut $item {
14-
&mut **self
15+
// Triggers DerefMut coercion depending on return type
16+
&mut *self
1517
}
1618
}
1719

18-
__impl_as_ref_as_mut!($name<$($t $(: $b)?),*>, $($tail,)*);
20+
// Borrow and BorrowMut are correct, since subclasses behaves
21+
// identical to the class they inherit (message sending doesn't care).
22+
//
23+
// In particular, `Eq`, `Ord` and `Hash` all give the same results
24+
// after borrow.
25+
26+
impl<$($t $(: $b)?),*> ::core::borrow::Borrow<$item> for $name<$($t),*> {
27+
#[inline]
28+
fn borrow(&self) -> &$item {
29+
// Triggers Deref coercion depending on return type
30+
&*self
31+
}
32+
}
33+
34+
impl<$($t $(: $b)?),*> ::core::borrow::BorrowMut<$item> for $name<$($t),*> {
35+
#[inline]
36+
fn borrow_mut(&mut self) -> &mut $item {
37+
// Triggers Deref coercion depending on return type
38+
&mut *self
39+
}
40+
}
41+
42+
__impl_as_ref_borrow!($name<$($t $(: $b)?),*>, $($tail,)*);
1943
};
2044
}
2145

@@ -125,7 +149,21 @@ macro_rules! object {
125149
}
126150
}
127151

128-
__impl_as_ref_as_mut!($name<$($t $(: $b)?),*>, $inherits, $($inheritance_rest,)*);
152+
impl<$($t $(: $b)?),*> AsRef<Self> for $name<$($t),*> {
153+
#[inline]
154+
fn as_ref(&self) -> &Self {
155+
self
156+
}
157+
}
158+
159+
impl<$($t $(: $b)?),*> AsMut<Self> for $name<$($t),*> {
160+
#[inline]
161+
fn as_mut(&mut self) -> &mut Self {
162+
self
163+
}
164+
}
165+
166+
__impl_as_ref_borrow!($name<$($t $(: $b)?),*>, $inherits, $($inheritance_rest,)*);
129167

130168
// Objective-C equality has approximately the same semantics as Rust
131169
// equality (although less aptly specified).
@@ -166,13 +204,12 @@ macro_rules! object {
166204
// TODO: Consider T: Debug bound
167205
impl<$($t $(: $b)?),*> ::core::fmt::Debug for $name<$($t),*> {
168206
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
169-
use ::objc2::MessageReceiver;
170207
use ::alloc::borrow::ToOwned;
171208
use $crate::NSObject;
172209
// "downgrading" to NSObject and calling `to_owned` to work
173210
// around `f` and Self not being AutoreleaseSafe.
174211
// TODO: Fix this!
175-
let this: &NSObject = unsafe { &*self.as_raw_receiver().cast() };
212+
let this: &NSObject = self.as_ref();
176213
let s = ::objc2::rc::autoreleasepool(|pool| {
177214
this.description().as_str(pool).to_owned()
178215
});

objc2-foundation/src/mutable_attributed_string.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,13 @@ unsafe impl NSMutableCopying for NSMutableAttributedString {
7474
type Output = NSMutableAttributedString;
7575
}
7676

77+
impl alloc::borrow::ToOwned for NSMutableAttributedString {
78+
type Owned = Id<NSMutableAttributedString, Owned>;
79+
fn to_owned(&self) -> Self::Owned {
80+
self.mutable_copy()
81+
}
82+
}
83+
7784
#[cfg(test)]
7885
mod tests {
7986
use alloc::string::ToString;

objc2-foundation/src/mutable_string.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,13 @@ unsafe impl NSMutableCopying for NSMutableString {
9696
type Output = NSMutableString;
9797
}
9898

99+
impl alloc::borrow::ToOwned for NSMutableString {
100+
type Owned = Id<NSMutableString, Owned>;
101+
fn to_owned(&self) -> Self::Owned {
102+
self.mutable_copy()
103+
}
104+
}
105+
99106
impl AddAssign<&NSString> for NSMutableString {
100107
#[inline]
101108
fn add_assign(&mut self, other: &NSString) {

objc2-foundation/src/object.rs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,34 @@ impl DefaultId for NSObject {
4444

4545
#[cfg(test)]
4646
mod tests {
47-
use super::NSObject;
48-
use crate::NSString;
47+
use super::*;
4948
use alloc::format;
5049

50+
#[test]
51+
fn test_deref() {
52+
let mut obj: Id<NSObject, Owned> = NSObject::new();
53+
let _: &NSObject = &*obj;
54+
let _: &mut NSObject = &mut *obj;
55+
let _: &Object = &*obj;
56+
let _: &mut Object = &mut *obj;
57+
}
58+
59+
#[test]
60+
fn test_as_ref_borrow() {
61+
use core::borrow::{Borrow, BorrowMut};
62+
63+
fn impls_as_ref<T: AsRef<U> + Borrow<U> + ?Sized, U: ?Sized>(_: &T) {}
64+
fn impls_as_mut<T: AsMut<U> + BorrowMut<U> + ?Sized, U: ?Sized>(_: &mut T) {}
65+
66+
let mut obj = NSObject::new();
67+
impls_as_ref::<Id<NSObject, Owned>, NSObject>(&obj);
68+
impls_as_mut::<Id<NSObject, Owned>, NSObject>(&mut obj);
69+
impls_as_ref::<NSObject, NSObject>(&obj);
70+
impls_as_mut::<NSObject, NSObject>(&mut obj);
71+
impls_as_ref::<NSObject, Object>(&obj);
72+
impls_as_mut::<NSObject, Object>(&mut obj);
73+
}
74+
5175
#[test]
5276
fn test_equality() {
5377
let obj1 = NSObject::new();

objc2-foundation/src/string.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use alloc::borrow::ToOwned;
12
use core::cmp;
23
use core::ffi::c_void;
34
use core::fmt;
@@ -6,7 +7,6 @@ use core::slice;
67
use core::str;
78
use std::os::raw::c_char;
89

9-
use alloc::borrow::ToOwned;
1010
use objc2::ffi;
1111
use objc2::rc::DefaultId;
1212
use objc2::rc::{autoreleasepool, AutoreleasePool};
@@ -255,6 +255,13 @@ unsafe impl NSMutableCopying for NSString {
255255
type Output = NSMutableString;
256256
}
257257

258+
impl ToOwned for NSString {
259+
type Owned = Id<NSString, Shared>;
260+
fn to_owned(&self) -> Self::Owned {
261+
self.copy()
262+
}
263+
}
264+
258265
impl fmt::Display for NSString {
259266
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
260267
// The call to `to_owned` is unfortunate, but is required to work

objc2-foundation/src/uuid.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,13 @@ unsafe impl NSCopying for NSUUID {
6868
type Output = NSUUID;
6969
}
7070

71+
impl alloc::borrow::ToOwned for NSUUID {
72+
type Owned = Id<NSUUID, Shared>;
73+
fn to_owned(&self) -> Self::Owned {
74+
self.copy()
75+
}
76+
}
77+
7178
#[cfg(test)]
7279
mod tests {
7380
use super::*;

0 commit comments

Comments
 (0)