cacao/appkit/foundation/array.rs

83 lines
2.7 KiB
Rust

//! 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<Object>);
impl From<Vec<&Object>> 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<Vec<id>> for NSArray {
/// Given a set of `*mut Object`s, creates an `NSArray` that holds them.
fn from(objects: Vec<id>) -> 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, F: Fn(id) -> T>(&self, transform: F) -> Vec<T> {
let count = self.count();
let mut ret: Vec<T> = 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
}
}