Skip to content

Commit 05708e7

Browse files
committed
Expose and document object! macro
1 parent 103debe commit 05708e7

File tree

7 files changed

+140
-45
lines changed

7 files changed

+140
-45
lines changed

objc2-foundation/CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
1010
* Added `MainThreadMarker` to help with designing APIs where a method is only
1111
safe to call on the main thread.
1212
* Added `NSException` object.
13+
* Added `object!` macro to help with defining other classes.
14+
* Expose the `objc2` version that this uses in the crate root.
1315

1416
### Changed
1517
* Changed a few `Debug` impls.

objc2-foundation/src/array.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use super::{
1414
NSRange,
1515
};
1616

17-
object! {
17+
__inner_object! {
1818
/// TODO
1919
///
2020
/// You can have a `Id<NSArray<T, Owned>, Owned>`, which allows mutable access
@@ -43,7 +43,7 @@ unsafe impl<T: Sync + Send> Send for NSArray<T, Shared> {}
4343
unsafe impl<T: Sync> Sync for NSArray<T, Owned> {}
4444
unsafe impl<T: Send> Send for NSArray<T, Owned> {}
4545

46-
object! {
46+
__inner_object! {
4747
// TODO: Ensure that this deref to NSArray is safe!
4848
// This "inherits" NSArray, and has the same `Send`/`Sync` impls as that.
4949
#[derive(Debug, PartialEq, Eq, Hash)]

objc2-foundation/src/dictionary.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use objc2::{msg_send, msg_send_id, Message};
99

1010
use super::{NSArray, NSCopying, NSEnumerator, NSFastEnumeration, NSObject};
1111

12-
object! {
12+
__inner_object! {
1313
#[derive(Debug, PartialEq, Eq, Hash)]
1414
unsafe pub struct NSDictionary<K, V>: NSObject {
1515
key: PhantomData<Id<K, Shared>>,

objc2-foundation/src/lib.rs

+6
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,12 @@ pub use self::value::NSValue;
7171
#[doc(no_inline)]
7272
pub use objc2::ffi::{NSInteger, NSUInteger};
7373

74+
#[doc(hidden)]
75+
pub use core as __core;
76+
77+
// Expose the version of objc2 that this crate uses
78+
pub use objc2;
79+
7480
#[cfg(feature = "apple")]
7581
#[link(name = "Foundation", kind = "framework")]
7682
extern "C" {}

objc2-foundation/src/macros.rs

+127-40
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,116 @@
1+
/// Create a new type to represent an Objective-C class.
2+
///
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).
6+
///
7+
///
8+
/// # Specification
9+
///
10+
/// This creates an opaque struct, and implements traits for it to allow
11+
/// easier usage as an Objective-C object.
12+
///
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`].
15+
///
16+
/// [`Deref`] and [`DerefMut`] are implemented and delegate to the first
17+
/// superclass (direct parent). Auto traits are inherited from this superclass
18+
/// as well (this macro effectively just creates a newtype wrapper around the
19+
/// superclass).
20+
///
21+
/// Finally, [`AsRef`], [`AsMut`], [`Borrow`] and [`BorrowMut`] are
22+
/// implemented to allow conversion to an arbitary superclasses in the
23+
/// inheritance chain (since an instance of a class can always be interpreted
24+
/// as it's superclasses).
25+
///
26+
/// [`Deref`]: core::ops::Deref
27+
/// [`DerefMut`]: core::ops::DerefMut
28+
/// [`Borrow`]: core::borrow::Borrow
29+
/// [`BorrowMut`]: core::borrow::BorrowMut
30+
///
31+
///
32+
/// # Safety
33+
///
34+
/// The specified inheritance chain must be correct (including in the correct
35+
/// order), and the types in said chain must be valid as Objective-C objects -
36+
/// this is easiest to ensure by also creating those using this macro.
37+
///
38+
///
39+
/// # Example
40+
///
41+
/// Create a new type to represent the `NSFormatter` class.
42+
///
43+
/// ```
44+
/// use objc2::msg_send_id;
45+
/// use objc2::rc::{Id, Shared};
46+
/// use objc2_foundation::{object, NSObject};
47+
/// #
48+
/// # #[cfg(feature = "gnustep-1-7")]
49+
/// # unsafe { objc2::__gnustep_hack::get_class_to_force_linkage() };
50+
///
51+
/// object! {
52+
/// /// An example description.
53+
/// #[derive(PartialEq, Eq, Hash)] // Uses `NSObject`'s implementation
54+
/// // Specify class and superclass
55+
/// // In this case the class `NSFormatter`, which subclasses `NSObject`
56+
/// unsafe pub struct NSFormatter: NSObject;
57+
/// }
58+
///
59+
/// // Provided by the macro
60+
/// let cls = NSFormatter::class();
61+
///
62+
/// // `NSFormatter` implements `Message`:
63+
/// let obj: Id<NSFormatter, Shared> = unsafe { msg_send_id![cls, new].unwrap() };
64+
/// ```
65+
///
66+
/// Represent the `NSDateFormatter` class, using the `NSFormatter` type we
67+
/// declared previously to specify as its superclass.
68+
///
69+
/// ```
70+
/// use objc2_foundation::{object, NSObject};
71+
/// #
72+
/// # object! {
73+
/// # #[derive(PartialEq, Eq, Hash)]
74+
/// # unsafe pub struct NSFormatter: NSObject;
75+
/// # }
76+
///
77+
/// object! {
78+
/// #[derive(PartialEq, Eq, Hash)]
79+
/// // Specify the correct inheritance chain
80+
/// // `NSDateFormatter` subclasses `NSFormatter` which subclasses `NSObject`
81+
/// unsafe pub struct NSDateFormatter: NSFormatter, NSObject;
82+
/// }
83+
/// ```
84+
///
85+
/// See the source code of `objc2_foundation` in general for more examples.
86+
#[macro_export]
87+
macro_rules! object {
88+
(
89+
$(#[$m:meta])*
90+
unsafe $v:vis struct $name:ident: $($inheritance_chain:ty),+;
91+
) => {
92+
$crate::__inner_object! {
93+
@__inner
94+
$(#[$m])*
95+
unsafe $v struct $name<>: $($inheritance_chain,)+ $crate::objc2::runtime::Object {}
96+
}
97+
};
98+
}
99+
100+
#[doc(hidden)]
101+
#[macro_export]
1102
macro_rules! __impl_as_ref_borrow {
2103
($name:ident<$($t:ident $(: $b:ident)?),*>,) => {};
3104
($name:ident<$($t:ident $(: $b:ident)?),*>, $item:ty, $($tail:ty,)*) => {
4-
impl<$($t $(: $b)?),*> AsRef<$item> for $name<$($t),*> {
105+
impl<$($t $(: $b)?),*> $crate::__core::convert::AsRef<$item> for $name<$($t),*> {
5106
#[inline]
6107
fn as_ref(&self) -> &$item {
7108
// Triggers Deref coercion depending on return type
8109
&*self
9110
}
10111
}
11112

12-
impl<$($t $(: $b)?),*> AsMut<$item> for $name<$($t),*> {
113+
impl<$($t $(: $b)?),*> $crate::__core::convert::AsMut<$item> for $name<$($t),*> {
13114
#[inline]
14115
fn as_mut(&mut self) -> &mut $item {
15116
// Triggers DerefMut coercion depending on return type
@@ -23,55 +124,40 @@ macro_rules! __impl_as_ref_borrow {
23124
// In particular, `Eq`, `Ord` and `Hash` all give the same results
24125
// after borrow.
25126

26-
impl<$($t $(: $b)?),*> ::core::borrow::Borrow<$item> for $name<$($t),*> {
127+
impl<$($t $(: $b)?),*> $crate::__core::borrow::Borrow<$item> for $name<$($t),*> {
27128
#[inline]
28129
fn borrow(&self) -> &$item {
29130
// Triggers Deref coercion depending on return type
30131
&*self
31132
}
32133
}
33134

34-
impl<$($t $(: $b)?),*> ::core::borrow::BorrowMut<$item> for $name<$($t),*> {
135+
impl<$($t $(: $b)?),*> $crate::__core::borrow::BorrowMut<$item> for $name<$($t),*> {
35136
#[inline]
36137
fn borrow_mut(&mut self) -> &mut $item {
37138
// Triggers Deref coercion depending on return type
38139
&mut *self
39140
}
40141
}
41142

42-
__impl_as_ref_borrow!($name<$($t $(: $b)?),*>, $($tail,)*);
143+
$crate::__impl_as_ref_borrow!($name<$($t $(: $b)?),*>, $($tail,)*);
43144
};
44145
}
45146

46-
/// TODO
47-
///
48-
/// # Safety
49-
///
50-
/// The given name must be a valid Objective-C class that inherits NSObject
51-
/// and it's instances must have the raw encoding `Encoding::Object` (an
52-
/// example: `NSAutoreleasePool` does not have this). Finally the ownership
53-
/// must be correct for this class.
54-
macro_rules! object {
55-
(
56-
$(#[$m:meta])*
57-
unsafe $v:vis struct $name:ident: $($inheritance_chain:ty),+ $(;)?
58-
) => {
59-
object! {
60-
@__inner
61-
$(#[$m])*
62-
unsafe $v struct $name<>: $($inheritance_chain,)+ ::objc2::runtime::Object {}
63-
}
64-
};
147+
#[doc(hidden)]
148+
#[macro_export]
149+
macro_rules! __inner_object {
150+
// TODO: Expose this variant in the `object` macro.
65151
(
66152
$(#[$m:meta])*
67153
unsafe $v:vis struct $name:ident<$($t:ident $(: $b:ident)?),*>: $($inheritance_chain:ty),+ {
68154
$($p:ident: $pty:ty,)*
69155
}
70156
) => {
71-
object! {
157+
$crate::__inner_object! {
72158
@__inner
73159
$(#[$m])*
74-
unsafe $v struct $name<$($t $(: $b)?),*>: $($inheritance_chain,)+ ::objc2::runtime::Object {
160+
unsafe $v struct $name<$($t $(: $b)?),*>: $($inheritance_chain,)+ $crate::objc2::runtime::Object {
75161
$($p: $pty,)*
76162
}
77163
}
@@ -87,20 +173,21 @@ macro_rules! object {
87173
// TODO: repr(transparent) when the inner pointer is no longer a ZST.
88174
#[repr(C)]
89175
$v struct $name<$($t $(: $b)?),*> {
90-
inner: $inherits,
176+
__inner: $inherits,
91177
// Additional fields (should only be zero-sized PhantomData).
92178
$($p: $pty),*
93179
}
94180

95-
unsafe impl<$($t $(: $b)?),*> ::objc2::Message for $name<$($t),*> { }
181+
unsafe impl<$($t $(: $b)?),*> $crate::objc2::Message for $name<$($t),*> { }
96182

97-
unsafe impl<$($t $(: $b)?),*> ::objc2::RefEncode for $name<$($t),*> {
98-
const ENCODING_REF: ::objc2::Encoding<'static> = ::objc2::Encoding::Object;
183+
unsafe impl<$($t $(: $b)?),*> $crate::objc2::RefEncode for $name<$($t),*> {
184+
const ENCODING_REF: $crate::objc2::Encoding<'static>
185+
= <$inherits as $crate::objc2::RefEncode>::ENCODING_REF;
99186
}
100187

101188
impl<$($t $(: $b)?),*> $name<$($t),*> {
102-
$v fn class() -> &'static ::objc2::runtime::Class {
103-
::objc2::class!($name)
189+
$v fn class() -> &'static $crate::objc2::runtime::Class {
190+
$crate::objc2::class!($name)
104191
}
105192
}
106193

@@ -122,12 +209,12 @@ macro_rules! object {
122209
// Note that you can easily have two different variables pointing to
123210
// the same object, `x: &T` and `y: &T::Target`, and this would be
124211
// perfectly safe!
125-
impl<$($t $(: $b)?),*> ::core::ops::Deref for $name<$($t),*> {
212+
impl<$($t $(: $b)?),*> $crate::__core::ops::Deref for $name<$($t),*> {
126213
type Target = $inherits;
127214

128215
#[inline]
129216
fn deref(&self) -> &Self::Target {
130-
&self.inner
217+
&self.__inner
131218
}
132219
}
133220

@@ -142,28 +229,28 @@ macro_rules! object {
142229
// But `&mut NSMutableString` -> `&mut NSString` safe, since the
143230
// `NSCopying` implementation of `NSMutableString` is used, and that
144231
// is guaranteed to return a different object.
145-
impl<$($t $(: $b)?),*> ::core::ops::DerefMut for $name<$($t),*> {
232+
impl<$($t $(: $b)?),*> $crate::__core::ops::DerefMut for $name<$($t),*> {
146233
#[inline]
147234
fn deref_mut(&mut self) -> &mut Self::Target {
148-
&mut self.inner
235+
&mut self.__inner
149236
}
150237
}
151238

152-
impl<$($t $(: $b)?),*> AsRef<Self> for $name<$($t),*> {
239+
impl<$($t $(: $b)?),*> $crate::__core::convert::AsRef<Self> for $name<$($t),*> {
153240
#[inline]
154241
fn as_ref(&self) -> &Self {
155242
self
156243
}
157244
}
158245

159-
impl<$($t $(: $b)?),*> AsMut<Self> for $name<$($t),*> {
246+
impl<$($t $(: $b)?),*> $crate::__core::convert::AsMut<Self> for $name<$($t),*> {
160247
#[inline]
161248
fn as_mut(&mut self) -> &mut Self {
162249
self
163250
}
164251
}
165252

166-
__impl_as_ref_borrow!($name<$($t $(: $b)?),*>, $inherits, $($inheritance_rest,)*);
253+
$crate::__impl_as_ref_borrow!($name<$($t $(: $b)?),*>, $inherits, $($inheritance_rest,)*);
167254
};
168255
}
169256

@@ -175,7 +262,7 @@ macro_rules! unsafe_def_fn {
175262
$(#[$m])*
176263
$v fn new() -> Id<Self, $o> {
177264
let cls = Self::class();
178-
unsafe { ::objc2::msg_send_id![cls, new].unwrap() }
265+
unsafe { $crate::objc2::msg_send_id![cls, new].unwrap() }
179266
}
180267
};
181268
}

objc2-foundation/src/object.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use objc2::{msg_send, msg_send_bool, msg_send_id};
77

88
use super::NSString;
99

10-
object! {
10+
__inner_object! {
1111
@__inner
1212
unsafe pub struct NSObject<>: Object {}
1313
}

objc2-foundation/src/value.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use objc2::{msg_send, msg_send_id};
1414

1515
use super::{NSCopying, NSObject};
1616

17-
object! {
17+
__inner_object! {
1818
// `T: Eq` bound correct to prevent `NSValue<f32>` from being `Eq`
1919
// (even though `[NAN isEqual: NAN]` is true in Objective-C).
2020
#[derive(Debug, PartialEq, Eq, Hash)]

0 commit comments

Comments
 (0)