Skip to content

Commit cf8b146

Browse files
committed
Refactor core traits Message, ClassType and ProtocolType
1 parent 65b1285 commit cf8b146

File tree

12 files changed

+265
-266
lines changed

12 files changed

+265
-266
lines changed

crates/objc2/src/lib.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -188,11 +188,10 @@ extern "C" {}
188188
#[doc(no_inline)]
189189
pub use objc_sys as ffi;
190190

191-
pub use self::class_type::ClassType;
192191
#[doc(no_inline)]
193192
pub use self::encode::{Encode, Encoding, RefEncode};
194-
pub use self::message::{Message, MessageArguments, MessageReceiver};
195-
pub use self::protocol_type::ProtocolType;
193+
pub use self::message::{MessageArguments, MessageReceiver};
194+
pub use self::top_level_traits::{ClassType, Message, ProtocolType};
196195

197196
#[cfg(feature = "objc2-proc-macros")]
198197
#[doc(hidden)]
@@ -210,18 +209,17 @@ macro_rules! __hash_idents {
210209

211210
#[doc(hidden)]
212211
pub mod __macro_helpers;
213-
mod class_type;
214212
pub mod declare;
215213
pub mod encode;
216214
pub mod exception;
217215
mod macros;
218216
mod message;
219217
pub mod mutability;
220-
mod protocol_type;
221218
pub mod rc;
222219
pub mod runtime;
223220
#[cfg(test)]
224221
mod test_utils;
222+
mod top_level_traits;
225223
mod verify;
226224

227225
// Link to Foundation to make NSObject work

crates/objc2/src/message.rs

Lines changed: 2 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ use core::mem::{self, ManuallyDrop};
22
use core::ptr::{self, NonNull};
33

44
use crate::__macro_helpers::{ConvertArgument, ConvertReturn};
5-
use crate::encode::{Encode, EncodeArgument, EncodeReturn, Encoding, RefEncode};
5+
use crate::encode::{Encode, EncodeArgument, EncodeReturn, Encoding};
66
use crate::mutability::IsMutable;
77
use crate::rc::Id;
88
use crate::runtime::{AnyClass, AnyObject, Imp, Sel};
9-
use crate::ClassType;
9+
use crate::{ClassType, Message};
1010

1111
/// Wrap the given closure in `exception::catch` if the `catch-all` feature is
1212
/// enabled.
@@ -313,79 +313,6 @@ fn panic_verify(cls: &AnyClass, sel: Sel, err: &crate::runtime::VerificationErro
313313
)
314314
}
315315

