Skip to content

Commit

Permalink
Add a few NSArray methods
Browse files Browse the repository at this point in the history
  • Loading branch information
madsmtm committed Dec 21, 2021
1 parent b276169 commit 08a9410
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 23 deletions.
3 changes: 1 addition & 2 deletions objc2-foundation-sys/src/generated_nsstring.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,11 @@ use objc2::rc::{Id, Unknown};
use objc2::runtime::{Bool, Object};
use objc2::{class, msg_send, Encoding, Message, RefEncode};

use crate::{Autoreleased, NSObject};
use crate::{Autoreleased, NSArray, NSObject};

pub type NSRange = [NSUInteger; 2];
pub type NSComparisonResult = NSInteger;

pub type NSArray = NSObject;
pub type NSCoder = NSObject;
pub type NSLocale = NSObject;
pub type NSError = NSObject;
Expand Down
70 changes: 70 additions & 0 deletions objc2-foundation-sys/src/generated_others_shim.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
//! Other quick examples
use core::mem::ManuallyDrop;
use core::ptr::NonNull;

use std::os::raw::{c_char, c_int, c_longlong, c_schar, c_ulong, c_ushort, c_void};

use objc2::ffi::{NSInteger, NSUInteger};
use objc2::rc::{Id, Unknown};
use objc2::runtime::{Bool, Object};
use objc2::{class, msg_send, Encoding, Message, RefEncode};

use crate::{Autoreleased, NSCoder, NSObject, NSRange, NSString};

