Skip to content

Commit

Permalink
Add ObjectType
Browse files Browse the repository at this point in the history
  • Loading branch information
madsmtm committed Nov 3, 2021
1 parent a52b847 commit 80d9463
Show file tree
Hide file tree
Showing 7 changed files with 44 additions and 40 deletions.
30 changes: 9 additions & 21 deletions objc2-foundation/examples/custom_class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::sync::Once;

use objc2::declare::ClassDecl;
use objc2::rc::{Id, Owned};
use objc2::runtime::{Class, Object, Sel};
use objc2::runtime::{Class, Object, ObjectType, Sel};
use objc2::{msg_send, sel};
use objc2::{Encoding, Message, RefEncode};
use objc2_foundation::{INSObject, NSObject};
Expand All @@ -21,6 +21,8 @@ pub struct MYObject {
unsafe impl RefEncode for MYObject {
const ENCODING_REF: Encoding<'static> = Encoding::Object;
}
unsafe impl Message for MYObject {}
unsafe impl ObjectType for MYObject {}

impl MYObject {
fn new() -> Id<Self, <Self as INSObject>::Ownership> {
Expand All @@ -29,22 +31,14 @@ impl MYObject {
}

fn number(&self) -> u32 {
unsafe {
let obj = &*(self as *const _ as *const Object);
*obj.get_ivar("_number")
}
unsafe { *self.get_ivar("_number") }
}

fn set_number(&mut self, number: u32) {
unsafe {
let obj = &mut *(self as *mut _ as *mut Object);
obj.set_ivar("_number", number);
}
unsafe { self.set_ivar("_number", number) }
}
}

unsafe impl Message for MYObject {}

static MYOBJECT_REGISTER_CLASS: Once = Once::new();

unsafe impl INSObject for MYObject {
Expand All @@ -58,9 +52,7 @@ unsafe impl INSObject for MYObject {

// Add ObjC methods for getting and setting the number
extern "C" fn my_object_set_number(this: &mut Object, _cmd: Sel, number: u32) {
unsafe {
this.set_ivar("_number", number);
}
unsafe { this.set_ivar("_number", number) }
}

extern "C" fn my_object_get_number(this: &Object, _cmd: Sel) -> u32 {
Expand All @@ -85,13 +77,9 @@ fn main() {
let mut obj = MYObject::new();

obj.set_number(7);
println!("Number: {}", unsafe {
let number: u32 = msg_send![obj, number];
number
});
let number: u32 = unsafe { msg_send![obj, number] };
println!("Number: {}", number);

unsafe {
let _: () = msg_send![obj, setNumber: 12u32];
}
let _: () = unsafe { msg_send![obj, setNumber: 12u32] };
println!("Number: {}", obj.number());
}
2 changes: 1 addition & 1 deletion objc2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ one ivar, a `u32` named `_number` and a `number` method that returns it:
```rust , no_run
use objc2::{class, sel};
use objc2::declare::ClassDecl;
use objc2::runtime::{Object, Sel};
use objc2::runtime::{Object, ObjectType, Sel};

let superclass = class!(NSObject);
let mut decl = ClassDecl::new("MyNumber", superclass).unwrap();
Expand Down
2 changes: 1 addition & 1 deletion objc2/examples/introspection.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use core::ptr::NonNull;

use objc2::rc::{Id, Owned};
use objc2::runtime::{Class, Object};
use objc2::runtime::{Class, Object, ObjectType};
use objc2::{class, msg_send, sel, Encode};

fn main() {
Expand Down
2 changes: 1 addition & 1 deletion objc2/src/declare.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ one ivar, a `u32` named `_number` and a `number` method that returns it:
``` no_run
# use objc2::{class, sel};
# use objc2::declare::ClassDecl;
# use objc2::runtime::{Class, Object, Sel};
# use objc2::runtime::{Class, Object, ObjectType, Sel};
let superclass = class!(NSObject);
let mut decl = ClassDecl::new("MyNumber", superclass).unwrap();
Expand Down
2 changes: 1 addition & 1 deletion objc2/src/message/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use core::ptr::NonNull;
use std::error::Error;

use crate::rc::{Id, Ownership};
use crate::runtime::{Class, Imp, Object, Sel};
use crate::runtime::{Class, Imp, Object, ObjectType, Sel};
use crate::{Encode, EncodeArguments, RefEncode};

#[cfg(feature = "catch_all")]
Expand Down
44 changes: 30 additions & 14 deletions objc2/src/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ pub use objc_sys::{
pub use objc_sys::{BOOL, NO, YES};

pub use super::bool::Bool;
use crate::Encode;
use crate::{Encode, Message};

/// A type that represents a method selector.
#[repr(transparent)]
Expand Down Expand Up @@ -404,14 +404,22 @@ fn get_ivar_offset<T: Encode>(cls: &Class, name: &str) -> isize {
}
}

impl Object {
pub(crate) fn as_ptr(&self) -> *const objc_sys::objc_object {
self as *const Self as *const _
}

/// Returns the class of this object.
pub fn class(&self) -> &Class {
unsafe { &*(object_getClass(self.as_ptr()) as *const Class) }
/// TODO
///
/// # Safety
///
/// A pointer to the type must be an Objective-C object; other things that can
/// be sent messages (like classes and blocks) should _not_ implement this.
///
/// Additionally, the type must implement [`Message`] and [`RefEncode`] and
/// adhere to the safety requirements therein.
pub unsafe trait ObjectType: Message {
/// Dynamically find the class of this object.
///
/// Can be overridden if the class for this specific object is constant
/// and can be cached or found statically.
fn class(&self) -> &Class {
unsafe { &*(object_getClass(self as *const Self as *const _) as *const Class) }
}

/// Returns a shared reference to the ivar with the given name.
Expand All @@ -424,7 +432,9 @@ impl Object {
/// # Safety
///
/// The caller must ensure that the ivar is actually of type `T`.
pub unsafe fn get_ivar<T: Encode>(&self, name: &str) -> &T {
///
/// Library implementors should expose a safe interface to the ivar.
unsafe fn get_ivar<T: Encode>(&self, name: &str) -> &T {
let offset = get_ivar_offset::<T>(self.class(), name);
// `offset` is given in bytes, so we convert to `u8`
let ptr = self as *const Self as *const u8;
Expand All @@ -442,7 +452,9 @@ impl Object {
/// # Safety
///
/// The caller must ensure that the ivar is actually of type `T`.
pub unsafe fn get_mut_ivar<T: Encode>(&mut self, name: &str) -> &mut T {
///
/// Library implementors should expose a safe interface to the ivar.
unsafe fn get_mut_ivar<T: Encode>(&mut self, name: &str) -> &mut T {
let offset = get_ivar_offset::<T>(self.class(), name);
// `offset` is given in bytes, so we convert to `u8`
let ptr = self as *mut Self as *mut u8;
Expand All @@ -460,21 +472,25 @@ impl Object {
/// # Safety
///
/// The caller must ensure that the ivar is actually of type `T`.
pub unsafe fn set_ivar<T: Encode>(&mut self, name: &str, value: T) {
///
/// Library implementors should expose a safe interface to the ivar.
unsafe fn set_ivar<T: Encode>(&mut self, name: &str, value: T) {
// SAFETY: Invariants upheld by caller
unsafe { *self.get_mut_ivar::<T>(name) = value };
}
}

unsafe impl ObjectType for Object {}

impl fmt::Debug for Object {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "<{:?}: {:p}>", self.class(), self.as_ptr())
write!(f, "<{:?}: {:p}>", self.class(), self as *const Self)
}
}

#[cfg(test)]
mod tests {
use super::{Class, Protocol, Sel};
use super::{Class, ObjectType, Protocol, Sel};
use crate::test_utils;
use crate::Encode;

Expand Down
2 changes: 1 addition & 1 deletion objc2/src/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::os::raw::c_char;
use std::sync::Once;

use crate::declare::{ClassDecl, ProtocolDecl};
use crate::runtime::{self, Class, Object, Protocol, Sel};
use crate::runtime::{self, Class, Object, ObjectType, Protocol, Sel};
use crate::{Encode, Encoding, MessageReceiver};

pub(crate) struct CustomObject {
Expand Down

0 comments on commit 80d9463

Please sign in to comment.