Skip to content

Commit 6b66590

Browse files
committed
Add rc::Allocated
1 parent aed5cdd commit 6b66590

9 files changed

+147
-70
lines changed

objc2/src/__macro_helpers.rs

+14-15
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::rc::{Id, Ownership};
1+
use crate::rc::{Allocated, Id, Ownership};
22
use crate::runtime::{Class, Sel};
33
use crate::{Message, MessageArguments, MessageError, MessageReceiver};
44

@@ -37,24 +37,22 @@ impl<T: ?Sized + Message, O: Ownership> MsgSendId<&'_ Class, Id<T, O>>
3737
}
3838
}
3939

40-
// `alloc`, should mark the return value as "allocated, not initialized" somehow
41-
impl<T: ?Sized + Message, O: Ownership> MsgSendId<&'_ Class, Id<T, O>>
40+
// `alloc`
41+
impl<T: ?Sized + Message, O: Ownership> MsgSendId<&'_ Class, Id<Allocated<T>, O>>
4242
for Assert<false, true, false, false>
4343
{
4444
#[inline(always)]
4545
unsafe fn send_message_id<A: MessageArguments>(
4646
cls: &Class,
4747
sel: Sel,
4848
args: A,
49-
) -> Result<Option<Id<T, O>>, MessageError> {
50-
unsafe { MessageReceiver::send_message(cls, sel, args).map(|r| Id::new(r)) }
49+
) -> Result<Option<Id<Allocated<T>, O>>, MessageError> {
50+
unsafe { MessageReceiver::send_message(cls, sel, args).map(|r| Id::new_allocated(r)) }
5151
}
5252
}
5353

