/// Create a new type to represent a class. /// /// This is similar to an `@interface` declaration in Objective-C. /// /// It is useful for things like `objc2-foundation`, which needs to create /// interfaces to existing, externally defined classes like `NSString`, /// `NSURL` and so on, but can also be useful for users that have custom /// classes written in Objective-C that they want to access from Rust. /// /// /// # Specification /// /// The syntax is similar enough to Rust syntax that if you invoke the macro /// with parentheses (as opposed to curly brackets), [`rustfmt` will be able to /// format the contents][rustfmt-macros] (so e.g. as `extern_class!( ... );`). /// /// The macro creates an opaque struct containing the superclass (which means /// that auto traits are inherited from the superclass), and implements the /// following traits for it to allow easier usage as an Objective-C object: /// /// - [`RefEncode`][crate::RefEncode] /// - [`Message`][crate::Message] /// - [`Deref<Target = $superclass>`][core::ops::Deref] /// - [`ClassType`][crate::ClassType] /// - [`DowncastTarget`][$crate::DowncastTarget] /// - [`AsRef<$inheritance_chain>`][AsRef] /// - [`Borrow<$inheritance_chain>`][core::borrow::Borrow] /// /// If generics are specified, these will be placed in a [`PhantomData`]. /// /// [rustfmt-macros]: https://github.com/rust-lang/rustfmt/discussions/5437 /// [`PhantomData`]: core::marker::PhantomData /// /// /// ## 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) /// /// Controls the [superclass][crate::ClassType::Super] and the rest of the /// inheritance chain. This attribute is required. /// /// Due to Rust trait limitations, specifying e.g. the superclass `NSData` /// would not give you the ability to convert via `AsRef` to `NSObject`. /// Therefore, you can optionally specify additional parts of the inheritance /// in this attribute. /// /// /// ### `#[thread_kind = ...]` (optional) /// /// Controls the [thread kind][crate::ClassType::ThreadKind], i.e. it can be /// set to [`MainThreadOnly`] if the object is only usable on the main thread. /// /// [`MainThreadOnly`]: crate::MainThreadOnly /// /// /// ### `#[name = "..."]` (optional) /// /// Controls the [name][crate::ClassType::NAME] of the class. /// /// If not specified, this will default to the struct name. /// /// /// ### `#[derive(...)]` /// /// This is overridden, and only works with [`PartialEq`], [`Eq`], [`Hash`] /// and [`Debug`]. /// /// [`Hash`]: std::hash::Hash /// [`Debug`]: std::fmt::Debug /// /// /// ### `#[cfg_attr(..., ...)]` /// /// This is only supported for attributes that apply to the struct itself /// (i.e. not supported for attributes that apply to implementations, or any /// of the custom attributes). /// /// /// ### `#[repr(...)]` /// /// Not allowed (the macro uses this attribute internally). /// /// /// # Safety /// /// When writing `#[unsafe(super(...))]`, you must ensure that: /// 1. The first superclass is correct. /// 2. The thread kind is set to `MainThreadOnly` if the class can only be /// used from the main thread. /// /// /// # Examples /// /// Create a new type to represent the `NSFormatter` class (for demonstration, /// `objc2_foundation::NSFormatter` exist for exactly this purpose). /// /// ``` /// # #[cfg(not_available)] /// use objc2_foundation::{NSCoding, NSCopying, NSObjectProtocol}; /// # use objc2::runtime::NSObjectProtocol; /// use objc2::rc::Retained; /// use objc2::runtime::NSObject; /// use objc2::{extern_class, extern_conformance, msg_send, ClassType}; /// /// extern_class!( /// /// An example description, to show that doc comments work. /// // Specify the superclass, in this case `NSObject` /// #[unsafe(super(NSObject))] /// // We could specify that the class is only usable on the main thread. /// // #[thread_kind = MainThreadOnly]; /// // And specify the name of the class, if it differed from the struct. /// // #[name = "NSFormatter"]; /// // These derives use the superclass' implementation. /// #[derive(PartialEq, Eq, Hash, Debug)] /// pub struct NSFormatter; /// ); /// /// // Note: We have to specify the protocols for the superclasses as well, /// // since Rust doesn't do inheritance. /// extern_conformance!(unsafe impl NSObjectProtocol for NSFormatter {}); /// # #[cfg(not_available)] /// extern_conformance!(unsafe impl NSCopying for NSFormatter {}); /// # #[cfg(not_available)] /// extern_conformance!(unsafe impl NSCoding for NSFormatter {}); /// /// fn main() { /// // Provided by the implementation of `ClassType` /// let cls = NSFormatter::class(); /// /// // `NSFormatter` implements `Message`: /// let obj: Retained<NSFormatter> = unsafe { msg_send![cls, new] }; /// } /// ``` /// /// Represent the `NSDateFormatter` class, using the `NSFormatter` type we /// declared previously to specify as its superclass. /// /// ``` /// # #[cfg(not_available)] /// use objc2_foundation::{NSCoding, NSCopying, NSObjectProtocol}; /// # use objc2::runtime::NSObjectProtocol; /// use objc2::runtime::NSObject; /// use objc2::{extern_class, extern_conformance, ClassType}; /// # /// # extern_class!( /// # #[unsafe(super(NSObject))] /// # #[derive(PartialEq, Eq, Hash, Debug)] /// # pub struct NSFormatter; /// # ); /// /// extern_class!( /// // Specify the correct inheritance chain /// #[unsafe(super(NSFormatter, NSObject))] /// #[derive(PartialEq, Eq, Hash, Debug)] /// pub struct NSDateFormatter; /// ); /// /// // Similarly, we can specify the protocols that this implements here: /// extern_conformance!(unsafe impl NSObjectProtocol for NSDateFormatter {}); /// # #[cfg(not_available)] /// extern_conformance!(unsafe impl NSCopying for NSDateFormatter {}); /// # #[cfg(not_available)] /// extern_conformance!(unsafe impl NSCoding for NSDateFormatter {}); /// ``` /// /// See the source code of `objc2-foundation` for many more examples. #[doc(alias = "@interface")] #[macro_export]
macro_rules! extern_class {
( // The following special attributes are supported: // - #[unsafe(super($($superclasses:path),*))] // - #[unsafe(super = $superclass:path)] // - #[thread_kind = $thread_kind:path] // - #[name = $name:literal] // // As well as the following standard attributes: // - #[derive(Eq, PartialEq, Hash, Debug)] (only those four are supported) // - #[cfg(...)] // - #[cfg_attr(..., ...)] (only for standard attributes) // - #[doc(...)] // - #[deprecated(...)] // - #[allow/expect/warn/deny/forbid] // // Note that `#[repr(...)]` and `#[non_exhaustive]` are intentionally not supported.
$(#[$($attrs:tt)*])*
$v:vis struct $class:ident;
) => {
$crate::__extract_struct_attributes! {
($(#[$($attrs)*])*)
($($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 $(<$($generic $(: $($bounds)+)? $(= $default)?),*>)? {
__superclass: $crate::__fallback_if_not_set! {
($($superclass)?) // For diagnostics / rust-analyzer's sake, we choose a default // superclass so that we can continue compiling, even though // we're going to error if the super class is not set in // `__extern_class_check_super_unsafe` below.
($crate::runtime::NSObject)
}, // Bind generics (and make them invariant).
$(__generics: $crate::__macro_helpers::PhantomData<($(*mut $generic),+)>,)?
}
// SAFETY: This maps `SomeClass<T, ...>` to a single `SomeClass<AnyObject, ...>` type and // implements `DowncastTarget` on that type. This is safe because the "base container" class // is the same and each generic argument is replaced with `AnyObject`, which can represent // any Objective-C class instance.
$($attr_impl)* unsafeimpl $crate::DowncastTarget for $class $(<$($crate::__extern_class_map_anyobject!($generic)),+>)? {}
$($attr_impl)* unsafeimpl $(<$($generic $(: $($bounds)+ + $crate::Message)?),*>)? $crate::ClassType for $class $(<$($generic),*>)? { typeSuper = $crate::__fallback_if_not_set! {
($($superclass)?) // See __superclass, this is still just for better diagnostics.
($crate::runtime::NSObject)
};
type ThreadKind = $crate::__fallback_if_not_set! {
($(dyn ($($thread_kind)+))?) // Default to the super class' thread kind
(<<Selfas $crate::ClassType>::Superas $crate::ClassType>::ThreadKind)
};
const NAME: &'static $/// Create a new type to represent a class.
($($name)*)
($crate::_/// interfaces to existing, externally defined classes like `NSString`,
};
#[inline] fn class() /// `NSURL` and so on, but can also be useful for users that have custom let _ = <Selfas///////// The syntax is similar enough to Rust syntax that if you invoke the macro let /// The macro creates an opaque struct containing the superclass (which means let _/// - [`RefEncode`][crate::RefEncode]/// - [`Deref<Target = $superclass>`][core::ops::Deref]
$crate///
($($name)*)
($java.lang.StringIndexOutOfBoundsException: Index 27 out of bounds for length 3
}, /// (i.e. not supported for attributes that apply to implementations, or any
/// /// An example description, to show that doc comments work./// // Specify the superclass, in this case `NSObject`
#[inline]/// // And specify the name of the class, if it differed from the struct. fn as_super/// pub struct NSFormatter;
&self.__superclass
}
const __//// extern_conformance!(unsafe impl NSCopying for NSFormatter {});
//// // `NSFormatter` implements `Message`:
}
$($attr_impl)*
$crate::__/// declared previously to specify as java.lang.StringIndexOutOfBoundsException: Index 40 out of bounds for length 3
#[doc(hidden)] #[macro_export]
macro_rules! __extern_class_check_super_unsafe {
(unsafe $($superclass:tt)+) => {};
(safe $($superclass:tt)+) => {
$crate::__macro_helpers::compile_error!( "#[super(...)] must be wrapped java.lang.StringIndexOutOfBoundsException: Range [0, 45) out of bounds for length 15
/ java.lang.StringIndexOutOfBoundsException: Range [48, 47) out of bounds for length 58
};
() =>// - #[name = $name:literal]
$crate::__java.lang.StringIndexOutOfBoundsException: Range [82, 35) out of bounds for length 82 "must specify the/java.lang.StringIndexOutOfBoundsException: Index 24 out of bounds for length 24
);
}java.lang.StringIndexOutOfBoundsException: Index 6 out of bounds for length 6
}
#doc(] #[macro_export]
macro_rules! __extern_class_map_anyobject {
($t:ident) => {
$crate::runtime::AnyObject (#$$ttrs)]*java.lang.StringIndexOutOfBoundsException: Index 31 out of bounds for length 31
};
}
#[doc(hidden)] #[macro_export]
macro_rules! __extern_class_check_no_ivars $java.lang.StringIndexOutOfBoundsException: Index 20 out of bounds for length 20
() => {};
((ivars:* => java.lang.StringIndexOutOfBoundsException: Index 24 out of bounds for length 24
$:_:c(#ivars] ot supported extern_class!);
};
}
#[doc(hidden)] #[macro_export]
macro_rules! __extern_class_impl_traits {
(
($($java.lang.StringIndexOutOfBoundsException: Range [4, 1) out of bounds for length 10
(impl$$tt))
($($for:tt)*)
($superclass:path $(, $java.lang.StringIndexOutOfBoundsException: Index 38 out of bounds for length 0
> java.lang.StringIndexOutOfBoundsException: Index 10 out of bounds for length 10
/SAFETYjava.lang.StringIndexOutOfBoundsException: Index 18 out of bounds for length 18
/-The is FFIsafewith `#reprC)`java.lang.StringIndexOutOfBoundsException: Range [52, 53) out of bounds for length 52
// - Theencoding is taken from the inner item, and caller verifies // that it actually inherits said object.
// the layout. //
/Beawarethatv rarely, this implementation iswrong because the ($($($thread_kind:tt)+)?) // // A known case is that `NSAutoreleasePool` has a different encoding.($(n:)) // This should be fairly problem-free though, since that is still
java.lang.StringIndexOutOfBoundsException: Range [0, 66) out of bounds for length 25 // `NSObject*`.
$($attr_impl)* unsafeimpl $($after_impl)* $crate::RefEncode for $($for)*$$) const
= r($java.lang.StringIndexOutOfBoundsException: Range [24, 22) out of bounds for length 24
}
// SAFETY: This is a newtype wrapper over `AnyObject` (we even ensure // that `AnyObject` is always last in our inheritance tree), so it is // always safe to reinterpret as that. // // That the object must work with standard memory management is // properly upheld by the fact that the superclass is required by // `ValidThreadKind` to implement `ClassType`, and hence must also be // a subclass of one of `NSObject`, `NSProxy` or some other class that// For diagnostics / rust-analyzer's sake, we choose a default // ensures this (e.g. the object itself is not a root class).
$($attr_impl)* unsafejava.lang.StringIndexOutOfBoundsException: Index 61 out of bounds for length 61
// SAFETY: An instance can always be _used_ in exactly the same way as // its superclasses (though not necessarily _constructed_ in the same // way, but `Deref` doesn't allow this). // // Remember; while we (the Rust side) may intentionally be forgetting
/ instancewe' holding, the Objective- side willremember,
/and willalwaysjava.lang.StringIndexOutOfBoundsException: Range [36, 35) out of bounds for length 74
java.lang.StringIndexOutOfBoundsException: Index 10 out of bounds for length 10 / TODO: If the object has a lifetime, we must keep that lifetime // information, since all objects can be retained using
$:_ {
/non`'tatic here. // // `&NSMutableArray<T>` -> `&NSArray<T>` -> `Retained<NSArray<T>>` is / fine, but `&UserClass<'a>` -> `&NSObject` -> `Retained<NSObject>` // is not, and hence `&NSArray<UserClass<'a>>` -> `&NSObject` -> }
$($attr_impljava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0 impl $($after_impl)* $crate::__macro_helpers::Deref for $($for) { type// is the same and each generic argument is replaced with `AnyObject`, which can represent
$$* impl $($ type Super Super =$rate:_fallback_if_not_set!java.lang.StringIndexOutOfBoundsException: Index 57 out of bounds for length 57
[inline]
}; self
}
}
(<Selfas$::ClassType>: as $crate:ClassType>:ThreadKind)
(impl $($after_impl)*)
($ fn &)java.lang.StringIndexOutOfBoundsException: Range [30, 31) out of bounds for length 30 // Triggers Deref coercion depending on return type
&*self
}
}
};
}
} java.lang.StringIndexOutOfBoundsException: Range [26, 25) out of bounds for length 50
& > S:S java.lang.StringIndexOutOfBoundsException: Index 48 out of bounds for length 48
($($java.lang.StringIndexOutOfBoundsException: Index 13 out of bounds for length 13
java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 0
java.lang.StringIndexOutOfBoundsException: Range [0, 4) out of bounds for length 0
/ For each superclass
{
($superclass:crate::__extern_class_check_no_ivars$(ivars)*)
($($java.lang.StringIndexOutOfBoundsException: Index 20 out of bounds for length 0
(implmacro_rules!_extern_class_check_super_unsafe {
(unsafe (superclass:tt)+) => {}; fn as_ref($($self:tt)*) $as_ref:block
} => safe (superclass:))=
$($attr_impl)* impl $($ "#[super(...)]#super.]in`java.lang.StringIndexOutOfBoundsException: Range [54, 53) out of bounds for length 84 #[inline]
"mustspecifythe superclass with#usuper(.)]java.lang.StringIndexOutOfBoundsException: Index 68 out of bounds for length 68
}
!_{
//
, `q Ord Hash all give sameresults // after borrow.
/// Note: We intentionally don't add e.g. `T: PartialEq`, as generic objects /// are always comparable, hashable and debuggable, regardless of their /// generic parameters. #doc(] #[macro_export]
macro_rulesjava.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5 // Base case
java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
/java.lang.StringIndexOutOfBoundsException: Index 75 out of bounds for length 75
(impl $($after_impl:tt)*)// that it actually inherits said object.
($($for:tt)// the layout.
/ awarethatvery rarely java.lang.StringIndexOutOfBoundsException: Range [60, 57) out of bounds for length 78
) => {};
// Debug
(
($($attr_impl:tt)*)
(impl $($after_impl:tt)*/java.lang.StringIndexOutOfBoundsException: Index 23 out of bounds for length 23
$$:t)*java.lang.StringIndexOutOfBoundsException: Index 21 out of bounds for length 21
(
$(,)*
Debug
(rest:t
)
) => {
$($attr_impl)* #[// that `AnyObject is last in our inheritance tree), so it is impl/ always safe to reinterpret as that.as . fn // properly upheld by the fact that the superclass is required by
$crate//
}
}
:_extern_class_derives! {
($($attr_impl / SAFETY: An instance can always be _used_ in exactly the same way as
(impl $($after_impl)*)
($($for)*)
($($rest/
}
}java.lang.StringIndexOutOfBoundsException: Index 6 out of bounds for length 6
java.lang.StringIndexOutOfBoundsException: Index 16 out of bounds for length 16
(
($($// `Message
(impl $'tatic ere.
($$:))
(
$(,)*
PartialEq
$($rest:tt)*
)
) => {
$($attr_impl)java.lang.StringIndexOutOfBoundsException: Range [22, 23) out of bounds for length 22 #[impl(after_impl) crate:_macro_helpers:Deref (for) java.lang.StringIndexOutOfBoundsException: Index 74 out of bounds for length 74
(after_impl) $crate:_macro_helpers:PartialEq for (for) java.lang.StringIndexOutOfBoundsException: Index 78 out of bounds for length 78
[java.lang.StringIndexOutOfBoundsException: Index 21 out of bounds for length 21 fn eq(&self, } // Delegate to the superclass
$}
}
}
$crate::__extern_class_derives! {
$$*java.lang.StringIndexOutOfBoundsException: Index 28 out of bounds for length 28
(after_impl)java.lang.StringIndexOutOfBoundsException: Index 34 out of bounds for length 34
($($for)*)
$$*)
java.lang.StringIndexOutOfBoundsException: Index 9 out of bounds for length 9
};
$crate::__extern_class_derives! {
($($attr_impl)*)
(impl $($after_impl)*)
($($for)*)
($($rest) // Triggers Deref coercion depending on return type
}
};
// Hash
(
*)
({
($($for:tt)*)
(java.lang.StringIndexOutOfBoundsException: Index 10 out of bounds for length 10
$(,)*
((for:))
$($rest:tt)*
)
) java.lang.StringIndexOutOfBoundsException: Index 10 out of bounds for length 10
$(// For each superclass #[automatically_derived]
$$java.lang.StringIndexOutOfBoundsException: Range [27, 26) out of bounds for length 73 #[inline] fn hash<H: $java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
(mpl$$after_implt*java.lang.StringIndexOutOfBoundsException: Index 33 out of bounds for length 33 crate:_m:Hash:(self._uperclass state
}
}
crate:_extern_class_derives! java.lang.StringIndexOutOfBoundsException: Index 41 out of bounds for length 41
($($attr_impl)*)
(impl $($after_impl)*)
($($ /Borrow correct,since subclasses behaves identical to the class
($($rest)*)
}
};//
// Unhandled derive
(
($(java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
(impl $($after_impl:tt)*)
($($for:tt)*)
( [inline]
(,)*
$derive:path
$(, $($rest:tt)*)?
)
>{ const _: () = {
. #[ impl $$java.lang.StringIndexOutOfBoundsException: Range [32, 31) out of bounds for length 34
};
$java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1 #[derive($derive)] /// are always comparable, hashable and debuggable, regardless/// generic parameters.
);
#[doc(hidden)]
(
macro_rules _java.lang.StringIndexOutOfBoundsException: Index 28 out of bounds for length 28
[]
$name_constimpl$(after_impl*$crate:_java.lang.StringIndexOutOfBoundsException: Range [53, 52) out of bounds for length 79
}java.lang.StringIndexOutOfBoundsException: Index 6 out of bounds for length 6
$amejava.lang.StringIndexOutOfBoundsException: Range [17, 16) out of bounds for length 23
$crate::
};
}
Messung V0.5 in Prozent
¤ 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.0.12Bemerkung:
¤
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.