#[doc(hidden)]
#[macro_export]
macro_rules! __inner_declare_class {
{@rewrite_methods @($($output:tt)*)} => {};
{
@rewrite_methods
@($($output:tt)*)
$(#[$($m:tt)*])*
unsafe fn $name:ident($($args:tt)*) $(-> $ret:ty)? $body:block
$($rest:tt)*
} => {
$crate::__rewrite_self_arg! {
($crate::__inner_declare_class)
($($args)*)
@$($output)*
@($(#[$($m)*])*)
@(unsafe extern "C")
@($name)
@($($ret)?)
@($body)
}
$crate::__inner_declare_class! {
@rewrite_methods
@($($output)*)
$($rest)*
}
};
{
@rewrite_methods
@($($output:tt)*)
$(#[$($m:tt)*])*
fn $name:ident($($args:tt)*) $(-> $ret:ty)? $body:block
$($rest:tt)*
} => {
$crate::__rewrite_self_arg! {
($crate::__inner_declare_class)
($($args)*)
@$($output)*
@($(#[$($m)*])*)
@(extern "C")
@($name)
@($($ret)?)
@($body)
}
$crate::__inner_declare_class! {
@rewrite_methods
@($($output)*)
$($rest)*
}
};
{
@method_out
@($(#[$($m:tt)*])*)
@($($qualifiers:tt)*)
@($name:ident)
@($($ret:ty)?)
@($($body:tt)*)
@($($_kind:tt)*)
@($($args_start:tt)*)
@($($args_rest:tt)*)
} => {
$crate::__fn_args! {
($crate::__inner_declare_class)
($($args_rest)*,)
()
()
@method_out_inner
@($(#[$($m)*])*)
@($($qualifiers)*)
@($name)
@($($ret)?)
@($($body)*)
@($($_kind)*)
@($($args_start)*)
}
};
{
@method_out_inner
@($(#[$($m:tt)*])*)
@($($qualifiers:tt)*)
@($name:ident)
@()
@($($body:tt)*)
@($($_kind:tt)*)
@($($args_start:tt)*)
@($($args_converted:tt)*)
@($($body_prefix:tt)*)
} => {
$crate::__attribute_helper! {
@strip_sel
$(@[$($m)*])*
($($qualifiers)* fn $name($($args_start)* $($args_converted)*) {
$($body_prefix)*
$($body)*
})
}
};
{
@method_out_inner
@($(#[$($m:tt)*])*)
@($($qualifiers:tt)*)
@($name:ident)
@($ret:ty)
@($($body:tt)*)
@($($_kind:tt)*)
@($($args_start:tt)*)
@($($args_converted:tt)*)
@($($body_prefix:tt)*)
} => {
$crate::__attribute_helper! {
@strip_sel
$(@[$($m)*])*
($($qualifiers)* fn $name($($args_start)* $($args_converted)*) -> <$ret as $crate::encode::EncodeConvert>::__Inner {
$($body_prefix)*
<$ret as $crate::encode::EncodeConvert>::__into_inner($($body)*)
})
}
};
{
@register_out($builder:ident)
@($(#[$($m:tt)*])*)
@($($qualifiers:tt)*)
@($name:ident)
@($($_ret:tt)*)
@($($_body:tt)*)
@(class_method)
@($($args_start:tt)*)
@($($args_rest:tt)*)
} => {
$builder.add_class_method(
$crate::__attribute_helper! {
@extract_sel
($crate::__inner_declare_class)
($(#[$($m)*])*)
@call_sel
},
Self::$name as $crate::__fn_ptr! {
@($($qualifiers)*) $($args_start)* $($args_rest)*
},
);
};
{
@register_out($builder:ident)
@($(#[$($m:tt)*])*)
@($($qualifiers:tt)*)
@($name:ident)
@($($_ret:tt)*)
@($($_body:tt)*)
@(instance_method)
@($($args_start:tt)*)
@($($args_rest:tt)*)
} => {
$builder.add_method(
$crate::__attribute_helper! {
@extract_sel
($crate::__inner_declare_class)
($(#[$($m)*])*)
@call_sel
},
Self::$name as $crate::__fn_ptr! {
@($($qualifiers)*) $($args_start)* $($args_rest)*
},
);
};
{
@call_sel
@($($sel:tt)*)
} => {
$crate::sel!($($sel)*)
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __fn_ptr {
(
@($($qualifiers:tt)*)
$($(mut)? $($param:ident)? $(_)?: $param_ty:ty),* $(,)?
) => {
$($qualifiers)* fn($($crate::__fn_ptr!(@__to_anonymous $param_ty)),*) -> _
};
(@__to_anonymous $param_ty:ty) => { _ }
}
#[doc(hidden)]
#[macro_export]
macro_rules! __fn_args {
{
($out_macro:path)
(_: $param_ty:ty, $($rest:tt)*)
($($args_converted:tt)*)
($($body_prefix:tt)*)
$($macro_args:tt)*
} => {
$crate::__fn_args! {
($out_macro)
($($rest)*)
($($args_converted)* _: $param_ty,)
($($body_prefix)*)
$($macro_args)*
}
};
{
($out_macro:path)
(mut $param:ident: $param_ty:ty, $($rest:tt)*)
($($args_converted:tt)*)
($($body_prefix:tt)*)
$($macro_args:tt)*
} => {
$crate::__fn_args! {
($out_macro)
($($rest)*)
($($args_converted)* $param: <$param_ty as $crate::encode::EncodeConvert>::__Inner,)
(
$($body_prefix)*
let mut $param = <$param_ty as $crate::encode::EncodeConvert>::__from_inner($param);
)
$($macro_args)*
}
};
{
($out_macro:path)
($param:ident: $param_ty:ty, $($rest:tt)*)
($($args_converted:tt)*)
($($body_prefix:tt)*)
$($macro_args:tt)*
} => {
$crate::__fn_args! {
($out_macro)
($($rest)*)
($($args_converted)* $param: <$param_ty as $crate::encode::EncodeConvert>::__Inner,)
(
$($body_prefix)*
let $param = <$param_ty as $crate::encode::EncodeConvert>::__from_inner($param);
)
$($macro_args)*
}
};
{
($out_macro:path)
($(,)*)
($($args_converted:tt)*)
($($body_prefix:tt)*)
$($macro_args:tt)*
} => {
$out_macro! {
$($macro_args)*
@($($args_converted)*)
@($($body_prefix)*)
}
};
}
#[doc(alias = "@interface")]
#[doc(alias = "@implementation")]
#[macro_export]
macro_rules! declare_class {
{
$(#[$m:meta])*
$v:vis struct $name:ident {
$($ivar_v:vis $ivar:ident: $ivar_ty:ty,)*
}
unsafe impl ClassType for $for:ty {
$(#[inherits($($inheritance_rest:ty),+)])?
type Super = $superclass:ty;
$(const NAME: &'static str = $name_const:literal;)?
}
$($methods:tt)*
} => {
$(
#[allow(non_camel_case_types)]
$ivar_v struct $ivar {
__priv: (),
}
unsafe impl $crate::declare::IvarType for $ivar {
type Type = $ivar_ty;
const NAME: &'static str = stringify!($ivar);
}
)*
$crate::__inner_extern_class! {
@__inner
$(#[$m])*
$v struct $name () {
// SAFETY:
$($ivar_v $ivar: $crate::declare::Ivar<$ivar>,)*
}
unsafe impl () for $for {
INHERITS = [$superclass, $($($inheritance_rest,)+)? $crate::runtime::Object];
}
}
unsafe impl ClassType for $for {
type Super = $superclass;
const NAME: &'static str = $crate::__select_name!($name; $($name_const)?);
fn class() -> &'static $crate::runtime::Class {
use $crate::__macro_helpers::Once;
static REGISTER_CLASS: Once = Once::new();
REGISTER_CLASS.call_once(|| {
let superclass = <$superclass as $crate::ClassType>::class();
let err_str = concat!(
"could not create new class ",
$crate::__select_name!($name; $($name_const)?),
". Perhaps a class with that name already exists?",
);
let mut builder = $crate::declare::ClassBuilder::new(Self::NAME, superclass).expect(err_str);
$(
builder.add_static_ivar::<$ivar>();
)*
if false $(
|| <<$ivar as $crate::declare::IvarType>::Type as $crate::declare::InnerIvarType>::__MAY_DROP
)* {
unsafe {
builder.add_method(
$crate::sel!(dealloc),
Self::__objc2_dealloc as unsafe extern "C" fn(_, _),
);
}
}
$crate::__declare_class_methods!(
@register_out(builder)
$($methods)*
);
let _cls = builder.register();
});
$crate::runtime::Class::get(Self::NAME).unwrap()
}
#[inline]
fn as_super(&self) -> &Self::Super {
&self.__inner
}
#[inline]
fn as_super_mut(&mut self) -> &mut Self::Super {
&mut self.__inner
}
}
impl $for {
unsafe extern "C" fn __objc2_dealloc(&mut self, _cmd: $crate::runtime::Sel) {
$(
let ptr: *mut $crate::declare::Ivar<$ivar> = &mut self.$ivar;
unsafe { $crate::__macro_helpers::drop_in_place(ptr) };
)*
unsafe { msg_send![super(self), dealloc] }
}
}
$crate::__declare_class_methods!(
@method_out
$($methods)*
);
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __select_name {
($_name:ident; $name_const:literal) => {
$name_const
};
($name:ident;) => {
$crate::__macro_helpers::stringify!($name)
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __declare_class_methods {
(@method_out) => {};
(
@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)*
);
};
(
@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)) => {};
(
@register_out($builder:ident)
$(#[$m:meta])*
unsafe impl Protocol<$protocol:ident> for $for:ty {
$($methods:tt)*
}
$($rest:tt)*
) => {
let err_str = concat!("could not find protocol ", stringify!($protocol));
$builder.add_protocol($crate::runtime::Protocol::get(stringify!($protocol)).expect(err_str));
unsafe {
$crate::__inner_declare_class! {
@rewrite_methods
@(register_out($builder))
$($methods)*
}
}
$crate::__declare_class_methods!(
@register_out($builder)
$($rest)*
);
};
(
@register_out($builder:ident)
$(#[$m:meta])*
unsafe impl $for:ty {
$($methods:tt)*
}
$($rest:tt)*
) => {
unsafe {
$crate::__inner_declare_class! {
@rewrite_methods
@(register_out($builder))
$($methods)*
}
}
$crate::__declare_class_methods!(
@register_out($builder)
$($rest)*
);
};
}