Skip to content

Commit b97bcbb

Browse files
authored
Merge pull request #234 from madsmtm/class-type
Add `ClassType` trait
2 parents 6f68cd0 + 577af32 commit b97bcbb

35 files changed

Lines changed: 255 additions & 103 deletions

objc2/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,15 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
1515
* Added `declare_class!`, `extern_class!` and `ns_string!` macros from
1616
`objc2-foundation`.
1717
* Added helper method `ClassBuilder::add_static_ivar`.
18+
* **BREAKING**: Added `ClassType` trait, and moved the associated `class`
19+
methods that `extern_class!` and `declare_class!` generated to that. This
20+
means you'll have to `use objc2::ClassType` whenever you want to use e.g.
21+
`NSData::class()`.
22+
* Added `Id::into_superclass`.
1823

1924
### Changed
2025
* **BREAKING**: Change selector syntax in `declare_class!` macro to be more Rust-like.
26+
* **BREAKING**: Renamed `Id::from_owned` to `Id::into_shared`.
2127

2228

2329
## 0.3.0-beta.1 - 2022-07-19

objc2/CHANGELOG_FOUNDATION.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
3030
type-safety from this, it makes `NSValue` much more useful in the real
3131
world!
3232
* **BREAKING**: Made `NSArray::new` generic over ownership.
33+
* **BREAKING**: Made `NSObject::is_kind_of` take a generic `T: ClassType`
34+
instead of a `runtime::Class`.
3335

3436
### Fixed
3537
* Made `Debug` impls for all objects print something useful.

objc2/examples/class_with_lifetime.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use objc2::foundation::NSObject;
1212
use objc2::rc::{Id, Owned};
1313
use objc2::runtime::{Class, Object, Sel};
1414
use objc2::{msg_send, msg_send_id, sel};
15-
use objc2::{Encoding, Message, RefEncode};
15+
use objc2::{ClassType, Encoding, Message, RefEncode};
1616

