Skip to content

Commit

Permalink
Add extern_protocol! macro and ProtocolType trait
Browse files Browse the repository at this point in the history
  • Loading branch information
madsmtm committed Sep 2, 2022
1 parent 4b7e392 commit 2566684
Show file tree
Hide file tree
Showing 8 changed files with 136 additions and 6 deletions.
1 change: 1 addition & 0 deletions objc2/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

### Added
* Allow directly specifying class name in `extern_class!` macro.
* Added `extern_protocol!` macro and `ProtocolType` trait.

### Changed
* Allow other types than `&Class` as the receiver in `msg_send_id!` methods
Expand Down
21 changes: 19 additions & 2 deletions objc2/src/foundation/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ use core::hash;

use super::NSString;
use crate::rc::{DefaultId, Id, Owned, Shared};
use crate::runtime::{Class, Object};
use crate::{ClassType, __inner_extern_class, class, extern_methods, msg_send_id};
use crate::runtime::{Class, Object, Protocol};
use crate::{ClassType, ProtocolType, __inner_extern_class, class, extern_methods, msg_send_id};

__inner_extern_class! {
@__inner
Expand Down Expand Up @@ -33,6 +33,23 @@ unsafe impl ClassType for NSObject {
}
}

unsafe impl ProtocolType for NSObject {
type Super = Object;
const NAME: &'static str = "NSObject";

fn protocol() -> &'static Protocol {
Protocol::get(<Self as ProtocolType>::NAME).expect("Could not find NSObject protocol")
}

fn as_super(&self) -> &Self::Super {
&self.__inner
}

fn as_super_mut(&mut self) -> &mut Self::Super {
&mut self.__inner
}
}

extern_methods!(
unsafe impl NSObject {
pub fn new() -> Id<Self, Owned> {
Expand Down
2 changes: 2 additions & 0 deletions objc2/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ pub use objc2_encode::{Encode, EncodeArguments, Encoding, RefEncode};

pub use crate::class_type::ClassType;
pub use crate::message::{Message, MessageArguments, MessageReceiver};
pub use crate::protocol_type::ProtocolType;
#[cfg(feature = "malloc")]
pub use crate::verify::VerificationError;

Expand All @@ -224,6 +225,7 @@ pub mod exception;
pub mod foundation;
mod macros;
mod message;
mod protocol_type;
pub mod rc;
pub mod runtime;
#[cfg(test)]
Expand Down
1 change: 1 addition & 0 deletions objc2/src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ mod __rewrite_self_arg;
mod declare_class;
mod extern_class;
mod extern_methods;
mod extern_protocol;

/// Gets a reference to a [`Class`] from the given name.
///
Expand Down
6 changes: 3 additions & 3 deletions objc2/src/macros/declare_class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -626,10 +626,10 @@ macro_rules! declare_class {

REGISTER_CLASS.call_once(|| {
let superclass = <$superclass as $crate::ClassType>::class();
let mut builder = $crate::declare::ClassBuilder::new(Self::NAME, superclass).unwrap_or_else(|| {
let mut builder = $crate::declare::ClassBuilder::new(<Self as ClassType>::NAME, superclass).unwrap_or_else(|| {
$crate::__macro_helpers::panic!(
"could not create new class {}. Perhaps a class with that name already exists?",
Self::NAME,
<Self as ClassType>::NAME,
)
});

Expand Down Expand Up @@ -660,7 +660,7 @@ macro_rules! declare_class {
});

// We just registered the class, so it should be available
$crate::runtime::Class::get(Self::NAME).unwrap()
$crate::runtime::Class::get(<Self as ClassType>::NAME).unwrap()
}

#[inline]
Expand Down
59 changes: 59 additions & 0 deletions objc2/src/macros/extern_protocol.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/// TODO
#[doc(alias = "@protocol")]
#[macro_export]
macro_rules! extern_protocol {
(
$(#[$m:meta])*
$v:vis struct $name:ident;

unsafe impl ProtocolType for $for:ty {
$(#[inherits($($inheritance_rest:ty),+)])?
type Super = $superprotocol:ty;

$(const NAME: &'static str = $name_const:literal;)?
}
) => {
$crate::__inner_extern_class!(
@__inner

$(#[$m])*
$v struct ($name) {}

unsafe impl () for $for {
INHERITS = [$superprotocol, $($($inheritance_rest,)+)? $crate::runtime::Object];
}
);

unsafe impl ProtocolType for $for {
type Super = $superprotocol;
const NAME: &'static str = $crate::__select_name!($name; $($name_const)?);

#[inline]
fn protocol() -> &'static $crate::runtime::Protocol {
$crate::runtime::Protocol::get(<Self as ProtocolType>::NAME).unwrap_or_else(|| {
$crate::__macro_helpers::panic!("could not find protocol {}", Self::NAME)
})
}

#[inline]
fn as_super(&self) -> &Self::Super {
&self.__inner
}

#[inline]
fn as_super_mut(&mut self) -> &mut Self::Super {
&mut self.__inner
}
}

const _: () = {
if $crate::__macro_helpers::size_of::<$name>() != 0 {
panic!(concat!(
"the struct ",
stringify!($name),
" is not zero-sized!",
))
}
};
};
}
38 changes: 38 additions & 0 deletions objc2/src/protocol_type.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
use crate::runtime::Protocol;
use crate::Message;

/// Marks types that represent specific protocols.
///
/// TODO.
///
///
/// # Safety
///
/// Same as [`ClassType`], TODO.
///
/// [`ClassType`]: crate::ClassType
pub unsafe trait ProtocolType: Message {
/// The protocol that this protocol inherits.
type Super: Message;

/// The name of the Objective-C protocol that this type represents.
const NAME: &'static str;

/// Get a reference to the Objective-C protocol that this type represents.
///
/// May register the protocol with the runtime if it wasn't already.
///
///
/// # Panics
///
/// This may panic if something went wrong with getting or declaring the
/// protocol, e.g. if the program is not properly linked to the framework
/// that defines the protocol.
fn protocol() -> &'static Protocol;

/// Get an immutable reference to the superprotocol.
fn as_super(&self) -> &Self::Super;

/// Get a mutable reference to the superprotocol.
fn as_super_mut(&mut self) -> &mut Self::Super;
}
14 changes: 13 additions & 1 deletion objc2/src/rc/id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use super::Allocated;
use super::AutoreleasePool;
use super::{Owned, Ownership, Shared};
use crate::ffi;
use crate::{ClassType, Message};
use crate::{ClassType, Message, ProtocolType};

/// An pointer for Objective-C reference counted objects.
///
Expand Down Expand Up @@ -650,6 +650,18 @@ where
}
}

impl<T: ProtocolType + 'static, O: Ownership> Id<T, O>
where
T::Super: 'static,
{
/// Convert the object into it's superprotocol.
#[inline]
pub fn into_super_protocol(this: Self) -> Id<T::Super, O> {
// SAFETY: Similar to `Id::into_super`
unsafe { Self::cast::<T::Super>(this) }
}
}

impl<T: Message> From<Id<T, Owned>> for Id<T, Shared> {
/// Convert an owned to a shared [`Id`], allowing it to be cloned.
///
Expand Down

0 comments on commit 2566684

Please sign in to comment.