//! A wrapper type for `NSArray`. This is abstracted out as we need to use `NSArray` in a ton of //! instances in this framework, and down the road I'd like to investigate using `CFArray` instead //! of `NSArray` (i.e, if the ObjC runtime is ever pulled or something - perhaps those types would //! stick around). //! //! Essentially, consider this some sanity/cleanliness/future-proofing. End users should never need //! to touch this. use objc::{class, msg_send, sel, sel_impl}; use objc::runtime::Object; use objc_id::Id; use crate::foundation::id; /// A wrapper for `NSArray` that makes common operations in our framework a bit easier to handle /// and reason about. #[derive(Debug)] pub struct NSArray(pub Id); impl From> for NSArray { /// Given a set of `Object`s, creates an `NSArray` that holds them. fn from(objects: Vec<&Object>) -> Self { NSArray(unsafe { Id::from_ptr(msg_send![class!(NSArray), arrayWithObjects:objects.as_ptr() count:objects.len()]) }) } } impl From> for NSArray { /// Given a set of `*mut Object`s, creates an `NSArray` that holds them. fn from(objects: Vec) -> Self { NSArray(unsafe { Id::from_ptr(msg_send![class!(NSArray), arrayWithObjects:objects.as_ptr() count:objects.len()]) }) } } impl NSArray { /// Given a set of `Object`s, creates an `NSArray` that holds them. pub fn new(objects: &[id]) -> Self { NSArray(unsafe { Id::from_ptr(msg_send![class!(NSArray), arrayWithObjects:objects.as_ptr() count:objects.len()]) }) } /// In some cases, we're vended an `NSArray` by the system, and it's ideal to not retain that. /// This handles that edge case. pub fn wrap(array: id) -> Self { NSArray(unsafe { Id::from_retained_ptr(array) }) } /// Consumes and returns the underlying Objective-C value. pub fn into_inner(mut self) -> id { &mut *self.0 } /// Returns the `count` (`len()` equivalent) for the backing `NSArray`. pub fn count(&self) -> usize { unsafe { msg_send![self.0, count] } } /// A helper method for mapping over the backing `NSArray` items. /// Often times we need to map in this framework to convert between Rust types, so isolating /// this out makes life much easier. pub fn map T>(&self, transform: F) -> Vec { let count = self.count(); let mut ret: Vec = Vec::with_capacity(count); let mut index = 0; loop { let item: id = unsafe { msg_send![&*self.0, objectAtIndex:index] }; ret.push(transform(item)); index += 1; if index == count { break } } ret } }