Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/third_party/rust/objc2/src/macros/   (Firefox Browser Version 153.0.1©)  Datei vom 27.6.2026 mit Größe 44 kB image not shown  

Quelle  define_class.rs

  Sprache: Rust
 

/// Create a new Objective-C class.
///
/// This is useful in many cases since Objective-C frameworks tend to favour a
/// design pattern using "delegates", where to hook into a piece of
/// functionality in a class, you implement that class' delegate protocol in
/// a custom class.
///
/// This macro is the declarative way of creating classes, in contrast with
/// [`ClassBuilder`], which allows creating classes in an imperative fashion.
/// It is highly recommended that you use this macro though, since it contains
/// a lot of extra debug assertions and niceties that help ensure the
/// soundness of your code.
///
/// The class is guaranteed to have been created and registered with the
/// Objective-C runtime after the [`ClassType::class`] function has been
/// called.
///
/// See [Apple's documentation] on defining classes for a more in-depth
/// introduction.
///
/// [Apple's documentation]: https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/DefiningClasses/DefiningClasses.html
/// [`ClassBuilder`]: crate::runtime::ClassBuilder
/// [`ClassType::class`]: crate::ClassType::class
///
///
/// # Specification
///
/// This macro consists of the following parts:
/// - The type definition, along with special attributes.
/// - Any number of inherent implementations.
/// - Any number of protocol implementations.
///
/// With the syntax generally resembling a combination of that in
/// [`extern_class!`] and [`extern_methods!`].
///
/// This macro creates an opaque struct with implementations in [a similar
/// manner as the `extern_class!` macro][ec_spec]. Additionally, it implements
/// the [`DefinedClass`] trait, as well as any protocols specified in the
/// protocol implementations.
///
/// If the type implements [`Drop`], the macro will generate a `dealloc`
/// method for you, which will call `drop` automatically.
///
/// The macro does not support generic types.
///
/// [`extern_class!`]: crate::extern_class
/// [`extern_methods!`]: crate::extern_methods
/// [ec_spec]: crate::extern_class#specification
/// [`DefinedClass`]: crate::DefinedClass
///
///
/// ## Attributes
///
/// You can add most normal attributes to the class, including `#[cfg(...)]`,
/// `#[allow(...)]` and doc comments.
///
/// Exceptions and special attributes are noted below.
///
///
/// ### `#[unsafe(super(...))]` (required)
///
/// Same [as in `extern_class!`](crate::extern_class#unsafesuper-required).
///
///
/// ### `#[thread_kind = ...]` (optional)
///
/// Same [as in `extern_class!`](crate::extern_class#thread_kind---optional).
///
///
/// ### `#[name = "..."]` (optional)
///
/// Specify the runtime-name for the class. Must be unique across the entire
/// application. This is useful if the name of a class is used elsewhere, such
/// as when defining a delegate that needs to be named in e.g. `Info.plist`.
///
/// If not set, this will default to:
/// ```ignore
/// concat!(module_path!(), "::", $class, env!("CARGO_PKG_VERSION"));
/// ```
///
/// E.g. for example `"my_crate::my_module::MyClass0.1.0"`.
///
/// If you're developing a library, it is recommended that you do not set
/// this, and instead rely on the default naming, since that usually works
/// better with users having multiple SemVer-incompatible versions of your
/// library in the same binary.
///
///
/// ### `#[ivars = ...]` (optional)
///
/// Controls [the instance variables] of the class; this is the intended way
/// to specify the data your class stores. If you don't set this attribute,
/// the macro will default to [`()`][unit].
///
/// It is recommended that you wrap your instance variables in [`Cell`],
/// [`RefCell`], atomics or other similar interior mutability abstractions to
/// allow mutating your instance variables. See [the docs on interior
/// mutability][interior_mutability] for further details.
///
/// Beware that if you want to use the class' inherited initializers (such as
/// `init`), you must override the subclass' designated initializers, and
/// initialize your ivars properly in there.
///
/// [the instance variables]: crate::DefinedClass::Ivars
/// [`Cell`]: core::cell::Cell
/// [`RefCell`]: core::cell::RefCell
/// [interior_mutability]: crate::topics::interior_mutability
///
///
/// ### `#[derive(...)]`
///
/// This is overridden, and only works with [`PartialEq`], [`Eq`], [`Hash`]
/// and [`Debug`].
///
/// The implementations delegate to the superclass' implementation, so if you
/// want to change how they work, you should override the [`isEqual:`] and
/// [`hash`] methods instead.
///
/// The `Debug` implementation currently also debug print your ivars, but that
/// may change in the future. Prefer to override [`description`] (and
/// potentially [`debugDescription`]) instead.
///
/// [`Hash`]: std::hash::Hash
/// [`Debug`]: std::fmt::Debug
/// [`isEqual:`]: crate::runtime::NSObjectProtocol::isEqual
/// [`hash`]: crate::runtime::NSObjectProtocol::hash
/// [`description`]: crate::runtime::NSObjectProtocol::description
/// [`debugDescription`]: crate::runtime::NSObjectProtocol::debugDescription
///
///
/// ### `#[cfg_attr(..., ...)]`
///
/// Same [as in `extern_class!`](crate::extern_class#cfg_attr-).
///
///
/// ### `#[repr(...)]`
///
/// Same [as in `extern_class!`](crate::extern_class#repr).
///
///
/// ## Inherent method definitions
///
/// Within the `impl` block you can define two types of functions;
/// ["associated functions"] and ["methods"]. These are then mapped to the
/// Objective-C equivalents "class methods" and "instance methods". In
/// particular, if you use `self` or the special name `this` (or `_this`),
/// your method will be registered as an instance method, and if you don't it
/// will be registered as a class method.
///
/// On instance methods, you can freely choose between different types of
/// receivers, e.g. `&self`, `self: *const Self`, `this: *const Self`, and so
/// on. Note that using `&mut self` is not possible, if you need mutation of
/// your class' instance variables, consider using [`Cell`] or similar
/// instead.
///
/// The desired selector can be specified using the
/// `#[unsafe(method(my:selector:))]` or `#[unsafe(method_id(my:selector:))]`
/// attributes, similar to the [`extern_methods!`] macro.
///
/// If the `#[unsafe(method_id(...))]` attribute is used, the return type must
/// be `Option<Retained<T>>` or `Retained<T>`. Additionally, if the selector
/// is in the "init"-family, the `self`/`this` parameter must be
/// `Allocated<Self>`.
///
/// Putting other attributes on the method such as `cfg`, `allow`, `doc`,
/// `deprecated` and so on is supported. However, note that `cfg_attr` may not
/// work correctly, due to implementation difficulty - if you have a concrete
/// use-case, please [open an issue], then we can discuss it.
///
/// 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
/// can't mark them as `pub` for the same reason). Instead, use the
/// [`extern_methods!`] macro to create a Rust interface to the methods.
///
/// If the parameter or return type is [`bool`], a conversion is performed to
/// make it behave similarly to the Objective-C `BOOL`. Use [`runtime::Bool`]
/// if you want to control this manually.
///
/// Note that `&mut Retained<_>` and other such out parameters are not yet
/// supported, and may generate a panic at runtime.
///
/// ["associated functions"]: https://doc.rust-lang.org/reference/items/associated-items.html#methods
/// ["methods"]: https://doc.rust-lang.org/reference/items/associated-items.html#methods
/// [`Cell`]: core::cell::Cell
/// [open an issue]: https://github.com/madsmtm/objc2/issues/new
/// [`msg_send!`]: crate::msg_send
/// [`runtime::Bool`]: crate::runtime::Bool
///
///
/// ## Protocol implementations
///
/// You can specify protocols that the class should implement, along with any
/// required/optional methods for said protocols.
///
/// The protocol must have been previously defined with [`extern_protocol!`].
///
/// The methods work exactly as normal, they're only put "under" the protocol
/// definition to make things easier to read.
///
/// Putting attributes on the `impl` item such as `cfg`, `allow`, `doc`,
/// `deprecated` and so on is supported.
///
/// [`extern_protocol!`]: crate::extern_protocol
///
///
/// # Panics
///
/// The implemented `ClassType::class` method may panic in a few cases, such
/// as if:
/// - A class with the specified name already exists.
/// - Debug assertions are enabled, and an overridden method's signature is not
///   equal to the one on the superclass.
/// - Debug assertions are enabled, and the protocol's required methods are not
///   implemented.
///
/// And possibly more similar cases in the future.
///
///
/// # Safety
///
/// Using this macro requires writing a lot of `unsafe` markers:
///
/// When writing `#[unsafe(super(...))]`, you must ensure that:
/// - Any invariants that the superclass [`ClassType::Super`] may have must be
///   upheld.
/// - If your type implements `Drop`, the implementation must abide by the
///   following rules:
///   - It must not call any overridden methods.
///   - It must not `retain` the object past the lifetime of the drop.
///   - It must not `retain` in the same scope that `&mut self` is active.
///   - TODO: And probably a few more. [Open an issue] if you would like
///     guidance on whether your implementation is correct.
///
/// `#[unsafe(method(...))]` asserts that the types match those that are
/// expected when the method is invoked from Objective-C. Note that unlike
/// with [`extern_methods!`], there are no safe-guards here; you can write
/// `i8`, but if Objective-C thinks it's an `u32`, it will cause UB when
/// called!
///
/// `unsafe impl 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.
///
/// [`ClassType::Super`]: crate::ClassType::Super
/// [Open an issue]: https://github.com/madsmtm/objc2/issues/new
///
///
/// # Thread safety
///
/// The Objective-C runtime is thread-safe, so any classes you create yourself
/// will automatically be [`Send`] and [`Sync`] (via auto traits) provided
/// that:
/// 1. The superclass is thread-safe, or is [`NSObject`].
/// 2. The ivars are thread-safe.
/// 3. The thread kind is not [`MainThreadOnly`].
///
/// Note though that in many cases, [the frameworks] you will be interacting
/// with will not be thread-safe, and so in many cases it will make sense to
/// [use interior mutability] in your custom classes.
///
/// [`NSObject`]: crate::runtime::NSObject
/// [`MainThreadOnly`]: crate::MainThreadOnly
/// [the frameworks]: crate::topics::about_generated
/// [use interior mutability]: crate::topics::interior_mutability
///
///
/// # Examples
///
/// Define a class `MyCustomObject` that inherits `NSObject`, has a few
/// instance variables and methods, and implements the `NSCopying` protocol.
///
/// ```
/// use std::ffi::c_int;
///
/// use objc2_foundation::{CopyingHelper, NSCopying, NSObject, NSObjectProtocol, NSZone};
/// use objc2::rc::{Allocated, Retained};
/// use objc2::{
///     define_class, extern_methods, extern_protocol, msg_send, AnyThread,
///     ClassType, DefinedClass, ProtocolType,
/// };
///
/// #[derive(Clone)]
/// struct Ivars {
///     foo: u8,
///     bar: c_int,
///     object: Retained<NSObject>,
/// }
///
/// define_class!(
///     // SAFETY:
///     // - The superclass NSObject does not have any subclassing requirements.
///     // - `MyCustomObject` does not implement `Drop`.
///     #[unsafe(super(NSObject))]
///
///     // If we were implementing delegate methods like `NSApplicationDelegate`,
///     // we would specify the object to only be usable on the main thread:
///     // #[thread_kind = MainThreadOnly]
///
///     // If we needed to refer to the class from elsewhere, we'd give it a
///     // name here explicitly.
///     // #[name = "MyCustomObject"]
///
///     // Specify the instance variables this class has.
///     #[ivars = Ivars]
///     struct MyCustomObject;
///
///     impl MyCustomObject {
///         #[unsafe(method(foo))]
///         fn __get_foo(&self) -> u8 {
///             self.ivars().foo
///         }
///
///         #[unsafe(method_id(object))]
///         fn __get_object(&self) -> Retained<NSObject> {
///             self.ivars().object.clone()
///         }
///
///         #[unsafe(method(myClassMethod))]
///         fn __my_class_method() -> bool {
///             true
///         }
///     }
///
///     unsafe impl NSObjectProtocol for MyCustomObject {}
///
///     unsafe impl NSCopying for MyCustomObject {
///         #[unsafe(method_id(copyWithZone:))]
///         fn copyWithZone(&self, _zone: *const NSZone) -> Retained<Self> {
///             let new = Self::alloc().set_ivars(self.ivars().clone());
///             unsafe { msg_send![super(new), init] }
///         }
///
///         // If we have tried to add other methods here, or had forgotten
///         // to implement the method, we would have gotten an error.
///     }
/// );
///
/// // Specially required for `NSCopying`, but otherwise not needed.
/// unsafe impl CopyingHelper for MyCustomObject {
///     type Result = Self;
/// }
///
/// // Add creation method.
/// impl MyCustomObject {
///     fn new(foo: u8) -> Retained<Self> {
///         // Initialize instance variables.
///         let this = Self::alloc().set_ivars(Ivars {
///             foo,
///             bar: 42,
///             object: NSObject::new(),
///         });
///         // Call `NSObject`'s `init` method.
///         unsafe { msg_send![super(this), init] }
///     }
/// }
///
/// // Make an interface to the methods we defined.
/// impl MyCustomObject {
///     extern_methods!(
///         #[unsafe(method(foo))]
///         pub fn get_foo(&self) -> u8;
///
///         #[unsafe(method(object))]
///         pub fn get_object(&self) -> Retained<NSObject>;
///
///         #[unsafe(method(myClassMethod))]
///         pub fn my_class_method() -> bool;
///     );
/// }
///
/// # // Intentionally use `fn main` for clarity
/// fn main() {
///     let obj = MyCustomObject::new(3);
///     assert_eq!(obj.ivars().foo, 3);
///     assert_eq!(obj.ivars().bar, 42);
///     assert!(obj.ivars().object.isKindOfClass(NSObject::class()));
///
///     let obj = obj.copy();
///
///     assert_eq!(obj.get_foo(), 3);
///     assert!(obj.get_object().isKindOfClass(NSObject::class()));
///
///     assert!(MyCustomObject::my_class_method());
/// }
/// ```
///
/// Approximately equivalent to the following ARC-enabled Objective-C code.
///
/// ```text
/// #import <Foundation/Foundation.h>
///
/// @interface MyCustomObject: NSObject <NSCopying>
/// - (instancetype)initWithFoo:(uint8_t)foo;
/// - (uint8_t)foo;
/// - (NSObject*)object;
/// + (BOOL)myClassMethod;
/// @end
///
///
/// @implementation MyCustomObject {
///     // Instance variables
///     uint8_t foo;
///     int bar;
///     NSObject* _Nonnull object;
/// }
///
/// - (instancetype)initWithFoo:(uint8_t)foo_arg {
///     self = [super init];
///     if (self) {
///         self->foo = foo_arg;
///         self->bar = 42;
///         self->object = [NSObject new];
///     }
///     return self;
/// }
///
/// - (uint8_t)foo {
///     return self->foo;
/// }
///
/// - (NSObject*)object {
///     return self->object;
/// }
///
/// + (BOOL)myClassMethod {
///     return YES;
/// }
///
/// // NSCopying
///
/// - (id)copyWithZone:(NSZone *)_zone {
///     MyCustomObject* new = [[MyCustomObject alloc] initWithFoo: self->foo];
///     new->bar = self->bar;
///     new->obj = self->obj;
///     return new;
/// }
///
/// @end
/// ```
#[doc(alias = "@interface")]
#[doc(alias = "@implementation")]
#[macro_export]
macro_rules! define_class {
    {
        // The following special attributes are supported:
        // - #[unsafe(super($($superclasses:path),*))]
        // - #[unsafe(super = $superclass:path)]
        // - #[thread_kind = $thread_kind:path]
        // - #[name = $name:literal]
        // - #[ivars = $ivars:path]
        $(#[$($attrs:tt)*])*
        $v:vis struct $class:ident;

        // unsafe impl Protocol for $class { ... }
        // impl $class { ... }
        $($impls:tt)*
    } => {
        // Struct and various impls.
        $crate::__extract_struct_attributes! {
            ($(#[$($attrs)*])*)

            ($crate::__define_class_inner)
            ($v)
            ($class)
            ($($impls)*)
        }

        // Methods.
        $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)*
    } => {
        // For slightly better diagnostics
        $(#[$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)*)
    ) => {
        // Ensure that the type has the same layout as the superclass.
        // #[repr(transparent)] doesn't work because the superclass is a ZST.
        #[repr(C)]
        $($attr_struct)*
        $v struct $class {
            // Superclasses are deallocated by calling `[super dealloc]`.
            //
            // Auto traits are taken from `__SubclassingType` (which is
            // usually the super class).
            __superclass: $crate::__macro_helpers::ManuallyDrop<$crate::__fallback_if_not_set! {
                ($(<$superclass as $crate::ClassType>::__SubclassingType)?)
                // For better diagnostics, see also __extern_class_inner!
                ($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)*)
        }

        // Anonymous block to hide the shared statics
        $($attr_impl)*
        const _: () = {
            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());
            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());
            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());

            // Creation
            unsafe impl $crate::ClassType for $class {
                type Super = $crate::__fallback_if_not_set! {
                    ($($superclass)?)
                    // For better diagnostics, see also __extern_class_inner!
                    ($crate::runtime::NSObject)
                };

                type ThreadKind = $crate::__fallback_if_not_set! {
                    ($(dyn ($($thread_kind)+))?)
                    // Default to the super class' thread kind
                    (<<Self as $crate::ClassType>::Super as $crate::ClassType>::ThreadKind)
                };

                const NAME: &'static $crate::__macro_helpers::str = $crate::__fallback_if_not_set! {
                    ($($name)*)
                    (
                        $crate::__macro_helpers::concat!(
                            // Module path includes crate name when in library.
                            $crate::__macro_helpers::module_path!(),
                            "::",
                            $crate::__macro_helpers::stringify!($class),
                            $crate::__macro_helpers::env!("CARGO_PKG_VERSION"),
                        )
                    )
                };

                fn class() -> &'static $crate::runtime::AnyClass {
                    let _ = <Self as $crate::__macro_helpers::ValidThreadKind<Self::ThreadKind>>::check;
                    let _ = <Self as $crate::__macro_helpers::MainThreadOnlyDoesNotImplSendSync<_>>::check;

                    // TODO: Use `std::sync::OnceLock`
                    static REGISTER_CLASS: $crate::__macro_helpers::Once = $crate::__macro_helpers::Once::new();

                    REGISTER_CLASS.call_once(|| {
                        let mut __objc2_builder = $crate::__macro_helpers::ClassBuilderHelper::<Self>::new();

                        // Implement protocols and methods
                        $crate::__define_class_register_impls! {
                            (__objc2_builder)
                            $($impls)*
                        }

                        let (__objc2_cls, __objc2_ivar_offset, __objc2_drop_flag_offset) = __objc2_builder.register();

                        // SAFETY: Modification is ensured by `Once` to happen
                        // before any access to the variables.
                        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));
                            }
                        }
                    });

                    // SAFETY: We just registered the class, so is now available
                    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 {
                    // Only access ivar offset if we have an ivar.
                    //
                    // This makes the offset not be included in the final
                    // executable if it's not needed.
                    if <Self as $crate::__macro_helpers::DefinedIvarsHelper>::HAS_IVARS {
                        // SAFETY: Accessing the offset is guaranteed to only be
                        // done after the class has been initialized.
                        unsafe { __OBJC2_IVAR_OFFSET.get().read().assume_init() }
                    } else {
                        // Fall back to an offset of zero.
                        //
                        // This is fine, since any reads here will only be via zero-sized
                        // ivars, where the actual pointer doesn't matter.
                        0
                    }
                }

                #[inline]
                fn __drop_flag_offset() -> $crate::__macro_helpers::isize {
                    if <Self as $crate::__macro_helpers::DefinedIvarsHelper>::HAS_DROP_FLAG {
                        // SAFETY: Same as above.
                        unsafe { __OBJC2_DROP_FLAG_OFFSET.get().read().assume_init() }
                    } else {
                        // Fall back to an offset of zero.
                        //
                        // This is fine, since the drop flag is never actually used in the
                        // cases where it was not added.
                        0
                    }
                }

                // SAFETY: The offsets are implemented correctly
                const __UNSAFE_OFFSETS_CORRECT: () = ();
            }
        };

        // SAFETY: This macro only allows non-generic classes and non-generic
        // classes are always valid downcast targets.
        $($attr_impl)*
        unsafe impl $crate::DowncastTarget for $class {}

        $($attr_impl)*
        $crate::__extern_class_check_super_unsafe!($($safety $superclass)?);
    };
}

