Skip to content

Commit

Permalink
Change syntax of impls in declare_class! macro
Browse files Browse the repository at this point in the history
Leads to a bit more duplication, but means the syntax is now Rust-like and can be formatted by rustfmt!
  • Loading branch information
madsmtm committed Aug 9, 2022
1 parent 87c6016 commit 0949941
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 58 deletions.
18 changes: 6 additions & 12 deletions objc2/examples/delegate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ extern_class!(
);

#[cfg(all(feature = "apple", target_os = "macos"))]
declare_class! {
declare_class!(
struct CustomAppDelegate {
pub ivar: u8,
another_ivar: Bool,
Expand All @@ -29,16 +29,10 @@ declare_class! {
type Superclass = NSResponder;
}

unsafe impl {
unsafe impl CustomAppDelegate {
#[sel(initWith:another:)]
fn init_with(
self: &mut Self,
ivar: u8,
another_ivar: Bool,
) -> *mut Self {
let this: *mut Self = unsafe {
msg_send![super(self, NSResponder::class()), init]
};
fn init_with(self: &mut Self, ivar: u8, another_ivar: Bool) -> *mut Self {
let this: *mut Self = unsafe { msg_send![super(self, NSResponder::class()), init] };
if let Some(this) = unsafe { this.as_mut() } {
// TODO: Allow initialization through MaybeUninit
*this.ivar = ivar;
Expand All @@ -58,7 +52,7 @@ declare_class! {
// `clang` only when used in Objective-C...
//
// TODO: Investigate this!
unsafe impl {
unsafe impl CustomAppDelegate {
/// This is `unsafe` because it expects `sender` to be valid
#[sel(applicationDidFinishLaunching:)]
unsafe fn did_finish_launching(&self, sender: *mut Object) {
Expand All @@ -74,7 +68,7 @@ declare_class! {
println!("Will terminate!");
}
}
}
);

#[cfg(all(feature = "apple", target_os = "macos"))]
impl CustomAppDelegate {
Expand Down
175 changes: 132 additions & 43 deletions objc2/src/macros/declare_class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,13 +210,13 @@ macro_rules! __inner_declare_class {
/// either be able to be created using [`MaybeUninit::zeroed`], or be
/// properly initialized in an `init` method.
///
/// `unsafe impl { ... }` asserts that the types match those that are expected
/// when the method is invoked from Objective-C. Note that there are no
/// safe-guards here; you can easily write `i8`, but if Objective-C thinks
/// `unsafe impl T { ... }` asserts that the types match those that are
/// expected when the method is invoked from Objective-C. Note that there are
/// no safe-guards here; you can easily write `i8`, but if Objective-C thinks
/// it's an `u32`, it will cause UB when called!
///
/// `unsafe impl protocol ... { ... }` requires that all required methods of
/// the specified protocol is implemented, and that any extra requirements
/// `unsafe impl Protocol<P> for T { ... }` requires that all required methods
/// of the specified protocol is implemented, and that any extra requirements
/// (implicit or explicit) that the protocol has are upheld. The methods in
/// this definition has the same safety requirements as above.
///
Expand All @@ -238,7 +238,7 @@ macro_rules! __inner_declare_class {
/// # #[cfg(feature = "gnustep-1-7")]
/// # unsafe { objc2::__gnustep_hack::get_class_to_force_linkage() };
///
/// declare_class! {
/// declare_class!(
/// struct MyCustomObject {
/// foo: u8,
/// pub bar: c_int,
Expand All @@ -248,7 +248,7 @@ macro_rules! __inner_declare_class {
/// type Superclass = NSObject;
/// }
///
/// unsafe impl {
/// unsafe impl MyCustomObject {
/// #[sel(initWithFoo:)]
/// fn init_with(&mut self, foo: u8) -> Option<&mut Self> {
/// let this: Option<&mut Self> = unsafe {
Expand All @@ -275,15 +275,15 @@ macro_rules! __inner_declare_class {
/// }
/// }
///
/// unsafe impl protocol NSCopying {
/// unsafe impl Protocol<NSCopying> for MyCustomObject {
/// #[sel(copyWithZone:)]
/// fn copy_with_zone(&self, _zone: *const NSZone) -> *mut Self {
/// let mut obj = Self::new(*self.foo);
/// *obj.bar = *self.bar;
/// obj.autorelease_return()
/// }
/// }
/// }
/// );
///
/// impl MyCustomObject {
/// pub fn new(foo: u8) -> Id<Self, Owned> {
Expand Down Expand Up @@ -385,12 +385,7 @@ macro_rules! declare_class {
type Superclass = $superclass:ty;
}

$(
$(#[$impl_m:meta])*
unsafe impl $(protocol $protocol:ident)? {
$($methods:tt)*
}
)*
$($methods:tt)*
} => {
$(
#[allow(non_camel_case_types)]
Expand Down Expand Up @@ -446,24 +441,11 @@ macro_rules! declare_class {
builder.add_static_ivar::<$ivar>();
)*

$(
// Implement protocol if any specified
$(
let err_str = concat!("could not find protocol ", stringify!($protocol));
builder.add_protocol($crate::runtime::Protocol::get(stringify!($protocol)).expect(err_str));
)?

// Implement methods
// SAFETY: Upheld by caller
unsafe {
$crate::__inner_declare_class! {
@rewrite_methods
@(register_out(builder))

$($methods)*
}
}
)*
// Implement protocols and methods
$crate::__declare_class_methods!(
@register_out(builder)
$($methods)*
);

let _cls = builder.register();
});
Expand All @@ -474,16 +456,123 @@ macro_rules! declare_class {
}

// Methods
$(
$(#[$impl_m])*
impl $name {
$crate::__inner_declare_class! {
@rewrite_methods
@(method_out)

$($methods)*
}
$crate::__declare_class_methods!(
@method_out
$($methods)*
);
};
}

#[doc(hidden)]
#[macro_export]
macro_rules! __declare_class_methods {
(@method_out) => {};
// With protocol
(
@method_out

$(#[$m:meta])*
unsafe impl Protocol<$protocol:ident> for $for:ty {
$($methods:tt)*
}

$($rest:tt)*
) => {
$(#[$m])*
impl $for {
$crate::__inner_declare_class! {
@rewrite_methods
@(method_out)
$($methods)*
}
)*
}

$crate::__declare_class_methods!(
@method_out
$($rest)*
);
};
// Without protocol
(
@method_out

$(#[$m:meta])*
unsafe impl $for:ty {
$($methods:tt)*
}

$($rest:tt)*
) => {
$(#[$m])*
impl $for {
$crate::__inner_declare_class! {
@rewrite_methods
@(method_out)
$($methods)*
}
}

$crate::__declare_class_methods!(
@method_out
$($rest)*
);
};

(@register_out($builder:ident)) => {};
// With protocol
(
@register_out($builder:ident)

$(#[$m:meta])*
unsafe impl Protocol<$protocol:ident> for $for:ty {
$($methods:tt)*
}

$($rest:tt)*
) => {
// Implement protocol
let err_str = concat!("could not find protocol ", stringify!($protocol));
$builder.add_protocol($crate::runtime::Protocol::get(stringify!($protocol)).expect(err_str));

// SAFETY: Upheld by caller
unsafe {
$crate::__inner_declare_class! {
@rewrite_methods
@(register_out($builder))

$($methods)*
}
}

$crate::__declare_class_methods!(
@register_out($builder)
$($rest)*
);
};
// Without protocol
(
@register_out($builder:ident)

$(#[$m:meta])*
unsafe impl $for:ty {
$($methods:tt)*
}

$($rest:tt)*
) => {
// SAFETY: Upheld by caller
unsafe {
$crate::__inner_declare_class! {
@rewrite_methods
@(register_out($builder))

$($methods)*
}
}

$crate::__declare_class_methods!(
@register_out($builder)
$($rest)*
);
};
}
6 changes: 3 additions & 3 deletions objc2/src/rc/test_object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ std::thread_local! {
pub(crate) static TEST_DATA: RefCell<ThreadTestData> = RefCell::new(Default::default());
}

declare_class! {
declare_class!(
/// A helper object that counts how many times various reference-counting
/// primitives are called.
#[derive(Debug, PartialEq)]
Expand All @@ -58,7 +58,7 @@ declare_class! {
type Superclass = NSObject;
}

unsafe impl {
unsafe impl RcTestObject {
#[sel(alloc)]
fn alloc() -> *mut Self {
TEST_DATA.with(|data| data.borrow_mut().alloc += 1);
Expand Down Expand Up @@ -127,7 +127,7 @@ declare_class! {
Id::consume_as_ptr(ManuallyDrop::new(Self::new()))
}
}
}
);

unsafe impl Send for RcTestObject {}
unsafe impl Sync for RcTestObject {}
Expand Down

0 comments on commit 0949941

Please sign in to comment.