Skip to content

Commit db8a236

Browse files
authored
Merge pull request #214 from madsmtm/extern-class-fields
Allow specifying fields in `extern_class!`
2 parents 88567d7 + f12c7be commit db8a236

File tree

2 files changed

+51
-45
lines changed

2 files changed

+51
-45
lines changed

objc2-foundation/src/declare_macro.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -638,6 +638,8 @@ macro_rules! __inner_declare_class {
638638
/// ```
639639
///
640640
/// [`extern_class!`]: crate::extern_class
641+
#[doc(alias = "@interface")]
642+
#[doc(alias = "@implementation")]
641643
#[macro_export]
642644
macro_rules! declare_class {
643645
{

objc2-foundation/src/macros.rs

Lines changed: 49 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,50 @@
11
/// Create a new type to represent an Objective-C class.
22
///
3-
/// The given name should correspond to a valid Objective-C class, whose
4-
/// instances have the encoding `Encoding::Object` (as an example:
5-
/// `NSAutoreleasePool` does not have this).
3+
/// This is similar to an `@interface` declaration in Objective-C.
4+
///
5+
/// The given struct name should correspond to a valid Objective-C class,
6+
/// whose instances have the encoding [`objc2::Encoding::Object`].
7+
/// (as an example: `NSAutoreleasePool` does not have this!)
8+
///
9+
/// You must specify the superclass of this class, similar to how you would
10+
/// in Objective-C. Due to Rust trait limitations, specifying e.g. the
11+
/// superclass `NSData` would not give you easy access to `NSObject`'s
12+
/// functionality, therefore you may specify additional parts of the
13+
/// inheritance chain.
614
///
715
///
816
/// # Specification
917
///
10-
/// This creates an opaque struct, and implements traits for it to allow
11-
/// easier usage as an Objective-C object.
18+
/// This creates an opaque struct containing the superclass (which means that
19+
/// auto traits are inherited from the superclass), and implements the
20+
/// following traits for it to allow easier usage as an Objective-C object:
1221
///
13-
/// The traits [`objc2::RefEncode`] and [`objc2::Message`] are implemented to
14-
/// allow sending messages to the object and using it in [`objc2::rc::Id`].
22+
/// - [`objc2::RefEncode`]
23+
/// - [`objc2::Message`]
24+
/// - [`Deref<Target = $superclass>`][core::ops::Deref]
25+
/// - [`DerefMut`][core::ops::DerefMut]
26+
/// - [`AsRef<$inheritance_chain>`][AsRef]
27+
/// - [`AsMut<$inheritance_chain>`][AsMut]
28+
/// - [`Borrow<$inheritance_chain>`][core::borrow::Borrow]
29+
/// - [`BorrowMut<$inheritance_chain>`][core::borrow::BorrowMut]
1530
///
1631
/// An associated function `class` is created on the object as a convenient
1732
/// shorthand so that you can do `MyObject::class()` instead of
1833
/// `class!(MyObject)`.
1934
///
20-
/// [`Deref`] and [`DerefMut`] are implemented and delegate to the first
21-
/// superclass (direct parent). Auto traits are inherited from this superclass
22-
/// as well (this macro effectively just creates a newtype wrapper around the
23-
/// superclass).
24-
///
25-
/// Finally, [`AsRef`], [`AsMut`], [`Borrow`] and [`BorrowMut`] are
26-
/// implemented to allow conversion to an arbitary superclasses in the
27-
/// inheritance chain (since an instance of a class can always be interpreted
28-
/// as its superclasses).
35+
/// The macro allows specifying fields on the struct, but _only_ zero-sized
36+
/// types like [`PhantomData`] and [`objc2::declare::Ivar`] are allowed here!
2937
///
30-
/// [`Deref`]: core::ops::Deref
31-
/// [`DerefMut`]: core::ops::DerefMut
32-
/// [`Borrow`]: core::borrow::Borrow
33-
/// [`BorrowMut`]: core::borrow::BorrowMut
38+
/// [`PhantomData`]: core::marker::PhantomData
3439
///
3540
///
3641
/// # Safety
3742
///
38-
/// The specified inheritance chain must be correct, including in the correct
39-
/// order, and the types in said chain must be valid as Objective-C objects
40-
/// (this is easy to ensure by also creating those using this macro).
43+
/// The specified superclass must be correct. The object must also respond to
44+
/// standard memory management messages (this is upheld if `NSObject` is part
45+
/// of its inheritance chain).
4146
///
42-
/// The object must respond to standard memory management messages (this is
43-
/// upheld if `NSObject` is part of its inheritance chain).
47+
/// Additionally, any fields (if specified) must be zero-sized.
4448
///
4549
///
4650
/// # Example
@@ -90,28 +94,28 @@
9094
/// ```
9195
///
9296
/// See the source code of `objc2_foundation` in general for more examples.
97+
#[doc(alias = "@interface")]
9398
#[macro_export]
9499
macro_rules! extern_class {
95100
(
96101
$(#[$m:meta])*
97-
unsafe $v:vis struct $name:ident: $($inheritance_chain:ty),+;
102+
unsafe $v:vis struct $name:ident: $superclass:ty $(, $inheritance_rest:ty)*;
98103
) => {
99-
$crate::__inner_extern_class! {
100-
@__inner
104+
$crate::extern_class! {
101105
$(#[$m])*
102-
unsafe $v struct $name<>: $($inheritance_chain,)+ $crate::objc2::runtime::Object {}
106+
unsafe $v struct $name: $superclass $(, $inheritance_rest)* {}
103107
}
104-
105-
impl $name {
106-
#[doc = concat!(
107-
"Get a reference to the Objective-C class `",
108-
stringify!($name),
109-
"`.",
110-
)]
111-
#[inline]
112-
// TODO: Allow users to configure this?
113-
$v fn class() -> &'static $crate::objc2::runtime::Class {
114-
$crate::objc2::class!($name)
108+
};
109+
(
110+
$(#[$m:meta])*
111+
unsafe $v:vis struct $name:ident: $superclass:ty $(, $inheritance_rest:ty)* {
112+
$($field_vis:vis $field:ident: $field_ty:ty,)*
113+
}
114+
) => {
115+
$crate::__inner_extern_class! {
116+
$(#[$m])*
117+
unsafe $v struct $name<>: $superclass $(, $inheritance_rest)* {
118+
$($field_vis $field: $field_ty,)*
115119
}
116120
}
117121
};
@@ -198,15 +202,15 @@ macro_rules! __inner_extern_class {
198202
(
199203
@__inner
200204
$(#[$m:meta])*
201-
unsafe $v:vis struct $name:ident<$($t:ident $(: $b:ident)?),*>: $inherits:ty $(, $inheritance_rest:ty)* {
205+
unsafe $v:vis struct $name:ident<$($t:ident $(: $b:ident)?),*>: $superclass:ty $(, $inheritance_rest:ty)* {
202206
$($p_v:vis $p:ident: $pty:ty,)*
203207
}
204208
) => {
205209
$(#[$m])*
206210
// TODO: repr(transparent) when the inner pointer is no longer a ZST.
207211
#[repr(C)]
208212
$v struct $name<$($t $(: $b)?),*> {
209-
__inner: $inherits,
213+
__inner: $superclass,
210214
// Additional fields (should only be zero-sized PhantomData or ivars).
211215
$($p_v $p: $pty),*
212216
}
@@ -219,7 +223,7 @@ macro_rules! __inner_extern_class {
219223
// the layout.
220224
unsafe impl<$($t $(: $b)?),*> $crate::objc2::RefEncode for $name<$($t),*> {
221225
const ENCODING_REF: $crate::objc2::Encoding<'static>
222-
= <$inherits as $crate::objc2::RefEncode>::ENCODING_REF;
226+
= <$superclass as $crate::objc2::RefEncode>::ENCODING_REF;
223227
}
224228

225229
// SAFETY: This is essentially just a newtype wrapper over `Object`
@@ -249,7 +253,7 @@ macro_rules! __inner_extern_class {
249253
// the same object, `x: &T` and `y: &T::Target`, and this would be
250254
// perfectly safe!
251255
impl<$($t $(: $b)?),*> $crate::__core::ops::Deref for $name<$($t),*> {
252-
type Target = $inherits;
256+
type Target = $superclass;
253257

254258
#[inline]
255259
fn deref(&self) -> &Self::Target {
@@ -289,7 +293,7 @@ macro_rules! __inner_extern_class {
289293
}
290294
}
291295

292-
$crate::__impl_as_ref_borrow!($name<$($t $(: $b)?),*>, $inherits, $($inheritance_rest,)*);
296+
$crate::__impl_as_ref_borrow!($name<$($t $(: $b)?),*>, $superclass, $($inheritance_rest,)*);
293297
};
294298
}
295299

0 commit comments

Comments
 (0)