Skip to content

Commit 41170ef

Browse files
committed
Merge branch 'smart-references' into id-improvements
2 parents 39c7ac1 + d067bbd commit 41170ef

File tree

3 files changed

+582
-17
lines changed

3 files changed

+582
-17
lines changed

objc2/src/rc/mod.rs

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,14 @@ assert!(weak.load().is_null());
3939
*/
4040

4141
mod autorelease;
42+
mod owned;
43+
mod retained;
4244
mod strong;
4345
mod weak;
4446

4547
pub use self::autorelease::{autoreleasepool, AutoreleasePool, AutoreleaseSafe};
48+
pub use self::owned::Owned;
49+
pub use self::retained::Retained;
4650
pub use self::strong::StrongPtr;
4751
pub use self::weak::WeakPtr;
4852

@@ -53,23 +57,6 @@ mod tests {
5357
use super::StrongPtr;
5458
use crate::runtime::Object;
5559

56-
#[test]
57-
fn test_strong_clone() {
58-
fn retain_count(obj: *mut Object) -> usize {
59-
unsafe { msg_send![obj, retainCount] }
60-
}
61-
62-
let obj = unsafe { StrongPtr::new(msg_send![class!(NSObject), new]) };
63-
assert!(retain_count(*obj) == 1);
64-
65-
let cloned = obj.clone();
66-
assert!(retain_count(*cloned) == 2);
67-
assert!(retain_count(*obj) == 2);
68-
69-
drop(obj);
70-
assert!(retain_count(*cloned) == 1);
71-
}
72-
7360
#[test]
7461
fn test_weak() {
7562
let obj = unsafe { StrongPtr::new(msg_send![class!(NSObject), new]) };

objc2/src/rc/owned.rs

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
use core::borrow;
2+
use core::fmt;
3+
use core::hash;
4+
use core::marker::PhantomData;
5+
use core::mem;
6+
use core::ops::{Deref, DerefMut};
7+
use core::ptr::{drop_in_place, NonNull};
8+
9+
use super::AutoreleasePool;
10+
use super::Retained;
11+
12+
/// A smart pointer that strongly references and uniquely owns an Objective-C
13+
/// object.
14+
///
15+
/// The fact that we uniquely own the pointer means that it's safe to mutate
16+
/// it. As such, this implements [`DerefMut`].
17+
///
18+
/// This is guaranteed to have the same size as the underlying pointer.
19+
///
20+
/// # Cloning and [`Retained`]
21+
///
22+
/// This does not implement [`Clone`], but [`Retained`] has a [`From`]
23+
/// implementation to convert from this, so you can easily reliquish ownership
24+
/// and work with a clonable [`Retained`] pointer.
25+
///
26+
/// ```no_run
27+
/// let obj: Owned<T> = ...;
28+
/// let retained: Retained<T> = obj.into();
29+
/// let cloned: Retained<T> = retained.clone();
30+
/// ```
31+
///
32+
/// TODO: Explain similarities to [`Box`].
33+
///
34+
/// TODO: Explain this vs. [`Retained`]
35+
#[repr(transparent)]
36+
pub struct Owned<T> {
37+
/// The pointer is always retained.
38+
ptr: NonNull<T>, // We are the unique owner of T, so covariance is correct
39+
phantom: PhantomData<T>, // Necessary for dropck
40+
}
41+
42+
/// `Owned` pointers are `Send` if `T` is `Send` because they give the same
43+
/// access as having a T directly.
44+
unsafe impl<T: Send> Send for Owned<T> {}
45+
46+
/// `Owned` pointers are `Sync` if `T` is `Sync` because they give the same
47+
/// access as having a `T` directly.
48+
unsafe impl<T: Sync> Sync for Owned<T> {}
49+
50+
// TODO: Unsure how the API should look...
51+
impl<T> Owned<T> {
52+
/// Create a new `Owned` pointer to the object.
53+
///
54+
/// Uses a retain count that has been handed off from somewhere else,
55+
/// usually Objective-C methods like `init`, `alloc`, `new`, or `copy`.
56+
///
57+
/// # Safety
58+
///
59+
/// The caller must ensure that there are no other pointers or references
60+
/// to the same object, and the given pointer is not be used afterwards.
61+
///
62+
/// Additionally, the given object pointer must have +1 retain count.
63+
///
64+
/// And lastly, the object pointer must be valid as a mutable reference
65+
/// (non-null, aligned, dereferencable, initialized and upholds aliasing
66+
/// rules, see the [`std::ptr`] module for more information).
67+
///
68+
/// # Example
69+
///
70+
/// ```rust
71+
/// let obj: &mut Object = unsafe { msg_send![cls, alloc] };
72+
/// let obj: Owned<Object> = unsafe { Owned::new(msg_send![obj, init]) };
73+
/// // Or in this case simply just:
74+
/// let obj: Owned<Object> = unsafe { Owned::new(msg_send![cls, new]) };
75+
/// ```
76+
#[inline]
77+
// Note: We don't take a mutable reference as a parameter since it would
78+
// be too easy to accidentally create two aliasing mutable references.
79+
pub unsafe fn new(ptr: *mut T) -> Self {
80+
Self {
81+
// SAFETY: Upheld by the caller
82+
ptr: NonNull::new_unchecked(ptr),
83+
phantom: PhantomData,
84+
}
85+
}
86+
87+
/// Acquires a `*mut` pointer to the object.
88+
#[inline]
89+
pub fn as_ptr(&self) -> *mut T {
90+
self.ptr.as_ptr()
91+
}
92+
93+
/// Construct an `Owned` pointer from a `Retained` pointer.
94+
///
95+
/// # Safety
96+
///
97+
/// The caller must ensure that there are no other pointers to the same
98+
/// object (which also means that the given [`Retained`] should have a
99+
/// retain count of exactly 1 in almost all cases).
100+
#[inline]
101+
pub unsafe fn from_retained(obj: Retained<T>) -> Self {
102+
// SAFETY: The pointer is guaranteed by `Retained` to be NonNull
103+
let ptr = NonNull::new_unchecked(mem::ManuallyDrop::new(obj).as_ptr() as *mut T);
104+
Self {
105+
ptr,
106+
phantom: PhantomData,
107+
}
108+
}
109+
110+
/// Autoreleases the retained pointer, meaning that the object is not
111+
/// immediately released, but will be when the innermost / current
112+
/// autorelease pool is drained.
113+
#[doc(alias = "objc_autorelease")]
114+
#[must_use = "If you don't intend to use the object any more, just drop it as usual"]
115+
#[inline]
116+
pub fn autorelease<'p>(self, pool: &'p AutoreleasePool) -> &'p mut T {
117+
let retained: Retained<T> = self.into();
118+
let ptr = retained.autorelease(pool) as *const T as *mut T;
119+
// SAFETY: The pointer was previously `Owned`, so is safe to be mutable
120+
unsafe { &mut *ptr }
121+
}
122+
}
123+
124+
/// `#[may_dangle]` (see [this][dropck_eyepatch]) would not be safe here,
125+
/// since we cannot verify that a `dealloc` method doesn't access borrowed
126+
/// data.
127+
///
128+
/// [dropck_eyepatch]: https://doc.rust-lang.org/nightly/nomicon/dropck.html#an-escape-hatch
129+
impl<T> Drop for Owned<T> {
130+
/// Releases the retained object.
131+
///
132+
/// This is guaranteed to be the last destructor that runs, in contrast to
133+
/// [`Retained`], which means that we can run the [`Drop`] implementation
134+
/// on the contained object as well.
135+
#[inline]
136+
fn drop(&mut self) {
137+
let ptr = self.as_ptr();
138+
unsafe {
139+
drop_in_place(ptr);
140+
// Construct a new `Retained`, which will be dropped immediately
141+
Retained::new(ptr);
142+
};
143+
}
144+
}
145+
146+
impl<T> Deref for Owned<T> {
147+
type Target = T;
148+
149+
#[inline]
150+
fn deref(&self) -> &Self::Target {
151+
// SAFETY: TODO
152+
unsafe { self.ptr.as_ref() }
153+
}
154+
}
155+
156+
impl<T> DerefMut for Owned<T> {
157+
#[inline]
158+
fn deref_mut(&mut self) -> &mut Self::Target {
159+
// SAFETY: TODO
160+
unsafe { self.ptr.as_mut() }
161+
}
162+
}
163+
164+
// TODO: impl PartialEq, PartialOrd, Ord and Eq
165+
166+
impl<T: fmt::Display> fmt::Display for Owned<T> {
167+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
168+
fmt::Display::fmt(&**self, f)
169+
}
170+
}
171+
172+
impl<T: fmt::Debug> fmt::Debug for Owned<T> {
173+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
174+
fmt::Debug::fmt(&**self, f)
175+
}
176+
}
177+
178+
impl<T> fmt::Pointer for Owned<T> {
179+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
180+
fmt::Pointer::fmt(&self.as_ptr(), f)
181+
}
182+
}
183+
184+
impl<T: hash::Hash> hash::Hash for Owned<T> {
185+
fn hash<H: hash::Hasher>(&self, state: &mut H) {
186+
(&**self).hash(state)
187+
}
188+
}
189+
190+
// TODO: impl Fn traits? See `boxed_closure_impls`
191+
192+
// TODO: CoerceUnsized
193+
194+
impl<T> borrow::Borrow<T> for Owned<T> {
195+
fn borrow(&self) -> &T {
196+
&**self
197+
}
198+
}
199+
200+
impl<T> borrow::BorrowMut<T> for Owned<T> {
201+
fn borrow_mut(&mut self) -> &mut T {
202+
&mut **self
203+
}
204+
}
205+
206+
impl<T> AsRef<T> for Owned<T> {
207+
fn as_ref(&self) -> &T {
208+
&**self
209+
}
210+
}
211+
212+
impl<T> AsMut<T> for Owned<T> {
213+
fn as_mut(&mut self) -> &mut T {
214+
&mut **self
215+
}
216+
}
217+
218+
// TODO: Comment on impl Unpin for Box
219+
impl<T> Unpin for Owned<T> {}

0 commit comments

Comments
 (0)