#[repr(transparent)]
pub struct NSArray(NSObject);
impl core::ops::Deref for NSArray {
type Target = NSObject;
#[inline]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl core::ops::DerefMut for NSArray {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
unsafe impl Message for NSArray {}
unsafe impl RefEncode for NSArray {
const ENCODING_REF: Encoding<'static> = Encoding::Object;
}
impl NSArray {
pub unsafe fn alloc() -> Option<Id<Self, Unknown>> {
Id::new_null(msg_send![class!(NSArray), alloc])
}
}
impl NSArray {
pub unsafe fn objectAtIndex_(&self, index: NSUInteger) -> Autoreleased<Object> {
msg_send![self, objectAtIndex: index]
}
pub unsafe fn init(this: Id<Self, Unknown>) -> Id<Self, Unknown> {
let this = ManuallyDrop::new(this);
Id::new(msg_send![this, init])
}
pub unsafe fn initWithObjects_count_(
this: Id<Self, Unknown>,
objects: NonNull<*mut Object>,
cnt: NSUInteger,
) -> Id<Self, Unknown> {
let this = ManuallyDrop::new(this);
Id::new(msg_send![this, initWithObjects: objects, count: cnt])
}
pub unsafe fn initWithCoder_(&self, coder: NonNull<NSCoder>) -> Option<Id<Self, Unknown>> {
Id::new_null(msg_send![self, initWithCoder: coder])
}
pub unsafe fn count(&self) -> NSUInteger {
msg_send![self, count]
}
pub unsafe fn firstObject(&self) -> Option<Autoreleased<Object>> {
msg_send![self, firstObject]
}
pub unsafe fn lastObject(&self) -> Option<Autoreleased<Object>> {
msg_send![self, lastObject]
}
pub unsafe fn getObjects_range_(&self, objects: NonNull<NonNull<Object>>, range: NSRange) {
msg_send![self, getObjects: objects, range: range]
}
}
3 changes: 3 additions & 0 deletions objc2-foundation-sys/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,8 @@ mod generated;
#[allow(improper_ctypes)] // TODO
mod generated_nsstring;

mod generated_others_shim;

pub use generated::*;
pub use generated_nsstring::*;
pub use generated_others_shim::*;
41 changes: 20 additions & 21 deletions objc2-foundation/src/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,34 +10,31 @@ use objc2::rc::{Id, Owned, Ownership, Shared, SliceId};
use objc2::runtime::Object;

use super::{
INSCopying, INSFastEnumeration, INSMutableCopying, INSObject, NSComparisonResult, NSEnumerator,
NSRange,
ffi, INSCopying, INSFastEnumeration, INSMutableCopying, INSObject, NSComparisonResult,
NSEnumerator, NSRange,
};

unsafe fn from_refs<A: INSArray>(refs: &[&A::Item]) -> Id<A, A::Ownership> {
let cls = A::class();
let obj: *mut A = unsafe { msg_send![cls, alloc] };
let obj: *mut A = unsafe {
msg_send![
obj,
initWithObjects: refs.as_ptr(),
count: refs.len(),
]
};
let obj = unsafe { NonNull::new_unchecked(obj) };
unsafe { Id::new(obj) }
let ptr = unsafe { NonNull::new_unchecked(refs.as_ptr() as *mut _) };
let obj = unsafe { ffi::NSArray::alloc().unwrap() };
let obj = unsafe { ffi::NSArray::initWithObjects_count_(obj, ptr, refs.len()) };
unsafe { obj.cast().into_ownership() }
}

pub unsafe trait INSArray: INSObject {
type Ownership: Ownership;
type Item: INSObject;
type ItemOwnership: Ownership;

fn r(&self) -> &ffi::NSArray {
unsafe { &*(self as *const Self as *const ffi::NSArray) }
}

unsafe_def_fn!(fn new -> Self::Ownership);

#[doc(alias = "count")]
fn len(&self) -> usize {
unsafe { msg_send![self, count] }
unsafe { self.r().count() }
}

fn is_empty(&self) -> bool {
Expand All @@ -49,7 +46,7 @@ pub unsafe trait INSArray: INSObject {
// TODO: Replace this check with catching the thrown NSRangeException
if index < self.len() {
// SAFETY: The index is checked to be in bounds.
Some(unsafe { msg_send![self, objectAtIndex: index] })
Some(unsafe { self.r().objectAtIndex_(index).cast().as_ref() })
} else {
None
}
Expand All @@ -63,7 +60,7 @@ pub unsafe trait INSArray: INSObject {
// TODO: Replace this check with catching the thrown NSRangeException
if index < self.len() {
// SAFETY: The index is checked to be in bounds.
Some(unsafe { msg_send![self, objectAtIndex: index] })
Some(unsafe { self.r().objectAtIndex_(index).cast().as_mut() })
} else {
None
}
Expand All @@ -81,28 +78,28 @@ pub unsafe trait INSArray: INSObject {

#[doc(alias = "firstObject")]
fn first(&self) -> Option<&Self::Item> {
unsafe { msg_send![self, firstObject] }
unsafe { self.r().firstObject().map(|ptr| ptr.cast().as_ref()) }
}

#[doc(alias = "firstObject")]
fn first_mut(&mut self) -> Option<&mut Self::Item>
where
Self: INSArray<ItemOwnership = Owned>,
{
unsafe { msg_send![self, firstObject] }
unsafe { self.r().firstObject().map(|ptr| ptr.cast().as_mut()) }
}

#[doc(alias = "lastObject")]
fn last(&self) -> Option<&Self::Item> {
unsafe { msg_send![self, lastObject] }
unsafe { self.r().lastObject().map(|ptr| ptr.cast().as_ref()) }
}

#[doc(alias = "lastObject")]
fn last_mut(&mut self) -> Option<&mut Self::Item>
where
Self: INSArray<ItemOwnership = Owned>,
{
unsafe { msg_send![self, lastObject] }
unsafe { self.r().lastObject().map(|ptr| ptr.cast().as_mut()) }
}

#[doc(alias = "objectEnumerator")]
Expand All @@ -121,7 +118,9 @@ pub unsafe trait INSArray: INSObject {
let range = NSRange::from(range);
let mut vec = Vec::with_capacity(range.length);
unsafe {
let _: () = msg_send![self, getObjects: vec.as_ptr(), range: range];
let tmp = [range.location, range.length]; // TMP
let ptr = NonNull::new_unchecked(vec.as_mut_ptr()).cast();
self.r().getObjects_range_(ptr, tmp);
vec.set_len(range.length);
}
vec
Expand Down

0 comments on commit 08a9410

Please sign in to comment.