#[doc(alias = "@interface")]
#[doc(alias = "@implementation")]
#[macro_export]
macro_rules! define_class {
{
$(#[$($attrs:tt)*])*
$v:vis struct $class:ident;
$($impls:tt)*
} => {
$crate::__extract_struct_attributes! {
($(#[$($attrs)*])*)
($crate::__define_class_inner)
($v)
($class)
($($impls)*)
}
$crate::__define_class_output_impls! {
$($impls)*
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! declare_class {
{
$(#[$m:meta])*
$v:vis struct $name:ident;
unsafe impl ClassType for $for_class:ty {
$(#[inherits($($inheritance_rest:ty),+)])?
type Super = $superclass:ty;
type Mutability = $mutability:ty;
const NAME: &'static str = $name_const:expr;
}
impl DefinedClass for $for_defined:ty {
$(type Ivars = $ivars:ty;)?
}
$($impls:tt)*
} => {
$(#[$m])*
$v struct $name;
$crate::__macro_helpers::compile_error!("declare_class! has been renamed to define_class!, and the syntax has changed")
}
}
#[doc(hidden)]
#[macro_export]
macro_rules! __define_class_inner {
(
($v:vis)
($class:ident)
($($impls:tt)*)
($($safety:tt $superclass:path $(, $superclasses:path)* $(,)?)?)
($($($thread_kind:tt)+)?)
($($name:tt)*)
($($ivars:tt)*)
($($derives:tt)*)
($($attr_struct:tt)*)
($($attr_impl:tt)*)
) => {
#[repr(C)]
$($attr_struct)*
$v struct $class {
__superclass: $crate::__macro_helpers::ManuallyDrop<$crate::__fallback_if_not_set! {
($(<$superclass as $crate::ClassType>::__SubclassingType)?)
($crate::runtime::NSObject)
}>,
__phantom: $crate::__macro_helpers::PhantomData<(
// Include ivars for auto traits.
<Self as $crate::DefinedClass>::Ivars,
// Translate thread kind to appropriate auto traits.
$crate::__macro_helpers::ThreadKindAutoTraits<<Self as $crate::ClassType>::ThreadKind>,
)>,
}
$crate::__extern_class_impl_traits! {
($($attr_impl)*)
(unsafe impl)
($class)
($($superclass, $($superclasses,)*)? $crate::runtime::AnyObject)
}
$crate::__define_class_derives! {
($($attr_impl)*)
($class)
($($derives)*)
}
$($attr_impl)*
const _: () = {
#[export_name = $crate::__macro_helpers::concat!(
"__CLASS_",
$crate::__define_class_name!($class, $($name)*),
)]
static __OBJC2_CLASS: $crate::__macro_helpers::SyncUnsafeCell<
$crate::__macro_helpers::MaybeUninit<&'static $crate::runtime::AnyClass>
> = $crate::__macro_helpers::SyncUnsafeCell::new($crate::__macro_helpers::MaybeUninit::uninit());
#[export_name = $crate::__macro_helpers::concat!(
"__IVAR_OFFSET_",
$crate::__define_class_name!($class, $($name)*),
)]
static __OBJC2_IVAR_OFFSET: $crate::__macro_helpers::SyncUnsafeCell<
$crate::__macro_helpers::MaybeUninit<$crate::__macro_helpers::isize>
> = $crate::__macro_helpers::SyncUnsafeCell::new($crate::__macro_helpers::MaybeUninit::uninit());
#[export_name = $crate::__macro_helpers::concat!(
"__DROP_FLAG_OFFSET_",
$crate::__define_class_name!($class, $($name)*),
)]
static __OBJC2_DROP_FLAG_OFFSET: $crate::__macro_helpers::SyncUnsafeCell<
$crate::__macro_helpers::MaybeUninit<$crate::__macro_helpers::isize>
> = $crate::__macro_helpers::SyncUnsafeCell::new($crate::__macro_helpers::MaybeUninit::uninit());
unsafe impl $crate::ClassType for $class {
type Super = $crate::__fallback_if_not_set! {
($($superclass)?)
($crate::runtime::NSObject)
};
type ThreadKind = $crate::__fallback_if_not_set! {
($(dyn ($($thread_kind)+))?)
(<<Self as $crate::ClassType>::Super as $crate::ClassType>::ThreadKind)
};
const NAME: &'static $crate::__macro_helpers::str = $crate::__define_class_name!($class, $($name)*);
fn class() -> &'static $crate::runtime::AnyClass {
let _ = <Self as $crate::__macro_helpers::ValidThreadKind<Self::ThreadKind>>::check;
let _ = <Self as $crate::__macro_helpers::MainThreadOnlyDoesNotImplSendSync<_>>::check;
const C_NAME: &'static $crate::__macro_helpers::CStr = $crate::__macro_helpers::class_c_name(
$crate::__macro_helpers::concat!($crate::__define_class_name!($class, $($name)*), "\0")
);
#[export_name = $crate::__macro_helpers::concat!(
"__REGISTER_CLASS_",
$crate::__define_class_name!($class, $($name)*),
)]
static REGISTER_CLASS: $crate::__macro_helpers::Once = $crate::__macro_helpers::Once::new();
REGISTER_CLASS.call_once(|| {
let (__objc2_cls, __objc2_ivar_offset, __objc2_drop_flag_offset) = $crate::__macro_helpers::define_class::<Self>(
C_NAME,
$crate::__define_class_name_is_auto_generated!($($name)*),
|mut __objc2_builder| {
$crate::__define_class_register_impls! {
(__objc2_builder)
$($impls)*
}
}
);
unsafe {
__OBJC2_CLASS.get().write($crate::__macro_helpers::MaybeUninit::new(__objc2_cls));
if <Self as $crate::__macro_helpers::DefinedIvarsHelper>::HAS_IVARS {
__OBJC2_IVAR_OFFSET.get().write($crate::__macro_helpers::MaybeUninit::new(__objc2_ivar_offset));
}
if <Self as $crate::__macro_helpers::DefinedIvarsHelper>::HAS_DROP_FLAG {
__OBJC2_DROP_FLAG_OFFSET.get().write($crate::__macro_helpers::MaybeUninit::new(__objc2_drop_flag_offset));
}
}
});
unsafe { __OBJC2_CLASS.get().read().assume_init() }
}
#[inline]
fn as_super(&self) -> &Self::Super {
&*self.__superclass
}
const __INNER: () = ();
type __SubclassingType = Self;
}
impl $crate::DefinedClass for $class {
type Ivars = $crate::__select_ivars!($($ivars)?);
#[inline]
fn __ivars_offset() -> $crate::__macro_helpers::isize {
if <Self as $crate::__macro_helpers::DefinedIvarsHelper>::HAS_IVARS {
unsafe { __OBJC2_IVAR_OFFSET.get().read().assume_init() }
} else {
0
}
}
#[inline]
fn __drop_flag_offset() -> $crate::__macro_helpers::isize {
if <Self as $crate::__macro_helpers::DefinedIvarsHelper>::HAS_DROP_FLAG {
unsafe { __OBJC2_DROP_FLAG_OFFSET.get().read().assume_init() }
} else {
0
}
}
const __UNSAFE_OFFSETS_CORRECT: () = ();
}
};
$($attr_impl)*
unsafe impl $crate::DowncastTarget for $class {}
$($attr_impl)*
$crate::__extern_class_check_super_unsafe!($($safety $superclass)?);
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __define_class_derives {
(
($($attr_impl:tt)*)
($for:path)
($(,)*)
) => {};
(
($($attr_impl:tt)*)
($for:path)
(
$(,)*
Debug
$($rest:tt)*
)
) => {
$($attr_impl)*
#[automatically_derived]
impl $crate::__macro_helpers::fmt::Debug for $for {
fn fmt(&self, f: &mut $crate::__macro_helpers::fmt::Formatter<'_>) -> $crate::__macro_helpers::fmt::Result {
f.debug_struct($crate::__macro_helpers::stringify!($for))
.field("super", &**self.__superclass)
.field("ivars", <Self as $crate::DefinedClass>::ivars(self))
.finish()
}
}
$crate::__define_class_derives! {
($($attr_impl)*)
($for)
($($rest)*)
}
};
(
($($attr_impl:tt)*)
($for:path)
(
$(,)*
PartialEq
$($rest:tt)*
)
) => {
$($attr_impl)*
#[automatically_derived]
impl $crate::__macro_helpers::PartialEq for $for {
#[inline]
fn eq(&self, other: &Self) -> $crate::__macro_helpers::bool {
$crate::__macro_helpers::PartialEq::eq(&self.__superclass, &other.__superclass)
}
}
$crate::__define_class_derives! {
($($attr_impl)*)
($for)
($($rest)*)
}
};
(
($($attr_impl:tt)*)
($for:path)
(
$(,)*
Eq
$($rest:tt)*
)
) => {
$($attr_impl)*
#[automatically_derived]
impl $crate::__macro_helpers::Eq for $for {}
$crate::__define_class_derives! {
($($attr_impl)*)
($for)
($($rest)*)
}
};
(
($($attr_impl:tt)*)
($for:path)
(
$(,)*
Hash
$($rest:tt)*
)
) => {
$($attr_impl)*
#[automatically_derived]
impl $crate::__macro_helpers::Hash for $for {
#[inline]
fn hash<H: $crate::__macro_helpers::Hasher>(&self, state: &mut H) {
$crate::__macro_helpers::Hash::hash(&self.__superclass, state)
}
}
$crate::__define_class_derives! {
($($attr_impl)*)
($for)
($($rest)*)
}
};
(
($($attr_impl:tt)*)
($for:path)
(
$(,)*
$derive:path
$(, $($rest:tt)*)?
)
) => {
const _: () = {
#[derive($derive)]
struct Derive;
};
$crate::__macro_helpers::compile_error!($crate::__macro_helpers::stringify!(
#[derive($derive)] is not supported in define_class!
));
$crate::__define_class_derives! {
($($attr_impl)*)
($for)
($($($rest)*)?)
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __select_ivars {
($ivars:ty) => {
$ivars
};
() => {
()
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __define_class_name_is_auto_generated {
($name:expr) => {
false
};
() => {
true
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __define_class_name {
($class:ident, $($name:tt)+) => {
$($name)+
};
($class:ident,) => {
$crate::__macro_helpers::concat!(
$crate::__macro_helpers::module_path!(),
"::",
$crate::__macro_helpers::stringify!($class),
$crate::__macro_helpers::env!("CARGO_PKG_VERSION"),
)
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __define_class_output_impls {
() => {};
(
$(#[$m:meta])*
unsafe impl $protocol:ident for $for:ty {
$($methods:tt)*
}
$($rest:tt)*
) => {
$(#[$m])*
unsafe impl $protocol for $for {}
$(#[$m])*
impl $for {
$crate::__define_class_output_methods! {
$($methods)*
}
}
$crate::__define_class_output_impls!{
$($rest)*
}
};
(
$(#[$m:meta])*
impl $for:ty {
$($methods:tt)*
}
$($rest:tt)*
) => {
$(#[$m])*
impl $for {
$crate::__define_class_output_methods! {
$($methods)*
}
}
$crate::__define_class_output_impls! {
$($rest)*
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __define_class_output_methods {
{} => {};
{
$(#[$($m:tt)*])*
unsafe fn $name:ident($($params:tt)*) $(-> $ret:ty)? $body:block
$($rest:tt)*
} => {
$crate::__rewrite_self_param! {
($($params)*)
($crate::__extract_method_attributes)
($(#[$($m)*])*)
($crate::__define_class_method_out)
(unsafe)
($name)
($($ret)?)
($body)
}
$crate::__define_class_output_methods! {
$($rest)*
}
};
{
$(#[$($m:tt)*])*
fn $name:ident($($params:tt)*) $(-> $ret:ty)? $body:block
$($rest:tt)*
} => {
$crate::__rewrite_self_param! {
($($params)*)
($crate::__extract_method_attributes)
($(#[$($m)*])*)
($crate::__define_class_method_out)
()
($name)
($($ret)?)
($body)
}
$crate::__define_class_output_methods! {
$($rest)*
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __define_class_register_impls {
(
($builder:ident)
) => {};
(
($builder:ident)
$(#[$($m:tt)*])*
unsafe impl $protocol:ident for $for:ty {
$($methods:tt)*
}
$($rest:tt)*
) => {
$crate::__extract_and_apply_cfg_attributes! {
($(#[$($m)*])*)
#[allow(unused_mut)]
let mut __objc2_protocol_builder = $builder.add_protocol_methods::<dyn $protocol>();
#[allow(deprecated)]
#[allow(unused_unsafe)]
unsafe {
$crate::__define_class_register_methods! {
(__objc2_protocol_builder)
$($methods)*
}
}
__objc2_protocol_builder.finish();
}
$crate::__define_class_register_impls! {
($builder)
$($rest)*
}
};
(
($builder:ident)
$(#[$($m:tt)*])*
impl $for:ty {
$($methods:tt)*
}
$($rest:tt)*
) => {
$crate::__extract_and_apply_cfg_attributes! {
($(#[$($m)*])*)
#[allow(deprecated)]
#[allow(unused_unsafe)]
unsafe {
$crate::__define_class_register_methods! {
($builder)
$($methods)*
}
}
}
$crate::__define_class_register_impls! {
($builder)
$($rest)*
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __define_class_register_methods {
{
($builder:ident)
} => {};
{
($builder:ident)
$(#[$($m:tt)*])*
unsafe fn $name:ident($($params:tt)*) $(-> $ret:ty)? $body:block
$($rest:tt)*
} => {
$crate::__rewrite_self_param! {
($($params)*)
($crate::__extract_method_attributes)
($(#[$($m)*])*)
($crate::__define_class_register_out)
($builder)
(unsafe)
($name)
($($ret)?)
($body)
}
$crate::__define_class_register_methods! {
($builder)
$($rest)*
}
};
{
($builder:ident)
$(#[$($m:tt)*])*
fn $name:ident($($params:tt)*) $(-> $ret:ty)? $body:block
$($rest:tt)*
} => {
$crate::__rewrite_self_param! {
($($params)*)
($crate::__extract_method_attributes)
($(#[$($m)*])*)
($crate::__define_class_register_out)
($builder)
()
($name)
($($ret)?)
($body)
}
$crate::__define_class_register_methods! {
($builder)
$($rest)*
}
};
{
($builder:ident)
$_associated_item:item
$($rest:tt)*
} => {
$crate::__define_class_output_methods! {
($builder)
$($rest)*
}
}
}
#[doc(hidden)]
#[macro_export]
macro_rules! __define_class_method_out {
{
($($qualifiers:tt)*)
($name:ident)
($($ret:ty)?)
($body:block)
($builder_method:ident)
($receiver:expr)
($receiver_ty:ty)
($($params_prefix:tt)*)
($($params_rest:tt)*)
($($m_method:tt)*)
($($method_family:tt)*)
($($optional:tt)*)
($($attr_method:tt)*)
($($attr_use:tt)*)
} => {
$crate::__define_class_rewrite_params! {
($($params_rest)*)
()
()
($crate::__define_class_method_out_inner)
($($qualifiers)*)
($name)
($($ret)?)
($body)
($builder_method)
($receiver)
($receiver_ty)
($($params_prefix)*)
($($m_method)*)
($($method_family)*)
($($optional)*)
($($attr_method)*)
($($attr_use)*)
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __define_class_rewrite_params {
{
(_ : $param_ty:ty $(, $($params_rest:tt)*)?)
($($params_converted:tt)*)
($($body_prefix:tt)*)
($out_macro:path)
$($macro_args:tt)*
} => {
$crate::__define_class_rewrite_params! {
($($($params_rest)*)?)
($($params_converted)* _ : <$param_ty as $crate::__macro_helpers::ConvertArgument>::__Inner,)
($($body_prefix)*)
($out_macro)
$($macro_args)*
}
};
{
(mut $param:ident : $param_ty:ty $(, $($params_rest:tt)*)?)
($($params_converted:tt)*)
($($body_prefix:tt)*)
($out_macro:path)
$($macro_args:tt)*
} => {
$crate::__define_class_rewrite_params! {
($($($params_rest)*)?)
($($params_converted)* $param : <$param_ty as $crate::__macro_helpers::ConvertArgument>::__Inner,)
(
$($body_prefix)*
let mut $param = <$param_ty as $crate::__macro_helpers::ConvertArgument>::__from_defined_param($param);
)
($out_macro)
$($macro_args)*
}
};
{
($param:ident : $param_ty:ty $(, $($params_rest:tt)*)?)
($($params_converted:tt)*)
($($body_prefix:tt)*)
($out_macro:path)
$($macro_args:tt)*
} => {
$crate::__define_class_rewrite_params! {
($($($params_rest)*)?)
($($params_converted)* $param : <$param_ty as $crate::__macro_helpers::ConvertArgument>::__Inner,)
(
$($body_prefix)*
let $param = <$param_ty as $crate::__macro_helpers::ConvertArgument>::__from_defined_param($param);
)
($out_macro)
$($macro_args)*
}
};
{
()
($($params_converted:tt)*)
($($body_prefix:tt)*)
($out_macro:path)
$($macro_args:tt)*
} => {
$out_macro! {
$($macro_args)*
($($params_converted)*)
($($body_prefix)*)
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __define_class_method_out_inner {
{
($($qualifiers:tt)*)
($name:ident)
($($ret:ty)?)
($body:block)
($__builder_method:ident)
($__receiver:expr)
($__receiver_ty:ty)
($($params_prefix:tt)*)
(method($($__sel:tt)*))
($($method_family:tt)*)
($($optional:tt)*)
($($attr_method:tt)*)
($($attr_use:tt)*)
($($params_converted:tt)*)
($($body_prefix:tt)*)
} => {
$($attr_method)*
#[allow(clippy::diverging_sub_expression)]
$($qualifiers)* extern "C-unwind" fn $name(
$($params_prefix)*
$($params_converted)*
) $(-> <$ret as $crate::__macro_helpers::ConvertReturn<()>>::Inner)? {
$crate::__define_class_no_method_family!($($method_family)*);
$($body_prefix)*
$crate::__convert_result! {
$body $(; $ret)?
}
}
};
{
($($qualifiers:tt)*)
($name:ident)
($ret:ty)
($body:block)
($__builder_method:ident)
($__receiver:expr)
($receiver_ty:ty)
($($params_prefix:tt)*)
(method_id($($sel:tt)*))
($($method_family:tt)*)
($($optional:tt)*)
($($attr_method:tt)*)
($($attr_use:tt)*)
($($params_converted:tt)*)
($($body_prefix:tt)*)
} => {
$($attr_method)*
#[allow(clippy::diverging_sub_expression)]
$($qualifiers)* extern "C-unwind" fn $name(
$($params_prefix)*
$($params_converted)*
) -> $crate::__macro_helpers::RetainedReturnValue {
$($body_prefix)*
let __objc2_result = $body;
#[allow(unreachable_code)]
<$crate::__method_family!(($($method_family)*) ($($sel)*)) as $crate::__macro_helpers::MessageReceiveRetained<
$receiver_ty,
$ret,
>>::into_return(__objc2_result)
}
};
{
($($qualifiers:tt)*)
($name:ident)
()
($body:block)
($__builder_method:ident)
($__receiver:expr)
($__receiver_ty:ty)
($($params_prefix:tt)*)
(method_id($($sel:tt)*))
($($method_family:tt)*)
($($optional:tt)*)
($($attr_method:tt)*)
($($attr_use:tt)*)
($($params_converted:tt)*)
($($body_prefix:tt)*)
} => {
$($attr_method)*
$($qualifiers)* extern "C-unwind" fn $name() {
$crate::__macro_helpers::compile_error!("`#[unsafe(method_id(...))]` must have a return type")
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __convert_result {
($body:block) => {
$body
};
($body:block; $ret:ty) => {
let __objc2_result = $body;
#[allow(unreachable_code)]
<$ret as $crate::__macro_helpers::ConvertReturn<()>>::convert_defined_return(__objc2_result)
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __define_class_register_out {
{
($builder:ident)
($($qualifiers:tt)*)
($name:ident)
($($__ret:ty)?)
($__body:block)
($builder_method:ident)
($__receiver:expr)
($__receiver_ty:ty)
($($__params_prefix:tt)*)
($($params_rest:tt)*)
($method_or_method_id:ident($($sel:tt)*))
($($method_family:tt)*)
($($optional:tt)*)
($($attr_method:tt)*)
($($attr_use:tt)*)
} => {
$($attr_use)*
{
$crate::__define_class_invalid_selectors!($method_or_method_id($($sel)*));
$crate::__define_class_no_optional!($($optional)*);
$builder.$builder_method(
$crate::sel!($($sel)*),
Self::$name as $crate::__fn_ptr! {
($($qualifiers)*)
(_, _,)
$($params_rest)*
},
);
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __define_class_invalid_selectors {
(method(dealloc)) => {
$crate::__macro_helpers::compile_error!(
"`#[unsafe(method(dealloc))]` is not supported. Implement `Drop` for the type instead"
)
};
(method_id(dealloc)) => {
$crate::__macro_helpers::compile_error!(
"`#[unsafe(method_id(dealloc))]` is not supported. Implement `Drop` for the type instead"
)
};
(method_id(alloc)) => {
$crate::__macro_helpers::compile_error!($crate::__macro_helpers::concat!(
"`#[unsafe(method_id(alloc))]` is not supported. ",
"Use `#[unsafe(method(alloc))]` and do the memory management yourself",
))
};
(method_id(retain)) => {
$crate::__macro_helpers::compile_error!($crate::__macro_helpers::concat!(
"`#[unsafe(method_id(retain))]` is not supported. ",
"Use `#[unsafe(method(retain))]` and do the memory management yourself",
))
};
(method_id(release)) => {
$crate::__macro_helpers::compile_error!($crate::__macro_helpers::concat!(
"`#[unsafe(method_id(release))]` is not supported. ",
"Use `#[unsafe(method(release))]` and do the memory management yourself",
))
};
(method_id(autorelease)) => {
$crate::__macro_helpers::compile_error!($crate::__macro_helpers::concat!(
"`#[unsafe(method_id(autorelease))]` is not supported. ",
"Use `#[unsafe(method(autorelease))]` and do the memory management yourself",
))
};
($method_or_method_id:ident($($sel:tt)*)) => {};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __define_class_no_method_family {
() => {};
($($t:tt)+) => {
$crate::__macro_helpers::compile_error!(
"`#[unsafe(method_family = ...)]` is not yet supported in `define_class!` together with `#[unsafe(method(...))]`"
)
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __define_class_no_optional {
() => {};
(#[optional]) => {
$crate::__macro_helpers::compile_error!(
"`#[optional]` is only supported in `extern_protocol!`"
)
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __fn_ptr {
(
($($qualifiers:tt)*)
($($output:tt)*)
$(,)?
) => {
$($qualifiers)* extern "C-unwind" fn($($output)*) -> _
};
(
($($qualifiers:tt)*)
($($output:tt)*)
_ : $param_ty:ty $(, $($rest:tt)*)?
) => {
$crate::__fn_ptr! {
($($qualifiers)*)
($($output)* _,)
$($($rest)*)?
}
};
(
($($qualifiers:tt)*)
($($output:tt)*)
mut $param:ident : $param_ty:ty $(, $($rest:tt)*)?
) => {
$crate::__fn_ptr! {
($($qualifiers)*)
($($output)* _,)
$($($rest)*)?
}
};
(
($($qualifiers:tt)*)
($($output:tt)*)
$param:ident : $param_ty:ty $(, $($rest:tt)*)?
) => {
$crate::__fn_ptr! {
($($qualifiers)*)
($($output)* _,)
$($($rest)*)?
}
};
}