Skip to content

Commit 481d817

Browse files
committed
Implement AsRef<T> and AsMut<T> for T in object! macro
1 parent 378fcea commit 481d817

File tree

3 files changed

+68
-8
lines changed

3 files changed

+68
-8
lines changed

objc2-foundation/src/data.rs

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ unsafe fn data_from_vec(cls: &Class, bytes: Vec<u8>) -> *mut Object {
336336

337337
#[cfg(test)]
338338
mod tests {
339-
use super::{NSData, NSMutableData};
339+
use super::*;
340340
#[cfg(feature = "block")]
341341
use alloc::vec;
342342

@@ -431,4 +431,41 @@ mod tests {
431431
data.extend(iter);
432432
assert_eq!(data.bytes(), &[1, 2, 3, 4, 5]);
433433
}
434+
435+
#[test]
436+
fn test_as_ref() {
437+
fn impls_as_ref<T: AsRef<U> + ?Sized, U: ?Sized>(_: &T) {}
438+
fn impls_as_mut<T: AsMut<U> + ?Sized, U: ?Sized>(_: &mut T) {}
439+
440+
let mut obj = NSMutableData::new();
441+
impls_as_ref::<Id<NSMutableData, Owned>, NSMutableData>(&obj);
442+
impls_as_mut::<Id<NSMutableData, Owned>, NSMutableData>(&mut obj);
443+
444+
impls_as_ref::<NSMutableData, NSMutableData>(&obj);
445+
impls_as_mut::<NSMutableData, NSMutableData>(&mut obj);
446+
impls_as_ref::<NSMutableData, NSData>(&obj);
447+
impls_as_mut::<NSMutableData, NSData>(&mut obj);
448+
impls_as_ref::<NSMutableData, NSObject>(&obj);
449+
impls_as_mut::<NSMutableData, NSObject>(&mut obj);
450+
impls_as_ref::<NSMutableData, Object>(&obj);
451+
impls_as_mut::<NSMutableData, Object>(&mut obj);
452+
453+
impls_as_ref::<NSData, NSData>(&obj);
454+
impls_as_mut::<NSData, NSData>(&mut obj);
455+
impls_as_ref::<NSData, NSObject>(&obj);
456+
impls_as_mut::<NSData, NSObject>(&mut obj);
457+
impls_as_ref::<NSData, Object>(&obj);
458+
impls_as_mut::<NSData, Object>(&mut obj);
459+
460+
impls_as_ref::<NSMutableData, [u8]>(&obj);
461+
impls_as_mut::<NSMutableData, [u8]>(&mut obj);
462+
impls_as_ref::<NSData, [u8]>(&obj);
463+
464+
let obj: &mut NSMutableData = &mut *obj;
465+
let _: &[u8] = obj.as_ref();
466+
let _: &mut [u8] = obj.as_mut();
467+
468+
let obj: &mut NSData = &mut **obj;
469+
let _: &[u8] = obj.as_ref();
470+
}
434471
}

objc2-foundation/src/macros.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,16 @@ macro_rules! __impl_as_ref_as_mut {
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

@@ -125,7 +127,7 @@ macro_rules! object {
125127
}
126128
}
127129

128-
__impl_as_ref_as_mut!($name<$($t $(: $b)?),*>, $inherits, $($inheritance_rest,)*);
130+
__impl_as_ref_as_mut!($name<$($t $(: $b)?),*>, $name<$($t),*>, $inherits, $($inheritance_rest,)*);
129131

130132
// Objective-C equality has approximately the same semantics as Rust
131133
// equality (although less aptly specified).
@@ -166,13 +168,12 @@ macro_rules! object {
166168
// TODO: Consider T: Debug bound
167169
impl<$($t $(: $b)?),*> ::core::fmt::Debug for $name<$($t),*> {
168170
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
169-
use ::objc2::MessageReceiver;
170171
use ::alloc::borrow::ToOwned;
171172
use $crate::NSObject;
172173
// "downgrading" to NSObject and calling `to_owned` to work
173174
// around `f` and Self not being AutoreleaseSafe.
174175
// TODO: Fix this!
175-
let this: &NSObject = unsafe { &*self.as_raw_receiver().cast() };
176+
let this: &NSObject = self.as_ref();
176177
let s = ::objc2::rc::autoreleasepool(|pool| {
177178
this.description().as_str(pool).to_owned()
178179
});

objc2-foundation/src/object.rs

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,32 @@ 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() {
61+
fn impls_as_ref<T: AsRef<U> + ?Sized, U: ?Sized>(_: &T) {}
62+
fn impls_as_mut<T: AsMut<U> + ?Sized, U: ?Sized>(_: &mut T) {}
63+
64+
let mut obj = NSObject::new();
65+
impls_as_ref::<Id<NSObject, Owned>, NSObject>(&obj);
66+
impls_as_mut::<Id<NSObject, Owned>, NSObject>(&mut obj);
67+
impls_as_ref::<NSObject, NSObject>(&obj);
68+
impls_as_mut::<NSObject, NSObject>(&mut obj);
69+
impls_as_ref::<NSObject, Object>(&obj);
70+
impls_as_mut::<NSObject, Object>(&mut obj);
71+
}
72+
5173
#[test]
5274
fn test_equality() {
5375
let obj1 = NSObject::new();

0 commit comments

Comments
 (0)