Skip to content

Commit 9a80136

Browse files
committed
Add API for associated objects
1 parent ee2afe2 commit 9a80136

File tree

4 files changed

+113
-4
lines changed

4 files changed

+113
-4
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
macro_rules! associated_object {
2+
(
3+
$(#[$m:meta])*
4+
impl $name:ident {
5+
$v:vis fn $setter_name:ident(&self, $setter_param:ident: $setter_ty:ty);
6+
$v:vis fn $getter_name:ident(&self) -> $getter_ty:ty;
7+
}
8+
) => {
9+
static mut __KEY: u8 = 0;
10+
11+
$(#[$m])*
12+
impl $name {
13+
$v fn $setter_name(&self, $setter_param: $setter_ty) {
14+
15+
}
16+
17+
$v fn $getter_name(&self) -> $getter_ty {
18+
19+
}
20+
}
21+
};
22+
}

crates/objc2/src/macros/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ mod __rewrite_self_arg;
66
mod declare_class;
77
mod extern_class;
88
mod extern_methods;
9+
mod associated_object;
910
mod extern_protocol;
1011

1112
/// Gets a reference to a [`Class`] from the given name.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
use core::ptr;
2+
3+
use super::Object;
4+
use crate::rc::{Id, Shared};
5+
use crate::ffi;
6+
7+
/// Associated object support.
8+
///
9+
/// These are associated functions, since they are very rarely used, and will
10+
/// mostly just clutter up the `Deref` chain and documentation of all other
11+
/// classes in `icrate`.
12+
///
13+
/// See [Apple's documentation](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocAssociativeReferences.html).
14+
impl Object {
15+
///
16+
///
17+
/// # Panics
18+
///
19+
/// This may panic or abort the process if the specified object does not
20+
/// support associated objects.
21+
unsafe fn set_associated_ptr<K>(this: &Self, key: &K, value: *const ()) {
22+
let key: *const K = key;
23+
// SAFETY: The object and key is non-null
24+
//
25+
// Caller ensures that the key is uniquely used for the expected
26+
// operation.
27+
unsafe {
28+
ffi::objc_setAssociatedObject(this.as_ptr(), key.cast(), value as *mut _, ffi::OBJC_ASSOCIATION_ASSIGN)
29+
}
30+
}
31+
32+
unsafe fn set_associated_id<K, T>(this: &Self, key: &K, value: Option<&Id<T, Shared>>) {
33+
let key: *const K = key;
34+
let ptr: *const T = value.map(|value| Id::as_ptr(value)).unwrap_or(ptr::null());
35+
// SAFETY: The object and key is non-null, and the value came from
36+
// a shared `Id`, so it is safe to retain.
37+
//
38+
// Caller ensures that the key is uniquely used for the expected
39+
// operation.
40+
unsafe {
41+
ffi::objc_setAssociatedObject(
42+
this.as_ptr(),
43+
key.cast(),
44+
ptr.cast(),
45+
ffi::OBJC_ASSOCIATION_RETAIN,
46+
)
47+
}
48+
}
49+
50+
unsafe fn get_associated_ptr<K>(this: &Self, key: &K) -> *const () {
51+
let key: *const K = key;
52+
// SAFETY:
53+
unsafe { ffi::objc_getAssociatedObject(this.as_ptr(), key.cast()).cast() }
54+
}
55+
56+
unsafe fn get_associated_id<K, T>(this: &Self, key: &K) -> Id<T, Shared> {
57+
let ptr = this.get_associated_ptr(key) as *mut T;
58+
// SAFETY: Caller upholds that the associated object stores an `Id`,
59+
// and that the `Id` was originally `Shared`.
60+
unsafe { Id::retain_autoreleased(ptr) }
61+
}
62+
63+
unsafe fn remove_associated<K, T>(this: &Self, key: &K) {
64+
let key: *const K = key;
65+
// SAFETY: The object and key is non-null, and the associated is being
66+
// broken, so the policy doesn't matter.
67+
//
68+
// Caller ensures that the key is uniquely used for the expected
69+
// operation.
70+
unsafe {
71+
ffi::objc_setAssociatedObject(
72+
this.as_ptr(),
73+
key.cast(),
74+
ptr::null(),
75+
ffi::OBJC_ASSOCIATION_ASSIGN,
76+
)
77+
}
78+
}
79+
80+
fn remove_all_associated(this: &Self) {
81+
// SAFETY:
82+
unsafe { ffi::objc_removeAssociatedObjects(this.as_ptr()) }
83+
}
84+
85+
// objc_setAssociatedObject
86+
// objc_getAssociatedObject
87+
// objc_removeAssociatedObjects
88+
89+
// https://nshipster.com/associated-objects/
90+
}

crates/objc2/src/runtime/mod.rs

-4
Original file line numberDiff line numberDiff line change
@@ -1005,10 +1005,6 @@ impl Object {
10051005
// SAFETY: Invariants upheld by caller
10061006
unsafe { *self.ivar_mut::<T>(name) = value };
10071007
}
1008-
1009-
// objc_setAssociatedObject
1010-
// objc_getAssociatedObject
1011-
// objc_removeAssociatedObjects
10121008
}
10131009

10141010
impl fmt::Debug for Object {

0 commit comments

Comments
 (0)