316-
/// Types that can be sent Objective-C messages.
317-
///
318-
/// Implementing this provides [`MessageReceiver`] implementations for common
319-
/// pointer types and references to the type, which allows using them as the
320-
/// receiver (first argument) in the [`msg_send!`][`crate::msg_send`] macro.
321-
///
322-
/// This trait also allows the object to be used in [`rc::Id`][`Id`].
323-
///
324-
/// This is a subtrait of [`RefEncode`], meaning the type must also implement
325-
/// that, almost always with [`RefEncode::ENCODING_REF`] being
326-
/// [`Encoding::Object`].
327-
///
328-
/// This can be implemented for unsized (`!Sized`) types, but the intention is
329-
/// not to support dynamically sized types like slices, only `extern type`s
330-
/// (which is currently unstable).
331-
///
332-
/// [`Encoding::Object`]: crate::Encoding::Object
333-
///
334-
///
335-
/// # `Drop` interaction
336-
///
337-
/// If the inner type implements [`Drop`], that implementation will very
338-
/// likely not be called, since there is no way to ensure that the Objective-C
339-
/// runtime will do so. If you need to run some code when the object is
340-
/// destroyed, implement the `dealloc` method instead.
341-
///
342-
/// The [`declare_class!`] macro does this for you, but the [`extern_class!`]
343-
/// macro fundamentally cannot.
344-
///
345-
/// [`declare_class!`]: crate::declare_class
346-
/// [`extern_class!`]: crate::extern_class
347-
///
348-
///
349-
/// # Safety
350-
///
351-
/// The type must represent an Objective-C object, meaning it:
352-
/// - Must be valid to reinterpret as [`runtime::AnyObject`][`AnyObject`].
353-
/// - Must be able to be the receiver of an Objective-C message sent with
354-
/// [`objc_msgSend`] or similar.
355-
/// - Must respond to the standard memory management `retain`, `release` and
356-
/// `autorelease` messages.
357-
/// - Must support weak references. (In the future we should probably make a
358-
/// new trait for this, for example `NSTextView` only supports weak
359-
/// references on macOS 10.12 or above).
360-
///
361-
/// [`objc_msgSend`]: https://developer.apple.com/documentation/objectivec/1456712-objc_msgsend
362-
///
363-
///
364-
/// # Example
365-
///
366-
/// ```
367-
/// use objc2::runtime::NSObject;
368-
/// use objc2::{Encoding, Message, RefEncode};
369-
///
370-
/// #[repr(C)]
371-
/// struct MyObject {
372-
/// // This has the exact same layout as `NSObject`
373-
/// inner: NSObject
374-
/// }
375-
///
376-
/// unsafe impl RefEncode for MyObject {
377-
/// const ENCODING_REF: Encoding = Encoding::Object;
378-
/// }
379-
///
380-
/// unsafe impl Message for MyObject {}
381-
///
382-
/// // `*mut MyObject` and other pointer/reference types to the object can
383-
/// // now be used in `msg_send!`
384-
/// //
385-
/// // And `Id<MyObject>` can now be constructed.
386-
/// ```
387-
pub unsafe trait Message: RefEncode {}
388-
389316
// TODO: Make this fully private
390317
pub(crate) mod private {
391318
pub trait Sealed {}

crates/objc2/src/protocol_type.rs

Lines changed: 0 additions & 71 deletions
This file was deleted.

crates/objc2/src/class_type.rs renamed to crates/objc2/src/top_level_traits.rs

Lines changed: 147 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,83 @@
1+
use crate::encode::RefEncode;
12
use crate::msg_send_id;
23
use crate::mutability::{IsAllocableAnyThread, IsRetainable, Mutability};
34
use crate::rc::{Allocated, Id};
4-
use crate::runtime::AnyClass;
5-
use crate::Message;
5+
use crate::runtime::{AnyClass, AnyProtocol};
6+
7+
/// Types that can be sent Objective-C messages.
8+
///
9+
/// Implementing this provides [`MessageReceiver`] implementations for common
10+
/// pointer types and references to the type, which allows using them as the
11+
/// receiver (first argument) in the [`msg_send!`][`crate::msg_send`] macro.
12+
///
13+
/// This trait also allows the object to be used in [`rc::Id`][`Id`].
14+
///
15+
/// This is a subtrait of [`RefEncode`], meaning the type must also implement
16+
/// that, almost always with [`RefEncode::ENCODING_REF`] being
17+
/// [`Encoding::Object`].
18+
///
19+
/// This can be implemented for unsized (`!Sized`) types, but the intention is
20+
/// not to support dynamically sized types like slices, only `extern type`s
21+
/// (which is currently unstable).
22+
///
23+
/// [`MessageReceiver`]: crate::MessageReceiver
24+
/// [`Encoding::Object`]: crate::Encoding::Object
25+
///
26+
///
27+
/// # `Drop` interaction
28+
///
29+
/// If the inner type implements [`Drop`], that implementation will very
30+
/// likely not be called, since there is no way to ensure that the Objective-C
31+
/// runtime will do so. If you need to run some code when the object is
32+
/// destroyed, implement the `dealloc` method instead.
33+
///
34+
/// The [`declare_class!`] macro does this for you, but the [`extern_class!`]
35+
/// macro fundamentally cannot.
36+
///
37+
/// [`declare_class!`]: crate::declare_class
38+
/// [`extern_class!`]: crate::extern_class
39+
///
40+
///
41+
/// # Safety
42+
///
43+
/// The type must represent an Objective-C object, meaning it:
44+
/// - Must be valid to reinterpret as [`AnyObject`].
45+
/// - Must be able to be the receiver of an Objective-C message sent with
46+
/// [`objc_msgSend`] or similar.
47+
/// - Must respond to the standard memory management `retain`, `release` and
48+
/// `autorelease` messages.
49+
/// - Must support weak references. (In the future we should probably make a
50+
/// new trait for this, for example `NSTextView` only supports weak
51+
/// references on macOS 10.12 or above).
52+
///
53+
/// [`AnyObject`]: crate::runtime::AnyObject
54+
/// [`objc_msgSend`]: https://developer.apple.com/documentation/objectivec/1456712-objc_msgsend
55+
///
56+
///
57+
/// # Example
58+
///
59+
/// ```
60+
/// use objc2::runtime::NSObject;
61+
/// use objc2::{Encoding, Message, RefEncode};
62+
///
63+
/// #[repr(C)]
64+
/// struct MyObject {
65+
/// // This has the exact same layout as `NSObject`
66+
/// inner: NSObject
67+
/// }
68+
///
69+
/// unsafe impl RefEncode for MyObject {
70+
/// const ENCODING_REF: Encoding = Encoding::Object;
71+
/// }
72+
///
73+
/// unsafe impl Message for MyObject {}
74+
///
75+
/// // `*mut MyObject` and other pointer/reference types to the object can
76+
/// // now be used in `msg_send!`
77+
/// //
78+
/// // And `Id<MyObject>` can now be constructed.
79+
/// ```
80+
pub unsafe trait Message: RefEncode {}
681

782
/// Marks types that represent specific classes.
883
///
@@ -231,3 +306,73 @@ pub unsafe trait ClassType: Message {
231306
// TODO: `fn alloc_on_main(mtm: MainThreadMarker)`
232307
// TODO: `fn mtm(&self) -> MainThreadMarker where T::Mutability: MainThreadOnly`
233308
}
309+
310+
/// Marks types that represent specific protocols.
311+
///
312+
/// This is the protocol equivalent of [`ClassType`].
313+
///
314+
/// This is implemented automatically by the [`extern_protocol!`] macro for
315+
/// `dyn T`, where `T` is the protocol.
316+
///
317+
/// [`ClassType`]: crate::ClassType
318+
/// [`extern_protocol!`]: crate::extern_protocol
319+
///
320+
///
321+
/// # Safety
322+
///
323+
/// This is meant to be a sealed trait, and should not be implemented outside
324+
/// of the [`extern_protocol!`] macro.
325+
///
326+
///
327+
/// # Examples
328+
///
329+
/// Use the trait to access the [`AnyProtocol`] of different objects.
330+
///
331+
/// ```
332+
/// use objc2::ProtocolType;
333+
/// use objc2::runtime::NSObjectProtocol;
334+
/// // Get a protocol object representing the `NSObject` protocol
335+
/// let protocol = <dyn NSObjectProtocol>::protocol().expect("NSObject to have a protocol");
336+
/// assert_eq!(<dyn NSObjectProtocol>::NAME, protocol.name());
337+
/// ```
338+
///
339+
/// Use the [`extern_protocol!`] macro to implement this trait for a type.
340+
///
341+
/// ```no_run
342+
/// use objc2::{extern_protocol, ProtocolType};
343+
///
344+
/// extern_protocol!(
345+
/// unsafe trait MyProtocol {}
346+
/// unsafe impl ProtocolType for dyn MyProtocol {}
347+
/// );
348+
///
349+
/// let protocol = <dyn MyProtocol>::protocol();
350+
/// ```
351+
pub unsafe trait ProtocolType {
352+
/// The name of the Objective-C protocol that this type represents.
353+
const NAME: &'static str;
354+
355+
/// Get a reference to the Objective-C protocol object that this type
356+
/// represents.
357+
///
358+
/// May register the protocol with the runtime if it wasn't already.
359+
///
360+
/// Note that some protocols [are not registered with the runtime][p-obj],
361+
/// depending on various factors. In those cases, this function may return
362+
/// `None`.
363+
///
364+
/// [p-obj]: https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocProtocols.html#//apple_ref/doc/uid/TP30001163-CH15-TPXREF149
365+
///
366+
///
367+
/// # Panics
368+
///
369+
/// This may panic if something went wrong with getting or declaring the
370+
/// protocol, e.g. if the program is not properly linked to the framework
371+
/// that defines the protocol.
372+
fn protocol() -> Option<&'static AnyProtocol> {
373+
AnyProtocol::get(Self::NAME)
374+
}
375+
376+
#[doc(hidden)]
377+
const __INNER: ();
378+
}

0 commit comments

Comments
 (0)