use std::{marker::PhantomData, slice};
use libc::c_char;
use objc::{class, msg_send, runtime::Object, sel, sel_impl};
use crate::{
foundation::NSString,
object,
objective_c_runtime::{
id,
traits::{FromId, PNSObject},
},
utils::to_bool,
};
use self::iter::Iter;
use super::{ns_mutable_array::NSMutableArray, NSLocale, NSNumber, NSRange, UInt, UInt8};
pub mod iter;
object! {
unsafe pub struct NSArray<T> {
_marker: PhantomData<T>,
}
}
impl<T> NSArray<T> {
pub fn iter(&self) -> Iter<'_, T>
where
T: PNSObject,
{
Iter {
array: self,
index: 0,
}
}
}
impl<T> NSArray<T> {
pub fn new() -> Self {
NSArray::m_new()
}
pub fn contains(&self, object: T) -> bool
where
T: PNSObject,
{
self.m_contains_object(object)
}
pub fn count(&self) -> u64 {
self.p_count()
}
}
pub trait INSArray<T>: PNSObject {
fn m_contains_object(&self, object: T) -> bool {
unsafe { to_bool(msg_send![self.m_self(), containsObject: object]) }
}
fn p_count(&self) -> UInt {
unsafe { msg_send![self.m_self(), count] }
}
fn p_first_object(&self) -> Option<T>
where
T: PNSObject + FromId,
{
unsafe {
let id: id = msg_send![self.m_self(), firstObject];
if id.is_null() {
None
} else {
Some(T::from_id(id))
}
}
}
fn p_last_object(&self) -> Option<T>
where
T: PNSObject + FromId,
{
unsafe {
let id: id = msg_send![self.m_self(), lastObject];
if id.is_null() {
None
} else {
Some(T::from_id(id))
}
}
}
fn m_object_at_index(&self, index: UInt) -> T
where
T: PNSObject + FromId,
{
unsafe { T::from_id(msg_send![self.m_self(), objectAtIndex: index]) }
}
fn m_object_at_indexed_subscript(&self, index: UInt) -> Option<id> {
unsafe {
let id: id = msg_send![self.m_self(), objectAtIndexedSubscript: index];
if id.is_null() {
None
} else {
Some(id)
}
}
}
fn m_index_of_object(&self, object: T) -> UInt {
unsafe { msg_send![self.m_self(), indexOfObject: object] }
}
fn m_index_of_object_in_range(&self, object: T, range: NSRange) -> UInt {
unsafe { msg_send![self.m_self(), indexOfObject: object inRange: range] }
}
fn m_index_of_object_identical_to(&self, object: T) -> UInt {
unsafe { msg_send![self.m_self(), indexOfObjectIdenticalTo: object] }
}
fn m_index_of_object_identical_to_in_range(&self, object: T, range: NSRange) -> UInt {
unsafe { msg_send![self.m_self(), indexOfObjectIdenticalTo: object inRange: range] }
}
fn m_first_object_common_with_array(&self, other: &NSArray<T>) -> Option<T>
where
T: PNSObject + FromId,
{
unsafe {
let id: id = msg_send![self.m_self(), firstObjectCommonWithArray: other.m_self()];
if id.is_null() {
None
} else {
Some(T::from_id(id))
}
}
}
fn m_is_equal_to_array(&self, other: &NSArray<T>) -> bool {
unsafe { to_bool(msg_send![self.m_self(), isEqualToArray: other.m_self()]) }
}
unsafe fn m_array_by_adding_object(&self, object: T) -> NSArray<T> {
NSArray::from_id(msg_send![self.m_self(), arrayByAddingObject: object])
}
unsafe fn m_array_by_adding_objects_from_array<A>(&self, objects: A) -> NSArray<T>
where
A: INSArray<T>,
{
NSArray::from_id(msg_send![self.m_self(), arrayByAddingObjectsFromArray: objects.m_self()])
}
unsafe fn m_subarray_with_range(&self, range: NSRange) -> NSArray<T> {
NSArray::from_id(msg_send![self.m_self(), subarrayWithRange: range])
}
fn m_description_with_locale(&self, locale: &NSLocale) -> NSString {
unsafe { msg_send![self.m_self(), descriptionWithLocale: locale.m_self()] }
}
fn m_description_with_locale_indent(&self, locale: &NSLocale, indent: UInt) -> NSString {
unsafe { msg_send![self.m_self(), descriptionWithLocale: locale.m_self() indent: indent] }
}
}
impl<T> INSArray<T> for NSArray<T> {}
impl<T> Default for NSArray<T> {
fn default() -> Self {
Self::m_new()
}
}
impl<'a, T> IntoIterator for &'a NSArray<T>
where
T: PNSObject + FromId,
{
type Item = T;
type IntoIter = Iter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl From<(*const c_char, usize)> for NSArray<UInt8> {
fn from((s, i): (*const c_char, usize)) -> Self {
let v = unsafe { slice::from_raw_parts(s as *const u8, i) };
NSArray::from(v)
}
}
impl<T> From<id> for NSArray<T> {
#[allow(clippy::not_unsafe_ptr_arg_deref)]
fn from(obj: id) -> Self {
unsafe { NSArray::from_id(obj) }
}
}
impl<T> From<&[T]> for NSArray<T>
where
T: PNSObject,
{
fn from(array: &[T]) -> Self {
unsafe {
let cls: *mut Object = msg_send![class!(NSArray),
arrayWithObjects:array.as_ptr()
count:array.len()
];
NSArray::from(cls)
}
}
}
impl<T> From<Vec<T>> for NSArray<T>
where
T: PNSObject,
{
fn from(objects: Vec<T>) -> Self {
unsafe {
let cls: id = msg_send![class!(NSArray),
arrayWithObjects:objects.as_ptr()
count:objects.len()
];
NSArray::from(cls)
}
}
}
impl From<Vec<i8>> for NSArray<NSNumber> {
fn from(objects: Vec<i8>) -> Self {
let objects: Vec<NSNumber> = objects.iter().map(|i| NSNumber::from(*i)).collect();
unsafe {
let cls: id = msg_send![class!(NSArray),
arrayWithObjects:objects.as_ptr()
count:objects.len()
];
NSArray::from(cls)
}
}
}
impl From<Vec<i16>> for NSArray<NSNumber> {
fn from(objects: Vec<i16>) -> Self {
let objects: Vec<NSNumber> = objects.iter().map(|i| NSNumber::from(*i)).collect();
unsafe {
let cls: id = msg_send![class!(NSArray),
arrayWithObjects:objects.as_ptr()
count:objects.len()
];
NSArray::from(cls)
}
}
}
impl From<Vec<i32>> for NSArray<NSNumber> {
fn from(objects: Vec<i32>) -> Self {
let objects: Vec<NSNumber> = objects.iter().map(|i| NSNumber::from(*i)).collect();
unsafe {
let cls: id = msg_send![class!(NSArray),
arrayWithObjects:objects.as_ptr()
count:objects.len()
];
NSArray::from(cls)
}
}
}
impl From<Vec<i64>> for NSArray<NSNumber> {
fn from(objects: Vec<i64>) -> Self {
let objects: Vec<NSNumber> = objects.iter().map(|i| NSNumber::from(*i)).collect();
unsafe {
let cls: id = msg_send![class!(NSArray),
arrayWithObjects:objects.as_ptr()
count:objects.len()
];
NSArray::from(cls)
}
}
}
impl From<Vec<u8>> for NSArray<NSNumber> {
fn from(objects: Vec<u8>) -> Self {
let objects: Vec<NSNumber> = objects.iter().map(|i| NSNumber::from(*i)).collect();
unsafe {
let cls: id = msg_send![class!(NSArray),
arrayWithObjects:objects.as_ptr()
count:objects.len()
];
NSArray::from(cls)
}
}
}
impl From<Vec<u16>> for NSArray<NSNumber> {
fn from(objects: Vec<u16>) -> Self {
let objects: Vec<NSNumber> = objects.iter().map(|i| NSNumber::from(*i)).collect();
unsafe {
let cls: id = msg_send![class!(NSArray),
arrayWithObjects:objects.as_ptr()
count:objects.len()
];
NSArray::from(cls)
}
}
}
impl From<Vec<u32>> for NSArray<NSNumber> {
fn from(objects: Vec<u32>) -> Self {
let objects: Vec<NSNumber> = objects.iter().map(|i| NSNumber::from(*i)).collect();
unsafe {
let cls: id = msg_send![class!(NSArray),
arrayWithObjects:objects.as_ptr()
count:objects.len()
];
NSArray::from(cls)
}
}
}
impl From<Vec<u64>> for NSArray<NSNumber> {
fn from(objects: Vec<u64>) -> Self {
let objects: Vec<NSNumber> = objects.iter().map(|i| NSNumber::from(*i)).collect();
unsafe {
let cls: id = msg_send![class!(NSArray),
arrayWithObjects:objects.as_ptr()
count:objects.len()
];
NSArray::from(cls)
}
}
}
impl From<&[u8]> for NSArray<u8> {
fn from(objects: &[u8]) -> Self {
unsafe {
let cls: id = msg_send![class!(NSArray),
arrayWithObjects:objects.as_ptr()
count:objects.len()
];
NSArray::from(cls)
}
}
}
impl From<&[id]> for NSArray<u8> {
fn from(objects: &[id]) -> Self {
unsafe {
let cls: id = msg_send![class!(NSArray),
arrayWithObjects:objects.as_ptr()
count:objects.len()
];
NSArray::from(cls)
}
}
}
impl From<Vec<id>> for NSArray<id> {
fn from(objects: Vec<id>) -> Self {
unsafe {
let cls: id = msg_send![class!(NSArray),
arrayWithObjects:objects.as_ptr()
count:objects.len()
];
NSArray::from_id(cls)
}
}
}
impl From<Vec<&str>> for NSArray<NSString> {
fn from(objects: Vec<&str>) -> Self {
let objects: Vec<NSString> = objects.iter().map(|s| NSString::from(*s)).collect();
unsafe {
let cls: id = msg_send![class!(NSArray),
arrayWithObjects:objects.as_ptr()
count:objects.len()
];
NSArray::from(cls)
}
}
}
impl From<Vec<String>> for NSArray<NSString> {
fn from(objects: Vec<String>) -> Self {
let objects: Vec<NSString> = objects.iter().map(|s| NSString::from(s.clone())).collect();
unsafe {
let cls: id = msg_send![class!(NSArray),
arrayWithObjects:objects.as_ptr()
count:objects.len()
];
NSArray::from(cls)
}
}
}
impl<T> From<NSMutableArray<T>> for NSArray<T>
where
T: PNSObject,
{
fn from(array: NSMutableArray<T>) -> Self {
let cls: id = unsafe {
{
msg_send![class!(NSArray), arrayWithArray: array]
}
};
NSArray::from(cls)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_array_from_vec() {
let array: NSArray<NSString> = vec!["foo", "bar"].into();
assert_eq!(array.count(), 2);
assert_eq!(array.m_object_at_index(0), NSString::from("foo"));
assert_eq!(array.m_object_at_index(1), NSString::from("bar"));
}
#[test]
fn test_first_common_object() {
let array: NSArray<NSString> = vec!["foo", "bar"].into();
let array2: NSArray<NSString> = vec!["foo", "bar"].into();
assert_eq!(
array.m_first_object_common_with_array(&array2),
Some(NSString::from("foo"))
);
}
}