Macro objc2::extern_methods
source · macro_rules! extern_methods { ( $( $(#[$impl_m:meta])* unsafe impl<$($t:ident $(: $b:ident $(+ $rest:ident)*)?),*> $type:ty { $($methods:tt)* } )+ ) => { ... }; ( $( $(#[$impl_m:meta])* unsafe impl $type:ty { $($methods:tt)* } )+ ) => { ... }; }
Expand description
Define methods on an external class.
This is a convenience macro to easily generate associated functions and
methods that call msg_send!
appropriately.
Specification
Within the impl
block you can define two types of functions without
bodies; “associated functions” and “methods”. These are then mapped to
the Objective-C equivalents “class methods” and “instance methods”, and an
appropriate body is created for you. In particular, if you use self
your
method will assumbed to be an instance method, and if you don’t it will be
assumed to be a class method.
The desired selector can be specified using the #[sel(my:selector:)]
attribute. The name of the function doesn’t matter.
If you specify a function/method with a body, the macro will simply ignore it.
Safety
You must ensure that any methods you declare with the #[sel(...)]
attribute upholds the safety guarantees decribed in the
msg_send!
macro, or are marked unsafe
.
Examples
Let’s create a quick interface to the NSCalendar
class:
use objc2::foundation::{NSObject, NSRange, NSString, NSUInteger};
use objc2::rc::{Id, Shared};
use objc2::{extern_class, extern_methods, msg_send_id, Encode, Encoding, ClassType};
extern_class!(
#[derive(PartialEq, Eq, Hash)]
pub struct NSCalendar;
unsafe impl ClassType for NSCalendar {
type Super = NSObject;
}
);
pub type NSCalendarIdentifier = NSString;
#[repr(usize)] // NSUInteger
pub enum NSCalendarUnit {
Hour = 32,
Minute = 64,
Second = 128,
// TODO: More units
}
unsafe impl Encode for NSCalendarUnit {
const ENCODING: Encoding = usize::ENCODING;
}
extern_methods!(
/// Creation methods.
// TODO: Support methods returning `Id`
unsafe impl NSCalendar {
pub fn current() -> Id<Self, Shared> {
unsafe { msg_send_id![Self::class(), currentCalendar] }
}
pub fn new(identifier: &NSCalendarIdentifier) -> Id<Self, Shared> {
unsafe {
msg_send_id![
msg_send_id![Self::class(), alloc],
initWithCalendarIdentifier: identifier,
]
}
}
}
/// Accessor methods.
// SAFETY: `first_weekday` is correctly defined
unsafe impl NSCalendar {
#[sel(firstWeekday)]
pub fn first_weekday(&self) -> NSUInteger;
pub fn am_symbol(&self) -> Id<NSString, Shared> {
unsafe { msg_send_id![self, amSymbol] }
}
#[sel(date:matchesComponents:)]
// `unsafe` because we don't have definitions for `NSDate` and
// `NSDateComponents` yet, so the user must ensure that is what's
// passed.
pub unsafe fn date_matches(&self, date: &NSObject, components: &NSObject) -> bool;
#[sel(maximumRangeOfUnit:)]
pub fn max_range(&self, unit: NSCalendarUnit) -> NSRange;
}
);
The extern_methods!
declaration then becomes:
/// Creation methods.
impl NSCalendar {
pub fn current() -> Id<Self, Shared> {
unsafe { msg_send_id![Self::class(), currentCalendar] }
}
pub fn new(identifier: &NSCalendarIdentifier) -> Id<Self, Shared> {
unsafe {
msg_send_id![
msg_send_id![Self::class(), alloc],
initWithCalendarIdentifier: identifier,
]
}
}
}
/// Accessor methods.
impl NSCalendar {
pub fn first_weekday(&self) -> NSUInteger {
unsafe { msg_send![self, firstWeekday] }
}
pub fn am_symbol(&self) -> Id<NSString, Shared> {
unsafe { msg_send_id![self, amSymbol] }
}
pub unsafe fn date_matches(&self, date: &NSObject, components: &NSObject) -> bool {
unsafe { msg_send![self, date: date, matchesComponents: components] }
}
pub fn max_range(&self, unit: NSCalendarUnit) -> NSRange {
unsafe { msg_send![self, maximumRangeOfUnit: unit] }
}
}