Skip to content

Commit

Permalink
Merge pull request #244 from madsmtm/extern-methods-id
Browse files Browse the repository at this point in the history
Allow returning `Id` from `extern_methods!`
  • Loading branch information
madsmtm authored Nov 1, 2022
2 parents fde2785 + 6aacd14 commit 2063dee
Show file tree
Hide file tree
Showing 29 changed files with 395 additions and 178 deletions.
4 changes: 4 additions & 0 deletions objc2/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
* Added the ability to specify an extra parameter at the end of the selector
in methods declared with `extern_methods!`, and let that be the `NSError**`
parameter.
* Added `#[method_id(...)]` attribute to `extern_methods!`.

### Changed
* Allow other types than `&Class` as the receiver in `msg_send_id!` methods
Expand All @@ -45,6 +46,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
associated functions whoose first parameter is called `this`, is treated as
instance methods instead of class methods.

### Fixed
* Fixed duplicate selector extraction in `extern_methods!`.


## 0.3.0-beta.3 - 2022-09-01

Expand Down
17 changes: 8 additions & 9 deletions objc2/src/foundation/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,15 +90,14 @@ extern_methods!(
/// Generic creation methods.
unsafe impl<T: Message, O: Ownership> NSArray<T, O> {
/// Get an empty array.
pub fn new() -> Id<Self, Shared> {
// SAFETY:
// - `new` may not create a new object, but instead return a shared
// instance. We remedy this by returning `Id<Self, Shared>`.
// - `O` don't actually matter here! E.g. `NSArray<T, Owned>` is
// perfectly legal, since the array doesn't have any elements, and
// hence the notion of ownership over the elements is void.
unsafe { msg_send_id![Self::class(), new] }
}
// SAFETY:
// - `new` may not create a new object, but instead return a shared
// instance. We remedy this by returning `Id<Self, Shared>`.
// - `O` don't actually matter here! E.g. `NSArray<T, Owned>` is
// perfectly legal, since the array doesn't have any elements, and
// hence the notion of ownership over the elements is void.
#[method_id(new)]
pub fn new() -> Id<Self, Shared>;

pub fn from_vec(vec: Vec<Id<T, O>>) -> Id<Self, O> {
// SAFETY:
Expand Down
34 changes: 18 additions & 16 deletions objc2/src/foundation/attributed_string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ use core::panic::{RefUnwindSafe, UnwindSafe};
use super::{
NSCopying, NSDictionary, NSMutableAttributedString, NSMutableCopying, NSObject, NSString,
};
use crate::rc::{DefaultId, Id, Shared};
use crate::rc::{Allocated, DefaultId, Id, Shared};
use crate::runtime::Object;
use crate::{extern_class, extern_methods, msg_send_id, ClassType};
use crate::{extern_class, extern_methods, ClassType};

extern_class!(
/// A string that has associated attributes for portions of its text.
Expand Down Expand Up @@ -45,9 +45,18 @@ extern_methods!(
/// Creating attributed strings.
unsafe impl NSAttributedString {
/// Construct an empty attributed string.
pub fn new() -> Id<Self, Shared> {
unsafe { msg_send_id![Self::class(), new] }
}
#[method_id(new)]
pub fn new() -> Id<Self, Shared>;

#[method_id(initWithString:attributes:)]
fn init_with_attributes(
this: Option<Allocated<Self>>,
string: &NSString,
attributes: &NSDictionary<NSAttributedStringKey, Object>,
) -> Id<Self, Shared>;

#[method_id(initWithString:)]
fn init_with_string(this: Option<Allocated<Self>>, string: &NSString) -> Id<Self, Shared>;

/// Creates a new attributed string from the given string and attributes.
///
Expand All @@ -59,28 +68,21 @@ extern_methods!(
// TODO: Mutability of the dictionary should be (Shared, Shared)
attributes: &NSDictionary<NSAttributedStringKey, Object>,
) -> Id<Self, Shared> {
unsafe {
msg_send_id![
Self::alloc(),
initWithString: string,
attributes: attributes,
]
}
Self::init_with_attributes(Self::alloc(), string, attributes)
}

/// Creates a new attributed string without any attributes.
#[doc(alias = "initWithString:")]
pub fn from_nsstring(string: &NSString) -> Id<Self, Shared> {
unsafe { msg_send_id![Self::alloc(), initWithString: string] }
Self::init_with_string(Self::alloc(), string)
}
}

/// Querying.
unsafe impl NSAttributedString {
// TODO: Lifetimes?
pub fn string(&self) -> Id<NSString, Shared> {
unsafe { msg_send_id![self, string] }
}
#[method_id(string)]
pub fn string(&self) -> Id<NSString, Shared>;

/// Alias for `self.string().len_utf16()`.
#[doc(alias = "length")]
Expand Down
12 changes: 5 additions & 7 deletions objc2/src/foundation/bundle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use core::panic::{RefUnwindSafe, UnwindSafe};

use super::{NSCopying, NSDictionary, NSObject, NSString};
use crate::rc::{Id, Shared};
use crate::{extern_class, extern_methods, msg_send_id, ClassType};
use crate::{extern_class, extern_methods, ClassType};

extern_class!(
/// A representation of the code and resources stored in a bundle
Expand All @@ -27,13 +27,11 @@ impl RefUnwindSafe for NSBundle {}

extern_methods!(
unsafe impl NSBundle {
pub fn main() -> Id<Self, Shared> {
unsafe { msg_send_id![Self::class(), mainBundle] }
}
#[method_id(mainBundle)]
pub fn main() -> Id<Self, Shared>;

pub fn info(&self) -> Id<NSDictionary<NSString, NSObject>, Shared> {
unsafe { msg_send_id![self, infoDictionary] }
}
#[method_id(infoDictionary)]
pub fn info(&self) -> Id<NSDictionary<NSString, NSObject>, Shared>;

pub fn name(&self) -> Option<Id<NSString, Shared>> {
// TODO: Use ns_string!
Expand Down
5 changes: 2 additions & 3 deletions objc2/src/foundation/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,8 @@ impl RefUnwindSafe for NSData {}
extern_methods!(
/// Creation methods.
unsafe impl NSData {
pub fn new() -> Id<Self, Shared> {
unsafe { msg_send_id![Self::class(), new] }
}
#[method_id(new)]
pub fn new() -> Id<Self, Shared>;

pub fn with_bytes(bytes: &[u8]) -> Id<Self, Shared> {
unsafe { Id::cast(with_slice(Self::class(), bytes)) }
Expand Down
10 changes: 4 additions & 6 deletions objc2/src/foundation/dictionary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,8 @@ impl<K: Message + UnwindSafe, V: Message + UnwindSafe> UnwindSafe for NSDictiona
impl<K: Message + RefUnwindSafe, V: Message + RefUnwindSafe> RefUnwindSafe for NSDictionary<K, V> {}
extern_methods!(
unsafe impl<K: Message, V: Message> NSDictionary<K, V> {
pub fn new() -> Id<Self, Shared> {
unsafe { msg_send_id![Self::class(), new] }
}
#[method_id(new)]
pub fn new() -> Id<Self, Shared>;

#[doc(alias = "count")]
#[method(count)]
Expand Down Expand Up @@ -102,9 +101,8 @@ extern_methods!(
}
}

pub fn keys_array(&self) -> Id<NSArray<K, Shared>, Shared> {
unsafe { msg_send_id![self, allKeys] }
}
#[method_id(allKeys)]
pub fn keys_array(&self) -> Id<NSArray<K, Shared>, Shared>;

pub fn from_keys_and_objects<T>(keys: &[&T], vals: Vec<Id<V, Owned>>) -> Id<Self, Shared>
where
Expand Down
10 changes: 4 additions & 6 deletions objc2/src/foundation/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,16 +63,14 @@ extern_methods!(

/// Accessor methods.
unsafe impl NSError {
pub fn domain(&self) -> Id<NSString, Shared> {
unsafe { msg_send_id![self, domain] }
}
#[method_id(domain)]
pub fn domain(&self) -> Id<NSString, Shared>;

#[method(code)]
pub fn code(&self) -> NSInteger;

pub fn user_info(&self) -> Option<Id<NSDictionary<NSErrorUserInfoKey, NSObject>, Shared>> {
unsafe { msg_send_id![self, userInfo] }
}
#[method_id(userInfo)]
pub fn user_info(&self) -> Option<Id<NSDictionary<NSErrorUserInfoKey, NSObject>, Shared>>;

pub fn localized_description(&self) -> Id<NSString, Shared> {
// TODO: For some reason this leaks a lot?
Expand Down
17 changes: 7 additions & 10 deletions objc2/src/foundation/exception.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,20 +83,17 @@ extern_methods!(
/// can take.
///
/// [doc]: https://developer.apple.com/documentation/foundation/nsexceptionname?language=objc
pub fn name(&self) -> Id<NSExceptionName, Shared> {
// Nullability not documented, but a name is expected in most places.
unsafe { msg_send_id![self, name] }
}
#[method_id(name)]
// Nullability not documented, but a name is expected in most places.
pub fn name(&self) -> Id<NSExceptionName, Shared>;

/// A human-readable message summarizing the reason for the exception.
pub fn reason(&self) -> Option<Id<NSString, Shared>> {
unsafe { msg_send_id![self, reason] }
}
#[method_id(reason)]
pub fn reason(&self) -> Option<Id<NSString, Shared>>;

/// Application-specific data pertaining to the exception.
pub fn user_info(&self) -> Option<Id<NSDictionary<Object, Object>, Shared>> {
unsafe { msg_send_id![self, userInfo] }
}
#[method_id(userInfo)]
pub fn user_info(&self) -> Option<Id<NSDictionary<Object, Object>, Shared>>;

/// Convert this into an [`Exception`] object.
pub fn into_exception(this: Id<Self, Shared>) -> Id<Exception, Shared> {
Expand Down
11 changes: 5 additions & 6 deletions objc2/src/foundation/mutable_array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use super::{
NSObject,
};
use crate::rc::{DefaultId, Id, Owned, Ownership, Shared, SliceId};
use crate::{ClassType, Message, __inner_extern_class, extern_methods, msg_send, msg_send_id};
use crate::{ClassType, Message, __inner_extern_class, extern_methods, msg_send};

__inner_extern_class!(
/// A growable ordered collection of objects.
Expand Down Expand Up @@ -42,11 +42,10 @@ unsafe impl<T: Message + Send> Send for NSMutableArray<T, Owned> {}
extern_methods!(
/// Generic creation methods.
unsafe impl<T: Message, O: Ownership> NSMutableArray<T, O> {
pub fn new() -> Id<Self, Owned> {
// SAFETY: Same as `NSArray::new`, except mutable arrays are always
// unique.
unsafe { msg_send_id![Self::class(), new] }
}
// SAFETY: Same as `NSArray::new`, except mutable arrays are always
// unique.
#[method_id(new)]
pub fn new() -> Id<Self, Owned>;

pub fn from_vec(vec: Vec<Id<T, O>>) -> Id<Self, Owned> {
// SAFETY: Same as `NSArray::from_vec`, except mutable arrays are
Expand Down
5 changes: 2 additions & 3 deletions objc2/src/foundation/mutable_attributed_string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,8 @@ extern_methods!(
/// Creating mutable attributed strings.
unsafe impl NSMutableAttributedString {
/// Construct an empty mutable attributed string.
pub fn new() -> Id<Self, Owned> {
unsafe { msg_send_id![Self::class(), new] }
}
#[method_id(new)]
pub fn new() -> Id<Self, Owned>;

// TODO: new_with_attributes

Expand Down
5 changes: 2 additions & 3 deletions objc2/src/foundation/mutable_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,8 @@ extern_class!(
extern_methods!(
/// Creation methods
unsafe impl NSMutableData {
pub fn new() -> Id<Self, Owned> {
unsafe { msg_send_id![Self::class(), new] }
}
#[method_id(new)]
pub fn new() -> Id<Self, Owned>;

pub fn with_bytes(bytes: &[u8]) -> Id<Self, Owned> {
unsafe { Id::from_shared(Id::cast(with_slice(Self::class(), bytes))) }
Expand Down
11 changes: 5 additions & 6 deletions objc2/src/foundation/mutable_dictionary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,11 @@ extern_methods!(
///
/// let dict = NSMutableDictionary::<NSString, NSObject>::new();
/// ```
pub fn new() -> Id<Self, Owned> {
// SAFETY:
// Mutable dictionaries are always unique, so it's safe to return
// `Id<Self, Owned>`
unsafe { msg_send_id![Self::class(), new] }
}
// SAFETY:
// Mutable dictionaries are always unique, so it's safe to return
// `Id<Self, Owned>`
#[method_id(new)]
pub fn new() -> Id<Self, Owned>;

#[method(setDictionary:)]
fn set_dictionary(&mut self, dict: &NSDictionary<K, V>);
Expand Down
11 changes: 5 additions & 6 deletions objc2/src/foundation/mutable_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use core::marker::PhantomData;
use super::set::with_objects;
use super::{NSCopying, NSFastEnumeration, NSFastEnumerator, NSMutableCopying, NSObject, NSSet};
use crate::rc::{DefaultId, Id, Owned, Ownership, Shared, SliceId};
use crate::{ClassType, Message, __inner_extern_class, extern_methods, msg_send_id};
use crate::{ClassType, Message, __inner_extern_class, extern_methods};

__inner_extern_class!(
/// A growable unordered collection of unique objects.
Expand Down Expand Up @@ -44,11 +44,10 @@ extern_methods!(
///
/// let set = NSMutableSet::<NSString>::new();
/// ```
pub fn new() -> Id<Self, Owned> {
// SAFETY:
// Same as `NSSet::new`, except mutable sets are always unique.
unsafe { msg_send_id![Self::class(), new] }
}
// SAFETY:
// Same as `NSSet::new`, except mutable sets are always unique.
#[method_id(new)]
pub fn new() -> Id<Self, Owned>;

/// Creates an [`NSMutableSet`] from a vector.
///
Expand Down
5 changes: 2 additions & 3 deletions objc2/src/foundation/mutable_string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,8 @@ extern_methods!(
/// Creating mutable strings.
unsafe impl NSMutableString {
/// Construct an empty [`NSMutableString`].
pub fn new() -> Id<Self, Owned> {
unsafe { msg_send_id![Self::class(), new] }
}
#[method_id(new)]
pub fn new() -> Id<Self, Owned>;

/// Creates a new [`NSMutableString`] by copying the given string slice.
#[doc(alias = "initWithBytes:length:encoding:")]
Expand Down
5 changes: 2 additions & 3 deletions objc2/src/foundation/number.rs
Original file line number Diff line number Diff line change
Expand Up @@ -244,9 +244,8 @@ extern_methods!(
#[method(isEqualToNumber:)]
fn is_equal_to_number(&self, other: &Self) -> bool;

fn string(&self) -> Id<NSString, Shared> {
unsafe { msg_send_id![self, stringValue] }
}
#[method_id(stringValue)]
fn string(&self) -> Id<NSString, Shared>;
}
);

Expand Down
5 changes: 2 additions & 3 deletions objc2/src/foundation/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,8 @@ unsafe impl ClassType for NSObject {

extern_methods!(
unsafe impl NSObject {
pub fn new() -> Id<Self, Owned> {
unsafe { msg_send_id![Self::class(), new] }
}
#[method_id(new)]
pub fn new() -> Id<Self, Owned>;

#[method(isKindOfClass:)]
fn is_kind_of_inner(&self, cls: &Class) -> bool;
Expand Down
12 changes: 5 additions & 7 deletions objc2/src/foundation/process_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use core::panic::{RefUnwindSafe, UnwindSafe};

use super::{NSObject, NSString};
use crate::rc::{Id, Shared};
use crate::{extern_class, extern_methods, msg_send_id, ClassType};
use crate::{extern_class, extern_methods, ClassType};

extern_class!(
/// A collection of information about the current process.
Expand All @@ -27,13 +27,11 @@ impl RefUnwindSafe for NSProcessInfo {}

extern_methods!(
unsafe impl NSProcessInfo {
pub fn process_info() -> Id<NSProcessInfo, Shared> {
unsafe { msg_send_id![Self::class(), processInfo] }
}
#[method_id(processInfo)]
pub fn process_info() -> Id<NSProcessInfo, Shared>;

pub fn process_name(&self) -> Id<NSString, Shared> {
unsafe { msg_send_id![self, processName] }
}
#[method_id(processName)]
pub fn process_name(&self) -> Id<NSString, Shared>;

// TODO: This contains a lot more important functionality!
}
Expand Down
Loading

0 comments on commit 2063dee

Please sign in to comment.