Skip to content
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

Change selector syntax in declare_class! macro #215

Merged
merged 1 commit into from
Jul 24, 2022
Merged
Show file tree
Hide file tree
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
3 changes: 3 additions & 0 deletions objc2-foundation/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
* Implemented `Extend` for `NSMutableArray`.
* Add extra `Extend<&u8>` impl for `NSMutableData`.

### Changed
* Change selector syntax in `declare_class!` macro to be more Rust-like.

### Fixed
* Made `Debug` impls for all objects print something useful.

Expand Down
10 changes: 6 additions & 4 deletions objc2-foundation/examples/declaration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ declare_class! {
}

unsafe impl {
@sel(initWith:another:)
#[sel(initWith:another:)]
fn init_with(
self: &mut Self,
ivar: u8,
Expand All @@ -37,7 +37,7 @@ declare_class! {
this
}

@sel(myClassMethod)
#[sel(myClassMethod)]
fn my_class_method() {
println!("A class method!");
}
Expand All @@ -49,12 +49,14 @@ declare_class! {
//
// TODO: Investigate this!
unsafe impl {
@sel(applicationDidFinishLaunching:)
#[sel(applicationDidFinishLaunching:)]
fn did_finish_launching(&self, _sender: *mut Object) {
println!("Did finish launching!");
}

@sel(applicationWillTerminate:)
/// Some comment before `sel`.
#[sel(applicationWillTerminate:)]
/// Some comment after `sel`.
fn will_terminate(&self, _: *mut Object) {
println!("Will terminate!");
}
Expand Down
79 changes: 39 additions & 40 deletions objc2-foundation/src/declare_macro.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ macro_rules! __inner_declare_class {
@$output_type:ident
@$builder:ident

$(#[$m:meta])*
@sel($($sel:tt)+)
$(#[$($m:tt)*])*
fn $name:ident($($args:tt)*) $(-> $ret:ty)? $body:block

$($rest:tt)*
Expand All @@ -21,8 +20,7 @@ macro_rules! __inner_declare_class {
// it as a function argument
($($args)*)

$(#[$m])*
@sel($($sel)+)
$(#[$($m)*])*
fn $name($($args)*) $(-> $ret)? $body
}

Expand All @@ -42,8 +40,7 @@ macro_rules! __inner_declare_class {
@$builder:ident
(&mut self $($__rest_args:tt)*)

$(#[$m:meta])*
@sel($($sel:tt)+)
$(#[$($m:tt)*])*
fn $name:ident(
&mut $self:ident
$(, $($rest_args:tt)*)?
Expand All @@ -52,12 +49,11 @@ macro_rules! __inner_declare_class {
$crate::__inner_declare_class! {
@$output_type
@instance_method
@sel($($sel)*)
@$name
@$builder
@($($($rest_args)*)?)

$(#[$m])*
$(#[$($m)*])*
extern "C" fn $name(
&mut $self,
_: $crate::objc2::runtime::Sel,
Expand All @@ -71,8 +67,7 @@ macro_rules! __inner_declare_class {
@$builder:ident
(&self $($__rest_args:tt)*)

$(#[$m:meta])*
@sel($($sel:tt)+)
$(#[$($m:tt)*])*
fn $name:ident(
&$self:ident
$(, $($rest_args:tt)*)?
Expand All @@ -81,12 +76,11 @@ macro_rules! __inner_declare_class {
$crate::__inner_declare_class! {
@$output_type
@instance_method
@sel($($sel)*)
@$name
@$builder
@($($($rest_args)*)?)

$(#[$m])*
$(#[$($m)*])*
extern "C" fn $name(
&$self,
_: $crate::objc2::runtime::Sel,
Expand All @@ -103,8 +97,7 @@ macro_rules! __inner_declare_class {
$(, $($__rest_args:tt)*)?
)

$(#[$m:meta])*
@sel($($sel:tt)+)
$(#[$($m:tt)*])*
fn $name:ident(
mut $self:ident: $self_ty:ty
$(, $($rest_args:tt)*)?
Expand All @@ -113,12 +106,11 @@ macro_rules! __inner_declare_class {
$crate::__inner_declare_class! {
@$output_type
@instance_method
@sel($($sel)*)
@$name
@$builder
@($($($rest_args)*)?)

$(#[$m])*
$(#[$($m)*])*
extern "C" fn $name(
mut $self: $self_ty,
_: $crate::objc2::runtime::Sel,
Expand All @@ -135,8 +127,7 @@ macro_rules! __inner_declare_class {
$(, $($__rest_args:tt)*)?
)

$(#[$m:meta])*
@sel($($sel:tt)+)
$(#[$($m:tt)*])*
fn $name:ident(
$self:ident: $self_ty:ty
$(, $($rest_args:tt)*)?
Expand All @@ -145,12 +136,11 @@ macro_rules! __inner_declare_class {
$crate::__inner_declare_class! {
@$output_type
@instance_method
@sel($($sel)*)
@$name
@$builder
@($($($rest_args)*)?)

$(#[$m])*
$(#[$($m)*])*
extern "C" fn $name(
$self: $self_ty,
_: $crate::objc2::runtime::Sel,
Expand All @@ -166,21 +156,19 @@ macro_rules! __inner_declare_class {
@$builder:ident
($($__args:tt)*)

$(#[$m:meta])*
@sel($($sel:tt)+)
$(#[$($m:tt)*])*
fn $name:ident(
$($args:tt)*
) $(-> $ret:ty)? $body:block
} => {
$crate::__inner_declare_class! {
@$output_type
@class_method
@sel($($sel)*)
@$name
@$builder
@($($args)*)

$(#[$m])*
$(#[$($m)*])*
extern "C" fn $name(
_: &$crate::objc2::runtime::Class,
_: $crate::objc2::runtime::Sel,
Expand All @@ -192,27 +180,35 @@ macro_rules! __inner_declare_class {
{
@method_out
@$method_type:ident
@sel($($sel:tt)*)
@$name:ident
@$_name:ident
@$builder:ident
@($($builder_args:tt)*)

$method:item
$(#[$($m:tt)*])*
extern "C" fn $($fn:tt)*
} => {
$method
$crate::__attribute_helper! {
@strip_sel
$(@[$($m)*])*
(extern "C" fn $($fn)*)
}
};

{
@register_out
@class_method
@sel($($sel:tt)*)
@$name:ident
@$builder:ident
@($($builder_args:tt)*)

$method:item
$(#[$($m:tt)*])*
extern "C" fn $($fn:tt)*
} => {
$builder.add_class_method(
$crate::objc2::sel!($($sel)*),
$crate::__attribute_helper! {
@extract_sel
$(#[$($m)*])*
},
$crate::__inner_declare_class! {
@cast_extern_fn
@$name
Expand All @@ -223,15 +219,18 @@ macro_rules! __inner_declare_class {
{
@register_out
@instance_method
@sel($($sel:tt)*)
@$name:ident
@$builder:ident
@($($builder_args:tt)*)

$method:item
$(#[$($m:tt)*])*
extern "C" fn $($fn:tt)*
} => {
$builder.add_method(
$crate::objc2::sel!($($sel)*),
$crate::__attribute_helper! {
@extract_sel
$(#[$($m)*])*
},
$crate::__inner_declare_class! {
@cast_extern_fn
@$name
Expand Down Expand Up @@ -454,8 +453,8 @@ macro_rules! __inner_declare_class {
/// particular, if you use `self` your method will be registered as an
/// instance method, and if you don't it will be registered as a class method.
///
/// The desired selector can be specified using a special `@sel(my:selector:)`
/// directive directly before the function definition.
/// The desired selector can be specified using the `#[sel(my:selector:)]`
/// attribute.
///
/// A transformation step is performed on the functions (to make them have the
/// correct ABI) and hence they shouldn't really be called manually. (You
Expand Down Expand Up @@ -520,7 +519,7 @@ macro_rules! __inner_declare_class {
/// }
///
/// unsafe impl {
/// @sel(initWithFoo:)
/// #[sel(initWithFoo:)]
/// fn init_with(&mut self, foo: u8) -> Option<&mut Self> {
/// let this: Option<&mut Self> = unsafe {
/// msg_send![super(self, NSObject::class()), init]
Expand All @@ -535,19 +534,19 @@ macro_rules! __inner_declare_class {
/// })
/// }
///
/// @sel(foo)
/// #[sel(foo)]
/// fn __get_foo(&self) -> u8 {
/// *self.foo
/// }
///
/// @sel(myClassMethod)
/// #[sel(myClassMethod)]
/// fn __my_class_method() -> Bool {
/// Bool::YES
/// }
/// }
///
/// unsafe impl protocol NSCopying {
/// @sel(copyWithZone:)
/// #[sel(copyWithZone:)]
/// fn copy_with_zone(&self, _zone: *const NSZone) -> *mut Self {
/// let mut obj = Self::new(*self.foo);
/// *obj.bar = *self.bar;
Expand Down
95 changes: 95 additions & 0 deletions objc2-foundation/src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -292,3 +292,98 @@ macro_rules! __inner_extern_class {
$crate::__impl_as_ref_borrow!($name<$($t $(: $b)?),*>, $inherits, $($inheritance_rest,)*);
};
}

#[doc(hidden)]
#[macro_export]
macro_rules! __attribute_helper {
// Convert a set of attributes described with `@[...]` to `#[...]`, while
// parsing out the `sel(...)` attribute.
{
@strip_sel
@[sel($($_sel_args:tt)*)]
$(@[$($m_rest:tt)*])*

$(#[$($m:tt)*])*
($($fn:tt)*)
} => {
$crate::__attribute_helper! {
@strip_sel
$(@[$($m_rest)*])*

$(#[$($m)*])*
($($fn)*)
}
};
{
@strip_sel
@[$($m_checked:tt)*]
$(@[$($m_rest:tt)*])*

$(#[$($m:tt)*])*
($($fn:tt)*)
} => {
$crate::__attribute_helper! {
@strip_sel
$(@[$($m_rest)*])*

$(#[$($m)*])*
#[$($m_checked)*]
($($fn)*)
}
};
{
@strip_sel
$(#[$($m:tt)*])*
($($fn:tt)*)
} => {
$(#[$($m)*])*
$($fn)*
};

// Extract and convert the `#[sel(...)]` attribute to a `sel!` invocation.
{
@extract_sel
#[sel($($sel:tt)*)]
$($rest:tt)*
} => {{
$crate::__attribute_helper! {
@extract_sel_duplicate
$($rest)*
}

$crate::objc2::sel!($($sel)*)
}};
{
@extract_sel
#[$($m_checked:tt)*]
$($rest:tt)*
} => {{
$crate::__attribute_helper! {
@extract_sel
$($rest)*
}
}};
{@extract_sel} => {{
compile_error!("Must specify the desired selector using `#[sel(...)]`");
}};

{
@extract_sel_duplicate
#[sel($($_sel_args:tt)*)]
$($rest:tt)*
} => {{
compile_error!("Cannot not specify a selector twice!");
}};
{
@extract_sel_duplicate
#[$($m_checked:tt)*]
$($rest:tt)*
} => {{
$crate::__attribute_helper! {
@extract_sel_duplicate
$($rest)*
}
}};
{@extract_sel_duplicate} => {};

}