Skip to content

WIP: Add API for associated objects #481

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions crates/objc2/src/macros/associated_object.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
macro_rules! associated_object {
(
$(#[$m:meta])*
impl $name:ident {
$v_getter:vis fn $getter_name:ident(&self) -> $getter_ty:ty;
$v_setter:vis fn $setter_name:ident(&self, $setter_param:ident: $setter_ty:ty);
}
) => {
const _: () = {
static mut __KEY: u8 = 0;

$(#[$m])*
impl $name {
$v_getter fn $getter_name(&self) -> $getter_ty {

}

$v_setter fn $setter_name(&self, $setter_param: $setter_ty) {

}
}
}
};
}
1 change: 1 addition & 0 deletions crates/objc2/src/macros/mod.rs
Original file line number Diff line number Diff line change
@@ -6,6 +6,7 @@ mod __rewrite_self_arg;
mod declare_class;
mod extern_class;
mod extern_methods;
mod associated_object;
mod extern_protocol;

/// Gets a reference to an [`AnyClass`] from the given name.
90 changes: 90 additions & 0 deletions crates/objc2/src/runtime/associated_object.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
use core::ptr;

use super::Object;
use crate::rc::{Id, Shared};
use crate::ffi;

/// Associated object support.
///
/// These are associated functions, since they are very rarely used, and will
/// mostly just clutter up the `Deref` chain and documentation of all other
/// classes in `icrate`.
///
/// See [Apple's documentation](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocAssociativeReferences.html).
impl Object {
///
///
/// # Panics
///
/// This may panic or abort the process if the specified object does not
/// support associated objects.
unsafe fn set_associated_ptr<K>(this: &Self, key: &K, value: *const ()) {
let key: *const K = key;
// SAFETY: The object and key is non-null
//
// Caller ensures that the key is uniquely used for the expected
// operation.
unsafe {
ffi::objc_setAssociatedObject(this.as_ptr(), key.cast(), value as *mut _, ffi::OBJC_ASSOCIATION_ASSIGN)
}
}

unsafe fn set_associated_id<K, T>(this: &Self, key: &K, value: Option<&Id<T, Shared>>) {
let key: *const K = key;
let ptr: *const T = value.map(|value| Id::as_ptr(value)).unwrap_or(ptr::null());
// SAFETY: The object and key is non-null, and the value came from
// a shared `Id`, so it is safe to retain.
//
// Caller ensures that the key is uniquely used for the expected
// operation.
unsafe {
ffi::objc_setAssociatedObject(
this.as_ptr(),
key.cast(),
ptr.cast(),
ffi::OBJC_ASSOCIATION_RETAIN,
)
}
}

unsafe fn get_associated_ptr<K>(this: &Self, key: &K) -> *const () {
let key: *const K = key;
// SAFETY:
unsafe { ffi::objc_getAssociatedObject(this.as_ptr(), key.cast()).cast() }
}

unsafe fn get_associated_id<K, T>(this: &Self, key: &K) -> Id<T, Shared> {
let ptr = this.get_associated_ptr(key) as *mut T;
// SAFETY: Caller upholds that the associated object stores an `Id`,
// and that the `Id` was originally `Shared`.
unsafe { Id::retain_autoreleased(ptr) }
}

unsafe fn remove_associated<K, T>(this: &Self, key: &K) {
let key: *const K = key;
// SAFETY: The object and key is non-null, and the associated is being
// broken, so the policy doesn't matter.
//
// Caller ensures that the key is uniquely used for the expected
// operation.
unsafe {
ffi::objc_setAssociatedObject(
this.as_ptr(),
key.cast(),
ptr::null(),
ffi::OBJC_ASSOCIATION_ASSIGN,
)
}
}

fn remove_all_associated(this: &Self) {
// SAFETY:
unsafe { ffi::objc_removeAssociatedObjects(this.as_ptr()) }
}

// objc_setAssociatedObject
// objc_getAssociatedObject
// objc_removeAssociatedObjects

// https://nshipster.com/associated-objects/
}
4 changes: 0 additions & 4 deletions crates/objc2/src/runtime/mod.rs
Original file line number Diff line number Diff line change
@@ -1265,10 +1265,6 @@ impl AnyObject {
// SAFETY: Invariants upheld by caller
unsafe { *self.ivar_mut::<T>(name) = value };
}

// objc_setAssociatedObject
// objc_getAssociatedObject
// objc_removeAssociatedObjects
}

impl fmt::Debug for AnyObject {