1717
/// Helper type for the instance variable
1818
struct NumberIvar<'a> {
@@ -62,8 +62,12 @@ impl<'a> MyObject<'a> {
6262
pub fn set(&mut self, number: u8) {
6363
**self.number = number;
6464
}
65+
}
66+
67+
unsafe impl<'a> ClassType for MyObject<'a> {
68+
type Superclass = NSObject;
6569

66-
pub fn class() -> &'static Class {
70+
fn class() -> &'static Class {
6771
// TODO: Use std::lazy::LazyCell
6872
static REGISTER_CLASS: Once = Once::new();
6973

@@ -119,14 +123,18 @@ fn main() {
119123
let mut number = 54;
120124
let mut obj = MyObject::new(&mut number);
121125

126+
// It is not possible to convert to `Id<NSObject, Owned>` since that would
127+
// loose the lifetime information that `MyObject` stores
128+
// let obj = Id::into_superclass(obj);
129+
122130
println!("Number: {}", obj.get());
123131

124132
obj.set(7);
125133
// Won't compile, since `obj` holds a mutable reference to number
126134
// println!("Number: {}", number);
127135
println!("Number: {}", obj.get());
128136

129-
let obj = Id::from_owned(obj);
137+
let obj = Id::into_shared(obj);
130138
let obj2 = obj.clone();
131139

132140
// We gave up ownership above, so can't edit the number any more!

objc2/examples/delegate.rs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
1-
#[cfg(all(feature = "apple", target_os = "macos"))]
2-
use objc2::{
3-
declare_class, extern_class,
4-
foundation::NSObject,
5-
msg_send, msg_send_id,
6-
rc::{Id, Shared},
7-
runtime::{Bool, Object},
8-
};
1+
#![cfg_attr(not(all(feature = "apple", target_os = "macos")), allow(unused))]
2+
use objc2::foundation::NSObject;
3+
use objc2::rc::{Id, Shared};
4+
use objc2::runtime::{Bool, Object};
5+
use objc2::{declare_class, extern_class, msg_send, msg_send_id, ClassType};
96

107
#[cfg(all(feature = "apple", target_os = "macos"))]
118
#[link(name = "AppKit", kind = "framework")]

objc2/examples/introspection.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use objc2::foundation::NSObject;
22
use objc2::runtime::Class;
3-
use objc2::sel;
4-
use objc2::Encode;
3+
use objc2::{sel, ClassType, Encode};
54

65
fn main() {
76
// Get the class representing `NSObject`

objc2/examples/nspasteboard.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use std::mem::ManuallyDrop;
99
use objc2::foundation::{NSArray, NSDictionary, NSInteger, NSObject, NSString};
1010
use objc2::rc::{Id, Shared};
1111
use objc2::runtime::{Class, Object};
12-
use objc2::{extern_class, msg_send, msg_send_bool, msg_send_id};
12+
use objc2::{extern_class, msg_send, msg_send_bool, msg_send_id, ClassType};
1313

1414
type NSPasteboardType = NSString;
1515
type NSPasteboardReadingOptionKey = NSString;

objc2/examples/speech_synthethis.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use std::time::Duration;
1515

1616
use objc2::foundation::{NSObject, NSString};
1717
use objc2::rc::{Id, Owned};
18-
use objc2::{extern_class, msg_send, msg_send_bool, msg_send_id, ns_string};
18+
use objc2::{extern_class, msg_send, msg_send_bool, msg_send_id, ns_string, ClassType};
1919

2020
#[cfg(all(feature = "apple", target_os = "macos"))]
2121
mod appkit {

objc2/src/__macro_helpers.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ mod tests {
255255
use crate::foundation::NSZone;
256256
use crate::rc::{Allocated, Owned, RcTestObject, Shared, ThreadTestData};
257257
use crate::runtime::Object;
258+
use crate::ClassType;
258259
use crate::{class, msg_send_id};
259260

260261
#[test]

objc2/src/class_type.rs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
use crate::runtime::Class;
2+
use crate::Message;
3+
4+
/// Marks types that represent specific classes.
5+
///
6+
/// Usually it is enough to generically know that a type is messageable, e.g.
7+
/// [`rc::Id`][crate::rc::Id] works with any type that implements the
8+
/// [`Message`] trait. But often, you have an object that you know represents
9+
/// a specific Objective-C class - this trait allows you to communicate that
10+
/// to the rest of the type-system.
11+
///
12+
/// This is implemented automatically by the
13+
/// [`declare_class!`][crate::declare_class] and
14+
/// [`extern_class!`][crate::extern_class] macros.
15+
///
16+
///
17+
/// # Safety
18+
///
19+
/// The class returned by [`Self::class`] must be a subclass of the class that
20+
/// [`Self::Superclass`] represents.
21+
///
22+
/// In pseudocode:
23+
/// ```ignore
24+
/// Self::class().superclass() == <Self::Superclass as ClassType>::class()
25+
/// ```
26+
///
27+
///
28+
/// # Examples
29+
///
30+
/// Use the trait to access the [`Class`] of different objects.
31+
///
32+
/// ```
33+
/// # #[cfg(feature = "gnustep-1-7")]
34+
/// # unsafe { objc2::__gnustep_hack::get_class_to_force_linkage() };
35+
/// use objc2::ClassType;
36+
/// use objc2::foundation::NSObject;
37+
/// // Get a class object representing `NSObject`
38+
/// let cls = <NSObject as ClassType>::class(); // Or just `NSObject::class()`
39+
/// ```
40+
///
41+
/// Use the [`extern_class!`][crate::extern_class] macro to implement this
42+
/// trait for a type.
43+
///
44+
/// ```ignore
45+
/// use objc2::{extern_class, ClassType};
46+
///
47+
/// extern_class! {
48+
/// unsafe struct MyClass: NSObject;
49+
/// }
50+
///
51+
/// let cls = MyClass::class();
52+
/// ```
53+
pub unsafe trait ClassType: Message {
54+
/// The superclass of this class.
55+
///
56+
/// If you have implemented [`Deref`] for your type, it is highly
57+
/// recommended that this is equal to [`Deref::Target`].
58+
///
59+
/// This may be [`runtime::Object`] if the class is a root class.
60+
///
61+
/// [`Deref`]: std::ops::Deref
62+
/// [`Deref::Target`]: std::ops::Deref::Target
63+
/// [`runtime::Object`]: crate::runtime::Object
64+
type Superclass: Message;
65+
66+
/// Get a reference to the Objective-C class that this type represents.
67+
///
68+
/// May register the class with the runtime if it wasn't already.
69+
///
70+
///
71+
/// # Panics
72+
///
73+
/// This may panic if something went wrong with getting or declaring the
74+
/// class, e.g. if the program is not properly linked to the framework
75+
/// that defines the class.
76+
fn class() -> &'static Class;
77+
}

objc2/src/declare.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@
1515
//! methods and methods for interfacing with the number.
1616
//!
1717
//! ```
18-
//! use objc2::{class, sel, msg_send, msg_send_id};
1918
//! use objc2::declare::ClassBuilder;
2019
//! use objc2::foundation::NSObject;
2120
//! use objc2::rc::{Id, Owned};
2221
//! use objc2::runtime::{Class, Object, Sel};
22+
//! use objc2::{class, sel, msg_send, msg_send_id, ClassType};
2323
//! # #[cfg(feature = "gnustep-1-7")]
2424
//! # unsafe { objc2::__gnustep_hack::get_class_to_force_linkage() };
2525
//!

0 commit comments

Comments
 (0)