|
| 1 | +use crate::encode::RefEncode; |
1 | 2 | use crate::msg_send_id;
|
2 | 3 | use crate::mutability::{IsAllocableAnyThread, IsRetainable, Mutability};
|
3 | 4 | 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 {} |
6 | 81 |
|
7 | 82 | /// Marks types that represent specific classes.
|
8 | 83 | ///
|
@@ -231,3 +306,73 @@ pub unsafe trait ClassType: Message {
|
231 | 306 | // TODO: `fn alloc_on_main(mtm: MainThreadMarker)`
|
232 | 307 | // TODO: `fn mtm(&self) -> MainThreadMarker where T::Mutability: MainThreadOnly`
|
233 | 308 | }
|
| 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