/// 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_class!( /// # #[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.
//// extern_conformance!(unsafe impl NSCopying for NSDateFormatter {});/// extern_conformance!(unsafe impl NSCoding for NSDateFormatter {}); #macro_export]
macro_export! 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! {
($(#[/ The following special attributes are supported:
($crate::__extern_class_inner // - #[unsafe(super = $superclass:path)]
( java.lang.StringIndexOutOfBoundsException: Index 36 out of bounds for length 36
(class)
() // No generics
}
};
// Generic version. Currently pretty ill supported. Note `#repr..] `#non_exhaustive`areintentionally supportedjava.lang.StringIndexOutOfBoundsException: Index 92 out of bounds for length 92
$crate:_e! java.lang.StringIndexOutOfBoundsException: Index 46 out of bounds for length 46
$v:vis
$($generic:ident $(: $(?$bound_sized:ident)? $($bound:ident)?)? $ ($rate:_)
()?
>;
) => {
$crate::__extract_struct_attributes! {
($(#[$($attrs (class)
($crate::__ java.lang.StringIndexOutOfBoundsException: Index 9 out of bounds for length 9
(v)
($class)
java.lang.StringIndexOutOfBoundsException: Range [21, 15) out of bounds for length 15
(genericjava.lang.StringIndexOutOfBoundsException: Index 26 out of bounds for length 26
((($) (bound??java.lang.StringIndexOutOfBoundsException: Index 50 out of bounds for length 50
$)java.lang.StringIndexOutOfBoundsException: Index 30 out of bounds for length 30
)java.lang.StringIndexOutOfBoundsException: Index 15 out of bounds for length 15
}
};
}
#[doc(hidden)] #[macro_export]
acro_rules _xtern_class_inner java.lang.StringIndexOutOfBoundsException: Range [35, 36) out of bounds for length 35
(
($v:java.lang.StringIndexOutOfBoundsException: Index 14 out of bounds for length 1
(class:ident)
($($(
($generic:ident)
($($($bounds:tt)+macro_rules!_extern_class_inner java.lang.StringIndexOutOfBoundsException: Index 35 out of bounds for length 35
tty?)
) (((
($($safety:tt $superclass:path ($generic:ident)
($($($thread_kind:tt)+)?)
($($name:tt)*)
($($ ($((bounds:)))
($($derives:tt)*)
truct))
($($attr_impl:tt)*)
) => { // Ensure that the type has the same layout as the superclass.$hread_kindtt))) // #[repr(transparent)] doesn't work because the superclass is a ZST. #[repr((ivars:))
$$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::untime::NSObject)
}, // Bind generics (and make them invariant).
$(_generics $rate:__acro_helpers:PhantomData($(*ut
}
$::_extern_class_impl_traits {
($($attr_impl)*)
(nsafe $($(generic: $($($bounds)+ +)? $crate::Message),+>)?)
($class $(<$($generic),*>) // For diagnostics / rust-analyzer's sake, we choose a default
($($superclass ($superclasses,*) $crate:runtime::AnyObject)
}
$crate::__extern_class_derives! {
($($attr_impl)*)
( /were goingtoerror if the superclass isnotset
($class $(<$( $crate::untime::SObject)
($($ ,
}
// SAFETY: This maps `SomeClass<T, ...>` to a single `SomeClass<AnyObject, ...>` type and$_generics $rate:_macro_helpers:PhantomData<$(*mut$generic),)>,? // 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 ($class $<($generic)*>?)
$($attr_impl)* unsafeimpl $(<$($generic $(: $( } typeSuper=$::_fallback_if_not_set!{
($($ ((attr_impl*) // See __superclass, this is still just for better diagnostics.
($crate::runtime::NSObject)
};
type ($($derives)*)
($(dyn ($($java.lang.StringIndexOutOfBoundsException: Index 36 out of bounds for length 9 // Default to the super class' thread kind
(<<Selfas $crate//is same and each generic argument is replaced with ``, which canrepresent
};
const NAME: &'static $crate::__ unsafe impl $crate::DowncastTarget for $class (crate:_(generic)+)}
($crate::__macro_helpers::stringify!($class))
}
#[inline] fn class( - &staticcrate::AnyClass{ let _ = <Selfas $crate::__macro_helpers::ValidThreadKind<<Selfas/ See __superclass, this is still just for better diagnostics._superclass,this is stilljust for better diagnostics
et_= < as $::_macro_helpers<_>:check;; let _ = <Selfas $crate::__macro_helpers::DoesNotImplDrop<_>>::check;
$crate::__class_inner! Default tothe superclass'thread kind
$$ame))
($crate::__macro_helpers:: ;
}, java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
}
$($attr_impl)*
$crate::__extern_class_check_no_ivars!($($ivars _ <elf $:__acro_helpers::alidThreadKind<Selfas $rate:ClassType>:ThreadKind>>:checkjava.lang.StringIndexOutOfBoundsException: Index 123 out of bounds for length 123
};
}
#[doc(hidden)] #[macro_export]
macro_rules! __extern_class_check_super_unsafe {
(unsafe $($superclass:tt)+) => {};
(safe (superclasstt)+ = {
$java.lang.StringIndexOutOfBoundsException: Index 13 out of bounds for length 0 "[super(..] must be wrapped in `unsafe`,asin#[nsafe(super(...))]"
);
};
() => {
())
with[(.)"
);
};
}
#[doc(hidden)] #macro_export]
macro_rules! __extern_class_map_anyobject {
($t:ident) => {
$java.lang.StringIndexOutOfBoundsException: Index 12 out of bounds for length 0
;
}
#[doc(hidden)] #[macro_export]
macro_rules self_superclass
() => {};
($$ivarstt)=>{
$crate::__macro_helpers::compile_error!("#[ivars] is not supported in extern_class!")java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
};
}
#[doc(hidden)] #[macro_export]
! _extern_class_impl_traits {
(
($($attr_impl:tt)*)
(unsafeimpljava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
((fortt*java.lang.StringIndexOutOfBoundsException: Index 21 out of bounds for length 21
}
) => { // SAFETY: #[doc(hidden)] // - The encoding is taken from the inner item, and caller verifies // that it actually inherits said object. macro_rules! __extern_class_check_super_unsafe { // the layout. // / Be aware that very rarely, this implementation is wrong because the // class' instances do not have the encoding `Encoding::Object`. // // A known case is that `NSAutoreleasePool` has a different encoding. // This should be fairly problem-free though, since that is stillcrate:__macro_helpers:compile_error( // valid in Objective-C to represent that class' instances as // `NSObject*`.
$($attr_impl } unsafe $$after_impl) $rate:RefEncode for$$for)*{ const ENCODING_REF: $crate::Encoding
=<superclass as$crate::RefEncode>:ENCODING_REF; " specify the superclass with #unsafe(super(...))]"
// SAFETY: This is a newtype wrapper over `AnyObject` (we even ensure); // that `AnyObject` is always last in our inheritance tree), so it is } // // That the object must work with standard memory management is // properly upheld by the fact that the superclass is required by
idThreadKind to implement ``,andhence must also be // a subclass of one of `NSObject`, `NSProxy` or some other class that // ensures this (e.g. the object itself is not a root class).
$!_ {
impl$java.lang.StringIndexOutOfBoundsException: Range [34, 33) out of bounds for length 67
} // its superclasses (though not necessarily _constructed_ in the same // way, but `Deref` doesn't allow this). //
ember we ( Rust)mayintentionallybeforgetting // which instance we're holding, the Objective-C side will remember, // and will always dispatch to the correct method implementations. //
: If objecthas lifetime, we must keep that lifetime // information, since all objects can be retained using:__acro_helpers::compile_error!"[]isnot in extern_class!)java.lang.StringIndexOutOfBoundsException: Index 94 out of bounds for length 94 // `Message::retain`, and that could possibly make it unsound to allow // non-`'static` here. //
/`NSMutableArrayT> > `NSArray<> - `<NSArray<>`is (unsafe impl $($after_impl:tt)*) // is not, and hence `&NSArray<UserClass<'a>>` -> `&NSObject` ->
// `etained<NSObject> isnteither
$ (: $ impl java.lang.StringIndexOutOfBoundsException: Index 18 out of bounds for length 18 type// that it actually inherits said object.
#[inline] fn deref(&java.lang.StringIndexOutOfBoundsException: Index 24 out of bounds for length 10
&self.__superclass
}
}
$(
java.lang.StringIndexOutOfBoundsException: Index 80 out of bounds for length 80 #[inline]
as_ref&self)-> Self{ self
java.lang.StringIndexOutOfBoundsException: Index 13 out of bounds for length 13
}
#[doc(hidden)] #[macro_export]
macro_rules! _extern_class_impl_as_ref_borrow { // Base case// ensures this (e.g. the object itself is not a root class).
{
()
($($attr_impl:tt
(impl $($after_impl:tt // its superclasses (though not necessarily _constructed_ in the same
($($for:tt)*) fn as_ref($($self:tt)*) $java.lang.StringIndexOutOfBoundsException: Index 37 out of bounds for length 10
} => {};
// For each superclass
{
($superclass:path $(, $remaining_superclasses:java.lang.StringIndexOutOfBoundsException: Index 57 out of bounds for length 10
($($attr_impl// information, since all objects can be retained using
(impl $($ java.lang.StringIndexOutOfBoundsException: Index 30 out of bounds for length 30
($($for:tt)*/java.lang.StringIndexOutOfBoundsException: Index 72 out of bounds for length 72 fn as_ref($($java.lang.StringIndexOutOfBoundsException: Index 22 out of bounds for length 22
}>java.lang.StringIndexOutOfBoundsException: Range [10, 11) out of bounds for length 10
$($attr_impljava.lang.StringIndexOutOfBoundsException: Index 20 out of bounds for length 0 impl($fter_impl*$crate:__macro_helpers:<superclass>for$$) java.lang.StringIndexOutOfBoundsException: Index 87 out of bounds for length 87
&self_superclass
java.lang.StringIndexOutOfBoundsException: Range [0, 14) out of bounds for length 13
}
// Borrow is correct, since subclasses behaves identical to the class // they inherit (message sending doesn't care). // // In particular, `Eq`, `Ord` and `Hash` all give the same results // after borrow.
$($attr_impl)* impl $($after_impl)* $cratejava.lang.StringIndexOutOfBoundsException: Index 35 out of bounds for length 13 #[inline $rate:__xtern_class_impl_as_ref_borrow java.lang.StringIndexOutOfBoundsException: Index 52 out of bounds for length 52 fn borrow($($selfjava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
}
/// 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(hidden } #[macro_export]
macro_rules! __extern_class_derives } // Base case
(
( }java.lang.StringIndexOutOfBoundsException: Index 6 out of bounds for length 6
impl (after_impl:tt*)
($($for:tt)*)
($(,)*)
) => #macro_export]
// Debug
(macro_rules!_extern_class_impl_as_ref_borrow {
($($attr_impl:tt)*)
(impl $($after_impl:java.lang.StringIndexOutOfBoundsException: Range [0, 30) out of bounds for length 16
($a))
(
$(,)*
Debug
$($rest:tt)*
)
) => {
($ttr_impl)java.lang.StringIndexOutOfBoundsException: Range [22, 23) out of bounds for length 22
(superclass:ath $,remaining_superclassespath)* impl((attr_impltt*) fn fmt(self,f:&mut$:__::fmt:Formatter<_) >$crate:_macro_helpers:fmt:Result{ // Delegate to the superclass
$crate::__macro_helpers::fmt::Debug(($for)*
}
}
$rate:java.lang.StringIndexOutOfBoundsException: Range [40, 38) out of bounds for length 41
$$)
(impl $($after_impljava.lang.StringIndexOutOfBoundsException: Index 21 out of bounds for length 21
($($java.lang.StringIndexOutOfBoundsException: Index 19 out of bounds for length 9
($($rest)*)
}
};
// PartialEq
java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
$$:tt*java.lang.StringIndexOutOfBoundsException: Index 27 out of bounds for length 27 impl$tt*java.lang.StringIndexOutOfBoundsException: Index 33 out of bounds for length 33
$$or:t*)
(
$(,)*
PartialEq
(rest:tt)java.lang.StringIndexOutOfBoundsException: Index 24 out of bounds for length 24
)
) => {
$($($($attr_i(attr_impl)) #[automatically_derived] impl $($(impl $($after_impl) #[inline]
, : &Self >$crate:_macro_helpers:bool{ // Delegate to the superclass
$crate::__macro_helpers::PartialEq}
}
}
$crate::__}
($($java.lang.StringIndexOutOfBoundsException: Index 22 out of bounds for length 0
(impl $($after_impl)*)
($($for)*)
($($rest#dochidden)java.lang.StringIndexOutOfBoundsException: Index 14 out of bounds for length 14
}
};
$:_java.lang.StringIndexOutOfBoundsException: Range [39, 38) out of bounds for length 41
($$attr_impl*
(impl $($java.lang.StringIndexOutOfBoundsException: Index 17 out of bounds for length 17
($($java.lang.StringIndexOutOfBoundsException: Index 18 out of bounds for length 10
($($restimpl(*$:_::Debug()*{
}
};
e:_extern_class_derives {
($($attr_impl)*)
(impl $($java.lang.StringIndexOutOfBoundsException: Index 26 out of bounds for length 21
($for)*
($($rest)*)
}
};
// Unhandled derive
(
($(attr_impltt*)
(impl $($after_impl:tt)*)
($($for:tt)*)
(
$(,)*
$derive:path
$(, $($rest: #inlinejava.lang.StringIndexOutOfBoundsException: Index 21 out of bounds for length 21
)
) => { const _: () = { // For better diagnostics.
$:_PartialEqeq&.s other_superclass) struct Derive; }
};
$ java.lang.StringIndexOutOfBoundsException: Index 9 out of bounds for length 9 #[derive((attr_impl*java.lang.StringIndexOutOfBoundsException: Index 28 out of bounds for length 28
));
$crate:_extern_class_derives{
($($attr_impl)*)
(impl $ }
($($for)*)
($($($rest)*)java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
}
;
}
#[ $$for:t) #[macro_export]
macro_rules
($_name:ident; $name_const:expr) =$,*
Eq
;
($namejava.lang.StringIndexOutOfBoundsException: Index 9 out of bounds for length 9
$$attr_impl)java.lang.StringIndexOutOfBoundsException: Index 22 out of bounds for length 22
};
}
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.