Skip to content

Commit 7147f9f

Browse files
committed
Add comments on why the Sync, Send and Drop implementations are safe
Also clean up other comments
1 parent 2ec0185 commit 7147f9f

File tree

2 files changed

+58
-31
lines changed

2 files changed

+58
-31
lines changed

src/rc/owned.rs

Lines changed: 34 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@ use core::ptr::{drop_in_place, NonNull};
99
use super::Retained;
1010
use crate::runtime::{self, Object};
1111

12-
/// A smart pointer that strongly references and owns an Objective-C object.
12+
/// A smart pointer that strongly references and uniquely owns an Objective-C
13+
/// object.
1314
///
14-
/// The fact that we own the pointer means that it's safe to mutate it. As
15-
/// such, this implements [`DerefMut`].
15+
/// The fact that we uniquely own the pointer means that it's safe to mutate
16+
/// it. As such, this implements [`DerefMut`].
1617
///
1718
/// This is guaranteed to have the same size as the underlying pointer.
1819
///
@@ -34,29 +35,31 @@ use crate::runtime::{self, Object};
3435
#[repr(transparent)]
3536
pub struct Owned<T> {
3637
/// The pointer is always retained.
37-
pub(super) ptr: NonNull<T>, // Covariant
38-
phantom: PhantomData<T>, // Necessary for dropcheck
38+
ptr: NonNull<T>, // We are the unique owner of T, so covariance is correct
39+
phantom: PhantomData<T>, // Necessary for dropck
3940
}
4041

41-
// SAFETY: TODO
42+
/// `Owned` pointers are `Send` if `T` is `Send` because they give the same
43+
/// access as having a T directly.
4244
unsafe impl<T: Send> Send for Owned<T> {}
4345

44-
// SAFETY: TODO
46+
/// `Owned` pointers are `Sync` if `T` is `Sync` because they give the same
47+
/// access as having a `T` directly.
4548
unsafe impl<T: Sync> Sync for Owned<T> {}
4649