/// Mirror of [`crate::__extern_class_derives`].
#[doc(hidden)]
#[macro_export]
macro_rules! __define_class_derives {
    // Base case
    (
        ($($attr_impl:tt)*)
        ($for:path)
        ($(,)*)
    ) => {};

    // Debug
    (
        ($($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)*)
        }
    };

    // PartialEq
    (
        ($($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 {
                // Delegate to the superclass (referential equality)
                $crate::__macro_helpers::PartialEq::eq(&self.__superclass, &other.__superclass)
            }
        }

        $crate::__define_class_derives! {
            ($($attr_impl)*)
            ($for)
            ($($rest)*)
        }
    };

    // Eq
    (
        ($($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)*)
        }
    };

    // Hash
    (
        ($($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: &tyle='color:red'>mut H) {
                // Delegate to the superclass (which hashes the reference)
                $crate::__macro_helpers::Hash::hash(&self.__superclass, state)
            }
        }

        $crate::__define_class_derives! {
            ($($attr_impl)*)
            ($for)
            ($($rest)*)
        }
    };

    // Unhandled derive
    (
        ($($attr_impl:tt)*)
        ($for:path)
        (
            $(,)*
            $derive:path
            $(, $($rest:tt)*)?
        )
    ) => {
        const _: () = {
            // For better diagnostics.
            #[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
    };
    () => {
        // Default ivars to unit
        ()
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! __define_class_output_impls {
    // Base-case
    () => {};

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

        $($rest:tt)*
    ) => {
        // SAFETY: Upheld by caller
        $(#[$m])*
        unsafe impl $protocol for $for {}

        $(#[$m])*
        impl $for {
            $crate::__define_class_output_methods! {
                $($methods)*
            }
        }

        $crate::__define_class_output_impls!{
            $($rest)*
        }
    };

    // Without protocol
    (
        $(#[$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 {
    // Base case
    {} => {};

    // Unsafe variant
    {
        $(#[$($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)*
        }
    };

    // Safe variant
    {
        $(#[$($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 {
    // Base-case
    (
        ($builder:ident)
    ) => {};

    // With protocol
    (
        ($builder:ident)

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

        $($rest:tt)*
    ) => {
        $crate::__extract_and_apply_cfg_attributes! {
            ($(#[$($m)*])*)

            // Implement protocol
            #[allow(unused_mut)]
            let mut __objc2_protocol_builder = $builder.add_protocol_methods::<dyn $protocol>();

            // In case the user's function is marked `deprecated`
            #[allow(deprecated)]
            // In case the user did not specify any methods
            #[allow(unused_unsafe)]
            // SAFETY: Upheld by caller
            unsafe {
                $crate::__define_class_register_methods! {
                    (__objc2_protocol_builder)

                    $($methods)*
                }
            }

            // Finished creating protocol; get error message if any
            __objc2_protocol_builder.finish();
        }

        $crate::__define_class_register_impls! {
            ($builder)
            $($rest)*
        }
    };

    // Without protocol
    (
        ($builder:ident)

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

        $($rest:tt)*
    ) => {
        $crate::__extract_and_apply_cfg_attributes! {
            ($(#[$($m)*])*)

            // In case the user's function is marked `deprecated`
            #[allow(deprecated)]
            // In case the user did not specify any methods
            #[allow(unused_unsafe)]
            // SAFETY: Upheld by caller
            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 {
    // Base case
    {
        ($builder:ident)
    } => {};

    // Unsafe variant
    {
        ($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)*
        }
    };

    // Safe variant
    {
        ($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)*
        }
    };

    // Consume associated items for better UI.
    //
    // This will still fail inside __define_class_output_methods!
    {
        ($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 {
    // Convert _
    {
        (_ : $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)*
        }
    };
    // Convert mut
    {
        (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)*
        }
    };
    // Convert
    {
        ($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)*
        }
    };
    // Output result
    {
        ()
        ($($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 {
    // #[unsafe(method(...))]
    {
        ($($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)?
            }
        }
    };

    // #[unsafe(method_id(...))]
    {
        ($($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 {
            // TODO: Somehow tell the compiler that `this: Allocated<Self>` is non-null.

            $($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!`"
        )
    };
}

/// Create function pointer type with inferred parameters.
#[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)*)?
        }
    };
}

Messung V0.5 in Prozent
C=90 H=94 G=91

¤ Dauer der Verarbeitung: 0.15 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.