Skip to content

Commit

Permalink
Somewhat document extern_protocol!
Browse files Browse the repository at this point in the history
  • Loading branch information
madsmtm committed Nov 16, 2022
1 parent 0e67c70 commit 5c26a71
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 3 deletions.
70 changes: 68 additions & 2 deletions crates/objc2/src/macros/extern_protocol.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,67 @@
/// TODO
/// Create a new type to represent an Objective-C protocol.
///
/// This is similar to a `@protocol` declaration in Objective-C.
///
/// See [Protocols - The Objective-C Programming Language][protocols] and
/// [Working with Protocols - Programming with Objective-C][working-with] for
/// general information about protocols in Objective-C.
///
/// [protocols]: https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocProtocols.html
/// [working-with]: https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/WorkingwithProtocols/WorkingwithProtocols.html
///
///
/// # Tradeoffs
///
/// It should come as no surprise that Objective-C and Rust are not the same
/// language! This is in particular very prominent in the way that we map
/// protocols to Rust; one could choose to map them as traits, which has some
/// upsides, but also prevents using them as objects.
///
/// If we could customize how `dyn Trait` works in Rust, then it may have been
/// beneficial to map them as traits, but as the sitation stands, we choose
/// to map them as structs that implement [`Message`], similar to how we map
/// classes. This means that you can use protocols inside [`rc::Id`], which is
/// very important for a lot of use-cases.
///
/// If you have ideas for how to improve this situation, please help us out in
/// [#291]!
///
/// [`Message`]: crate::Message
/// [`rc::Id`]: crate::rc::Id
/// [#291]: https://github.com/madsmtm/objc2/issues/291
///
///
/// # Specification
///
/// This macro shares many similarities with [`extern_class!`] and
/// [`extern_methods!`], if you are familiar with those, it should be fairly
/// straightforward to use.
///
/// It differs in a few aspects though:
/// - You can use the `#[optional]` attribute to mark optional methods. This
/// currently doesn't have any effect, but will probably in the future.
/// - Class methods are not (yet) supported.
/// - Protocols do not have a direct parent/child relationship, so specifying
/// a parent is not required. However, to make usage easier if the protocol
/// only directly conforms to one protocol, you may specify a "parent"
/// protocol that this protocol will `Deref` to.
/// - Other protocols that this protocol conforms to can be specified using
/// the `#[conforms_to(...)]` attribute, similar to `#[inherits(...)]` in
/// [`extern_class!`].
///
/// [`extern_class!`]: crate::extern_class
/// [`extern_methods!`]: crate::extern_methods
/// [`ConformsTo`]: crate::ConformsTo
///
///
/// # Safety
///
/// - The specified name must be an exisiting Objective-C protocol.
/// - The protocol must actually inherit/conform to the protocols specified in
/// `#[conforms_to(...)]`.
/// - If a parent protocol is specified, the protocol must inherit/conform to
/// said protocol.
/// - The protocol's methods must be correctly specified.
#[doc(alias = "@protocol")]
#[macro_export]
macro_rules! extern_protocol {
Expand Down Expand Up @@ -150,13 +213,16 @@ macro_rules! __extern_protocol_inner {
}
);

// SAFETY: TODO
// SAFETY: The specified name is ensured by caller to be a protocol,
// and is correctly defined.
unsafe impl ProtocolType for $for {
const NAME: &'static str = $name_const;
const __INNER: () = ();
}

$(
// SAFETY: Caller ensures that the protocol actually conforms to
// these protocols.
unsafe impl $crate::ConformsTo<$conforms_to> for $for {}
)*

Expand Down
2 changes: 1 addition & 1 deletion crates/objc2/src/protocol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ use crate::Message;
///
/// Use the [`extern_protocol!`] macro to implement this trait for a type.
///
/// ```ignore
/// ```no_run
/// use objc2::{extern_protocol, ProtocolType};
///
/// extern_protocol!(
Expand Down

0 comments on commit 5c26a71

Please sign in to comment.