4750
// TODO: Unsure how the API should look...
4851
impl<T> Owned<T> {
49-
/// TODO
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`.
5056
///
5157
/// # Safety
5258
///
53-
/// The caller must ensure the given object reference has exactly 1 retain
54-
/// count (that is, a retain count that has been handed off from somewhere
55-
/// else, usually Objective-C methods like `init`, `alloc`, `new`, or
56-
/// `copy`).
59+
/// The caller must ensure that there are no other pointers or references
60+
/// to the same object, and the given reference is not be used afterwards.
5761
///
58-
/// Additionally, there must be no other pointers or references to the same
59-
/// object, and the given reference must not be used afterwards.
62+
/// Additionally, the given object reference must have +1 retain count.
6063
///
6164
/// # Example
6265
///
@@ -70,6 +73,7 @@ impl<T> Owned<T> {
7073
/// TODO: Something about there not being other references.
7174
// Note: The fact that we take a `&mut` here is more of a lint; the lifetime
7275
// information is lost, so whatever produced the reference can still be
76+
// mutated or aliased afterwards.
7377
#[inline]
7478
pub unsafe fn new(obj: &mut T) -> Self {
7579
Self {
@@ -78,27 +82,37 @@ impl<T> Owned<T> {
7882
}
7983
}
8084

81-
/// Construct an `Owned` pointer
85+
/// Acquires a `*mut` pointer to the object.
86+
#[inline]
87+
pub fn as_ptr(&self) -> *mut T {
88+
self.ptr.as_ptr()
89+
}
90+
91+
/// Construct an `Owned` pointer from a `Retained` pointer.
8292
///
8393
/// # Safety
8494
///
8595
/// The caller must ensure that there are no other pointers to the same
8696
/// object (which also means that the given [`Retained`] should have a
87-
/// retain count of exactly 1).
97+
/// retain count of exactly 1 in almost all cases).
8898
#[inline]
8999
pub unsafe fn from_retained(obj: Retained<T>) -> Self {
90-
let ptr = mem::ManuallyDrop::new(obj).ptr;
100+
// SAFETY: The pointer is guaranteed by `Retained` to be NonNull
101+
let ptr = NonNull::new_unchecked(mem::ManuallyDrop::new(obj).as_ptr() as *mut T);
91102
Self {
92103
ptr,
93104
phantom: PhantomData,
94105
}
95106
}
96107
}
97108

98-
// TODO: #[may_dangle]
99-
// https://doc.rust-lang.org/nightly/nomicon/dropck.html
109+
/// `#[may_dangle]` (see [this][dropck_eyepatch]) would not be safe here,
110+
/// since we cannot verify that a `dealloc` method doesn't access borrowed
111+
/// data.
112+
///
113+
/// [dropck_eyepatch]: https://doc.rust-lang.org/nightly/nomicon/dropck.html#an-escape-hatch
100114
impl<T> Drop for Owned<T> {
101-
/// Releases the retained object
115+
/// Releases the retained object.
102116
///
103117
/// This is guaranteed to be the last destructor that runs, in contrast to
104118
/// [`Retained`], which means that we can run the [`Drop`] implementation
@@ -114,8 +128,6 @@ impl<T> Drop for Owned<T> {
114128
}
115129
}
116130

117-
// Note: `Clone` is not implemented for this!
118-
119131
impl<T> Deref for Owned<T> {
120132
type Target = T;
121133

src/rc/retained.rs

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -55,16 +55,26 @@ pub struct Retained<T> {
5555
/// https://doc.rust-lang.org/core/ptr/traitalias.Thin.html
5656
///
5757
/// [extern-type-rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1861-extern-types.md
58-
pub(super) ptr: NonNull<T>, // Covariant - but should probably be invariant?
58+
ptr: NonNull<T>, // T is immutable, so covariance is correct
5959
/// TODO:
6060
/// https://github.com/rust-lang/rfcs/blob/master/text/0769-sound-generic-drop.md#phantom-data
6161
phantom: PhantomData<T>,
6262
}
6363

64-
// SAFETY: TODO
64+
/// The `Send` implementation requires `T: Sync` because `Retained` gives
65+
/// access to `&T`.
66+
///
67+
/// Additiontally, it requires `T: Send` because if `T: !Send`, you could
68+
/// clone a `Retained`, send it to another thread, and drop the clone last,
69+
/// making `dealloc` get called on the other thread, violating `T: !Send`.
6570
unsafe impl<T: Sync + Send> Send for Retained<T> {}
6671

67-
// SAFETY: TODO
72+
/// The `Sync` implementation requires `T: Sync` because `&Retained` gives
73+
/// access to `&T`.
74+
///
75+
/// Additiontally, it requires `T: Send`, because if `T: !Send`, you could
76+
/// clone a `&Retained` from another thread, and drop the clone last, making
77+
/// `dealloc` get called on the other thread, violating `T: !Send`.
6878
unsafe impl<T: Sync + Send> Sync for Retained<T> {}
6979

7080
impl<T> Retained<T> {
@@ -73,13 +83,14 @@ impl<T> Retained<T> {
7383
///
7484
/// When dropped, the object will be released.
7585
///
76-
/// See also [`Owned::new`] for the common case of creating objects.
86+
/// This is used when you have a retain count that has been handed off
87+
/// from somewhere else, usually Objective-C methods with the
88+
/// `ns_returns_retained` attribute. See [`Owned::new`] for the more
89+
/// common case when creating objects.
7790
///
7891
/// # Safety
7992
///
80-
/// The caller must ensure the given object reference has +1 retain count
81-
/// (that is, a retain count that has been handed off from somewhere else,
82-
/// usually Objective-C methods with the `ns_returns_retained` attribute).
93+
/// The caller must ensure the given object reference has +1 retain count.
8394
///
8495
/// Additionally, there must be no [`Owned`] pointers to the same object.
8596
///
@@ -92,6 +103,7 @@ impl<T> Retained<T> {
92103
}
93104
}
94105

106+
/// Acquires a `*const` pointer to the object.
95107
#[inline]
96108
pub fn as_ptr(&self) -> *const T {
97109
self.ptr.as_ptr()
@@ -196,8 +208,11 @@ impl<T> Retained<T> {
196208
// }
197209
// }
198210

199-
// TODO: #[may_dangle]
200-
// https://doc.rust-lang.org/nightly/nomicon/dropck.html
211+
/// `#[may_dangle]` (see [this][dropck_eyepatch]) doesn't really make sense
212+
/// here, since we actually want to disallow creating `Retained` pointers to
213+
/// objects that have a `Drop` implementation.
214+
///
215+
/// [dropck_eyepatch]: https://doc.rust-lang.org/nightly/nomicon/dropck.html#an-escape-hatch
201216
impl<T> Drop for Retained<T> {
202217
/// Releases the retained object
203218
#[doc(alias = "objc_release")]

0 commit comments

Comments
 (0)