54-
// `init`, should mark the input value as "allocated, not initialized" somehow
55-
//
56-
// The generic bound allows `init` to take both `Option<Id>` and `Id`.
57-
impl<X: Into<Option<Id<T, O>>>, T: ?Sized + Message, O: Ownership> MsgSendId<X, Id<T, O>>
54+
// `init`. The generic bound allows `init` to take both `Option<Id>` and `Id`.
55+
impl<X: Into<Option<Id<Allocated<T>, O>>>, T: ?Sized + Message, O: Ownership> MsgSendId<X, Id<T, O>>
5856
for Assert<false, false, true, false>
5957
{
6058
#[inline(always)]
@@ -63,7 +61,7 @@ impl<X: Into<Option<Id<T, O>>>, T: ?Sized + Message, O: Ownership> MsgSendId<X,
6361
sel: Sel,
6462
args: A,
6563
) -> Result<Option<Id<T, O>>, MessageError> {
66-
let ptr = Id::option_into_ptr(obj.into());
64+
let ptr = Id::option_into_ptr(obj.into().map(|obj| unsafe { Id::assume_init(obj) }));
6765
// SAFETY: `ptr` may be null here, but that's fine since the return
6866
// is `*mut T`, which is one of the few types where messages to nil is
6967
// allowed.
@@ -151,7 +149,7 @@ mod tests {
151149

152150
use core::ptr;
153151

154-
use crate::rc::{Owned, Shared};
152+
use crate::rc::{Allocated, Owned, Shared};
155153
use crate::runtime::Object;
156154
use crate::{Encoding, RefEncode};
157155

@@ -169,21 +167,22 @@ mod tests {
169167
fn test_macro_alloc() {
170168
let cls = class!(NSObject);
171169

172-
let _obj: Option<Id<Object, Shared>> = unsafe { msg_send_id![cls, alloc] };
170+
let _obj: Option<Id<Allocated<Object>, Shared>> = unsafe { msg_send_id![cls, alloc] };
173171

174172
let zone: *const _NSZone = ptr::null();
175-
let _obj: Option<Id<Object, Owned>> = unsafe { msg_send_id![cls, allocWithZone: zone] };
173+
let _obj: Option<Id<Allocated<Object>, Owned>> =
174+
unsafe { msg_send_id![cls, allocWithZone: zone] };
176175
}
177176

178177
#[test]
179178
fn test_macro_init() {
180179
let cls = class!(NSObject);
181180

182-
let obj: Option<Id<Object, Shared>> = unsafe { msg_send_id![cls, alloc] };
181+
let obj: Option<Id<Allocated<Object>, Shared>> = unsafe { msg_send_id![cls, alloc] };
183182
// Don't check allocation error
184183
let _obj: Id<Object, Shared> = unsafe { msg_send_id![obj, init].unwrap() };
185184

186-
let obj: Option<Id<Object, Shared>> = unsafe { msg_send_id![cls, alloc] };
185+
let obj: Option<Id<Allocated<Object>, Shared>> = unsafe { msg_send_id![cls, alloc] };
187186
// Check allocation error before init
188187
let obj = obj.unwrap();
189188
let _obj: Id<Object, Shared> = unsafe { msg_send_id![obj, init].unwrap() };

objc2/src/rc/allocated.rs

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/// TODO
2+
///
3+
/// The reason we use `Option<Id<Allocated<T>, O>>` instead of just `*mut T`
4+
/// is:
5+
/// - To safely know the object is valid (albeit uninitialized)
6+
/// - To allow specifying ownership
7+
/// - To allow releasing allocated (but yet still uninitialized) objects.
8+
#[repr(transparent)]
9+
pub struct Allocated<T: ?Sized> {
10+
_inner: T,
11+
}
12+
13+
// Explicitly don't implement `Message` nor `RefEncode`!

objc2/src/rc/id.rs

+31-10
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use core::ops::{Deref, DerefMut};
55
use core::panic::{RefUnwindSafe, UnwindSafe};
66
use core::ptr::NonNull;
77

8+
use super::Allocated;
89
use super::AutoreleasePool;
910
use super::{Owned, Ownership, Shared};
1011
use crate::ffi;
@@ -124,6 +125,36 @@ pub struct Id<T: ?Sized, O: Ownership> {
124125
notunwindsafe: PhantomData<&'static mut ()>,
125126
}
126127

128+
impl<T: ?Sized, O: Ownership> Id<T, O> {
129+
#[inline]
130+
unsafe fn new_nonnull(ptr: NonNull<T>) -> Self {
131+
Self {
132+
ptr,
133+
item: PhantomData,
134+
own: PhantomData,
135+
notunwindsafe: PhantomData,
136+
}
137+
}
138+
}
139+
140+
impl<T: Message + ?Sized, O: Ownership> Id<Allocated<T>, O> {
141+
#[inline]
142+
pub(crate) unsafe fn new_allocated(ptr: *mut T) -> Option<Self> {
143+
// SAFETY: Upheld by the caller
144+
NonNull::new(ptr as *mut Allocated<T>).map(|ptr| unsafe { Self::new_nonnull(ptr) })
145+
}
146+
147+
#[inline]
148+
pub(crate) unsafe fn assume_init(this: Self) -> Id<T, O> {
149+
let ptr = ManuallyDrop::new(this).ptr;
150+
let ptr = ptr.as_ptr() as *mut T;
151+
let ptr = unsafe { NonNull::new_unchecked(ptr) };
152+
// SAFETY: The pointer is valid.
153+
// Caller verifies that the object is allocated.
154+
unsafe { Id::new_nonnull(ptr) }
155+
}
156+
}
157+
127158
impl<T: Message + ?Sized, O: Ownership> Id<T, O> {
128159
/// Constructs an [`Id`] to an object that already has +1 retain count.
129160
///
@@ -181,16 +212,6 @@ impl<T: Message + ?Sized, O: Ownership> Id<T, O> {
181212
NonNull::new(ptr).map(|ptr| unsafe { Id::new_nonnull(ptr) })
182213
}
183214

184-
#[inline]
185-
unsafe fn new_nonnull(ptr: NonNull<T>) -> Id<T, O> {
186-
Self {
187-
ptr,
188-
item: PhantomData,
189-
own: PhantomData,
190-
notunwindsafe: PhantomData,
191-
}
192-
}
193-
194215
/// Returns a raw pointer to the object.
195216
///
196217
/// The pointer is valid for at least as long as the `Id` is held.

objc2/src/rc/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
//! assert!(weak.load().is_none());
5656
//! ```
5757
58+
mod allocated;
5859
mod autorelease;
5960
mod id;
6061
mod id_forwarding_impls;
@@ -65,6 +66,7 @@ mod weak_id;
6566
#[cfg(test)]
6667
mod test_object;
6768

69+
pub use self::allocated::Allocated;
6870
pub use self::autorelease::{autoreleasepool, AutoreleasePool, AutoreleaseSafe};
6971
pub use self::id::Id;
7072
pub use self::id_traits::{DefaultId, SliceId, SliceIdMut};

tests/assembly/test_msg_send_id/lib.rs

+7-4
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
//! Test assembly output of `msg_send_id!` internals.
22
use objc2::__macro_helpers::{Assert, MsgSendId};
3-
use objc2::rc::{Id, Shared};
3+
use objc2::rc::{Allocated, Id, Shared};
44
use objc2::runtime::{Class, Object, Sel};
55

66
#[no_mangle]
7-
unsafe fn handle_alloc(obj: &Class, sel: Sel) -> Option<Id<Object, Shared>> {
7+
unsafe fn handle_alloc(obj: &Class, sel: Sel) -> Option<Id<Allocated<Object>, Shared>> {
88
<Assert<false, true, false, false>>::send_message_id(obj, sel, ()).unwrap()
99
}
1010

1111
#[no_mangle]
12-
unsafe fn handle_init(obj: Option<Id<Object, Shared>>, sel: Sel) -> Option<Id<Object, Shared>> {
12+
unsafe fn handle_init(
13+
obj: Option<Id<Allocated<Object>, Shared>>,
14+
sel: Sel,
15+
) -> Option<Id<Object, Shared>> {
1316
<Assert<false, false, true, false>>::send_message_id(obj, sel, ()).unwrap()
1417
}
1518

@@ -21,7 +24,7 @@ unsafe fn handle_alloc_init(obj: &Class, sel1: Sel, sel2: Sel) -> Option<Id<Obje
2124

2225
#[no_mangle]
2326
unsafe fn handle_alloc_release(cls: &Class, sel: Sel) {
24-
let _obj: Id<Object, Shared> =
27+
let _obj: Id<Allocated<Object>, Shared> =
2528
<Assert<false, true, false, false>>::send_message_id(cls, sel, ())
2629
.unwrap()
2730
.unwrap_unchecked();

tests/ui/msg_send_id_invalid_receiver.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
11
//! Test compiler output with invalid msg_send_id receivers.
22
use objc2::msg_send_id;
33
use objc2::runtime::{Class, Object};
4-
use objc2::rc::{Id, Shared};
4+
use objc2::rc::{Allocated, Id, Shared};
55

66
fn main() {
77
let obj: &Object;
88
let _: Id<Object, Shared> = unsafe { msg_send_id![obj, new].unwrap() };
9-
let _: Id<Object, Shared> = unsafe { msg_send_id![obj, alloc].unwrap() };
9+
let _: Id<Allocated<Object>, Shared> = unsafe { msg_send_id![obj, alloc].unwrap() };
1010
let _: Id<Object, Shared> = unsafe { msg_send_id![obj, init].unwrap() };
1111

1212
let cls: &Class;
1313
let _: Id<Object, Shared> = unsafe { msg_send_id![cls, init].unwrap() };
14+
let obj: Id<Object, Shared>;
15+
let _: Id<Object, Shared> = unsafe { msg_send_id![obj, init].unwrap() };
16+
let obj: Option<Id<Object, Shared>>;
17+
let _: Id<Object, Shared> = unsafe { msg_send_id![obj, init].unwrap() };
1418

1519
let obj: Id<Object, Shared>;
1620
let _: Id<Object, Shared> = unsafe { msg_send_id![obj, copy].unwrap() };

tests/ui/msg_send_id_invalid_receiver.stderr

+42-14
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@ note: associated function defined here
1616
| ^^^^^^^^^^^^^^^
1717

1818
error[E0308]: mismatched types
19-
--> ui/msg_send_id_invalid_receiver.rs:9:55
19+
--> ui/msg_send_id_invalid_receiver.rs:9:66
2020
|
21-
9 | let _: Id<Object, Shared> = unsafe { msg_send_id![obj, alloc].unwrap() };
22-
| -------------^^^--------
23-
| | |
24-
| | expected struct `objc2::runtime::Class`, found struct `objc2::runtime::Object`
25-
| arguments to this function are incorrect
21+
9 | let _: Id<Allocated<Object>, Shared> = unsafe { msg_send_id![obj, alloc].unwrap() };
22+
| -------------^^^--------
23+
| | |
24+
| | expected struct `objc2::runtime::Class`, found struct `objc2::runtime::Object`
25+
| arguments to this function are incorrect
2626
|
2727
= note: expected reference `&objc2::runtime::Class`
2828
found reference `&objc2::runtime::Object`
@@ -32,38 +32,66 @@ note: associated function defined here
3232
| unsafe fn send_message_id<A: MessageArguments>(
3333
| ^^^^^^^^^^^^^^^
3434

35-
error[E0277]: the trait bound `Option<Id<_, _>>: From<&objc2::runtime::Object>` is not satisfied
35+
error[E0277]: the trait bound `Option<Id<Allocated<_>, _>>: From<&objc2::runtime::Object>` is not satisfied
3636
--> ui/msg_send_id_invalid_receiver.rs:10:42
3737
|
3838
10 | let _: Id<Object, Shared> = unsafe { msg_send_id![obj, init].unwrap() };
39-
| ^^^^^^^^^^^^^^^^^^^^^^^ the trait `From<&objc2::runtime::Object>` is not implemented for `Option<Id<_, _>>`
39+
| ^^^^^^^^^^^^^^^^^^^^^^^ the trait `From<&objc2::runtime::Object>` is not implemented for `Option<Id<Allocated<_>, _>>`
4040
|
4141
= help: the following other types implement trait `From<T>`:
4242
<Option<&'a T> as From<&'a Option<T>>>
4343
<Option<&'a mut T> as From<&'a mut Option<T>>>
4444
<Option<T> as From<T>>
45-
= note: required because of the requirements on the impl of `Into<Option<Id<_, _>>>` for `&objc2::runtime::Object`
45+
= note: required because of the requirements on the impl of `Into<Option<Id<Allocated<_>, _>>>` for `&objc2::runtime::Object`
4646
= note: required because of the requirements on the impl of `MsgSendId<&objc2::runtime::Object, Id<_, _>>` for `Assert<false, false, true, false>`
4747
= note: this error originates in the macro `msg_send_id` (in Nightly builds, run with -Z macro-backtrace for more info)
4848

49-
error[E0277]: the trait bound `Option<Id<_, _>>: From<&objc2::runtime::Class>` is not satisfied
49+
error[E0277]: the trait bound `Option<Id<Allocated<_>, _>>: From<&objc2::runtime::Class>` is not satisfied
5050
--> ui/msg_send_id_invalid_receiver.rs:13:42
5151
|
5252
13 | let _: Id<Object, Shared> = unsafe { msg_send_id![cls, init].unwrap() };
53-
| ^^^^^^^^^^^^^^^^^^^^^^^ the trait `From<&objc2::runtime::Class>` is not implemented for `Option<Id<_, _>>`
53+
| ^^^^^^^^^^^^^^^^^^^^^^^ the trait `From<&objc2::runtime::Class>` is not implemented for `Option<Id<Allocated<_>, _>>`
5454
|
5555
= help: the following other types implement trait `From<T>`:
5656
<Option<&'a T> as From<&'a Option<T>>>
5757
<Option<&'a mut T> as From<&'a mut Option<T>>>
5858
<Option<T> as From<T>>
59-
= note: required because of the requirements on the impl of `Into<Option<Id<_, _>>>` for `&objc2::runtime::Class`
59+
= note: required because of the requirements on the impl of `Into<Option<Id<Allocated<_>, _>>>` for `&objc2::runtime::Class`
6060
= note: required because of the requirements on the impl of `MsgSendId<&objc2::runtime::Class, Id<_, _>>` for `Assert<false, false, true, false>`
6161
= note: this error originates in the macro `msg_send_id` (in Nightly builds, run with -Z macro-backtrace for more info)
6262

63+
error[E0277]: the trait bound `Option<Id<Allocated<_>, _>>: From<Id<objc2::runtime::Object, Shared>>` is not satisfied
64+
--> ui/msg_send_id_invalid_receiver.rs:15:42
65+
|
66+
15 | let _: Id<Object, Shared> = unsafe { msg_send_id![obj, init].unwrap() };
67+
| ^^^^^^^^^^^^^^^^^^^^^^^ the trait `From<Id<objc2::runtime::Object, Shared>>` is not implemented for `Option<Id<Allocated<_>, _>>`
68+
|
69+
= help: the following other types implement trait `From<T>`:
70+
<Option<&'a T> as From<&'a Option<T>>>
71+
<Option<&'a mut T> as From<&'a mut Option<T>>>
72+
<Option<T> as From<T>>
73+
= note: required because of the requirements on the impl of `Into<Option<Id<Allocated<_>, _>>>` for `Id<objc2::runtime::Object, Shared>`
74+
= note: required because of the requirements on the impl of `MsgSendId<Id<objc2::runtime::Object, Shared>, Id<_, _>>` for `Assert<false, false, true, false>`
75+
= note: this error originates in the macro `msg_send_id` (in Nightly builds, run with -Z macro-backtrace for more info)
76+
77+
error[E0277]: the trait bound `Option<Id<Allocated<_>, _>>: From<Option<Id<objc2::runtime::Object, Shared>>>` is not satisfied
78+
--> ui/msg_send_id_invalid_receiver.rs:17:42
79+
|
80+
17 | let _: Id<Object, Shared> = unsafe { msg_send_id![obj, init].unwrap() };
81+
| ^^^^^^^^^^^^^^^^^^^^^^^ the trait `From<Option<Id<objc2::runtime::Object, Shared>>>` is not implemented for `Option<Id<Allocated<_>, _>>`
82+
|
83+
= help: the following other types implement trait `From<T>`:
84+
<Option<&'a T> as From<&'a Option<T>>>
85+
<Option<&'a mut T> as From<&'a mut Option<T>>>
86+
<Option<T> as From<T>>
87+
= note: required because of the requirements on the impl of `Into<Option<Id<Allocated<_>, _>>>` for `Option<Id<objc2::runtime::Object, Shared>>`
88+
= note: required because of the requirements on the impl of `MsgSendId<Option<Id<objc2::runtime::Object, Shared>>, Id<_, _>>` for `Assert<false, false, true, false>`
89+
= note: this error originates in the macro `msg_send_id` (in Nightly builds, run with -Z macro-backtrace for more info)
90+
6391
error[E0277]: the trait bound `Id<objc2::runtime::Object, Shared>: MessageReceiver` is not satisfied
64-
--> ui/msg_send_id_invalid_receiver.rs:16:42
92+
--> ui/msg_send_id_invalid_receiver.rs:20:42
6593
|
66-
16 | let _: Id<Object, Shared> = unsafe { msg_send_id![obj, copy].unwrap() };
94+
20 | let _: Id<Object, Shared> = unsafe { msg_send_id![obj, copy].unwrap() };
6795
| ^^^^^^^^^^^^^^^^^^^^^^^ the trait `MessageReceiver` is not implemented for `Id<objc2::runtime::Object, Shared>`
6896
|
6997
= help: the following other types implement trait `MessageReceiver`:

tests/ui/msg_send_id_invalid_return.rs

+7-6
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,24 @@
11
//! Test compiler output with invalid msg_send_id receivers.
22
use objc2::msg_send_id;
33
use objc2::runtime::{Class, Object};
4-
use objc2::rc::{Id, Owned, Shared};
4+
use objc2::rc::{Allocated, Id, Owned, Shared};
55
use objc2_foundation::NSObject;
66

77
fn main() {
88
let cls: &Class;
99
let _: &Object = unsafe { msg_send_id![cls, new].unwrap() };
1010
let _: Id<Class, Shared> = unsafe { msg_send_id![cls, new].unwrap() };
1111
let _: &Object = unsafe { msg_send_id![cls, alloc].unwrap() };
12-
let _: Id<Class, Shared> = unsafe { msg_send_id![cls, alloc].unwrap() };
12+
let _: Id<Allocated<Class>, Shared> = unsafe { msg_send_id![cls, alloc].unwrap() };
13+
let _: Id<Object, Shared> = unsafe { msg_send_id![cls, alloc].unwrap() };
1314

14-
let obj: Option<Id<Object, Shared>>;
15+
let obj: Option<Id<Allocated<Object>, Shared>>;
1516
let _: &Object = unsafe { msg_send_id![obj, init].unwrap() };
16-
let obj: Option<Id<Object, Shared>>;
17+
let obj: Option<Id<Allocated<Object>, Shared>>;
1718
let _: Id<Class, Shared> = unsafe { msg_send_id![obj, init].unwrap() };
18-
let obj: Option<Id<Object, Shared>>;
19+
let obj: Option<Id<Allocated<Object>, Shared>>;
1920
let _: Id<NSObject, Shared> = unsafe { msg_send_id![obj, init].unwrap() };
20-
let obj: Option<Id<Object, Shared>>;
21+
let obj: Option<Id<Allocated<Object>, Shared>>;
2122
let _: Id<Object, Owned> = unsafe { msg_send_id![obj, init].unwrap() };
2223

2324
let obj: Id<Object, Shared>;

0 commit comments

Comments
 (0)