rust_macios/foundation/
ns_array.rs

1use std::{marker::PhantomData, slice};
2
3use libc::c_char;
4use objc::{class, msg_send, runtime::Object, sel, sel_impl};
5
6use crate::{
7    foundation::NSString,
8    object,
9    objective_c_runtime::{
10        id,
11        traits::{FromId, PNSObject},
12    },
13    utils::to_bool,
14};
15
16use self::iter::Iter;
17
18use super::{ns_mutable_array::NSMutableArray, NSLocale, NSNumber, NSRange, UInt, UInt8};
19
20/// Iterator for Array
21pub mod iter;
22
23object! {
24    /// A static ordered collection of objects.
25    unsafe pub struct NSArray<T> {
26        _marker: PhantomData<T>,
27    }
28}
29
30impl<T> NSArray<T> {
31    /// Creates an iterator.
32    pub fn iter(&self) -> Iter<'_, T>
33    where
34        T: PNSObject,
35    {
36        Iter {
37            array: self,
38            index: 0,
39        }
40    }
41}
42
43impl<T> NSArray<T> {
44    /// Creates an empty array.
45    pub fn new() -> Self {
46        NSArray::m_new()
47    }
48
49    /// Returns true if the obect is an instance of NSArray.
50    pub fn contains(&self, object: T) -> bool
51    where
52        T: PNSObject,
53    {
54        self.m_contains_object(object)
55    }
56
57    /// Returns the number of objects in the array.
58    pub fn count(&self) -> u64 {
59        self.p_count()
60    }
61}
62
63/// A static ordered collection of objects.
64pub trait INSArray<T>: PNSObject {
65    /* Querying an Array
66     */
67
68    /// Returns a Boolean value that indicates whether a given object is present in the array.
69    ///
70    /// # Arguments
71    ///
72    /// * `object` - An object to look for in the array..
73    ///
74    /// # Returns
75    ///
76    /// A Boolean value that indicates whether `object` is present in the array.
77    ///
78    fn m_contains_object(&self, object: T) -> bool {
79        unsafe { to_bool(msg_send![self.m_self(), containsObject: object]) }
80    }
81
82    /// The number of objects in the array.
83    fn p_count(&self) -> UInt {
84        unsafe { msg_send![self.m_self(), count] }
85    }
86
87    /// The first object in the array.
88    fn p_first_object(&self) -> Option<T>
89    where
90        T: PNSObject + FromId,
91    {
92        unsafe {
93            let id: id = msg_send![self.m_self(), firstObject];
94            if id.is_null() {
95                None
96            } else {
97                Some(T::from_id(id))
98            }
99        }
100    }
101
102    /// The last object in the array.
103    fn p_last_object(&self) -> Option<T>
104    where
105        T: PNSObject + FromId,
106    {
107        unsafe {
108            let id: id = msg_send![self.m_self(), lastObject];
109            if id.is_null() {
110                None
111            } else {
112                Some(T::from_id(id))
113            }
114        }
115    }
116
117    /// The object at the specified index.
118    fn m_object_at_index(&self, index: UInt) -> T
119    where
120        T: PNSObject + FromId,
121    {
122        unsafe { T::from_id(msg_send![self.m_self(), objectAtIndex: index]) }
123    }
124
125    /// The index of the specified object.
126    fn m_object_at_indexed_subscript(&self, index: UInt) -> Option<id> {
127        unsafe {
128            let id: id = msg_send![self.m_self(), objectAtIndexedSubscript: index];
129            if id.is_null() {
130                None
131            } else {
132                Some(id)
133            }
134        }
135    }
136
137    /* Finding Objects in an Array
138     */
139
140    /// Returns the lowest index whose corresponding array value is equal to a given object.
141    fn m_index_of_object(&self, object: T) -> UInt {
142        unsafe { msg_send![self.m_self(), indexOfObject: object] }
143    }
144
145    /// Returns the lowest index within a specified range whose corresponding array value is equal to a given object .
146    fn m_index_of_object_in_range(&self, object: T, range: NSRange) -> UInt {
147        unsafe { msg_send![self.m_self(), indexOfObject: object inRange: range] }
148    }
149
150    /// Returns the lowest index whose corresponding array value is identical to a given object.
151    fn m_index_of_object_identical_to(&self, object: T) -> UInt {
152        unsafe { msg_send![self.m_self(), indexOfObjectIdenticalTo: object] }
153    }
154
155    /// Returns the lowest index within a specified range whose corresponding array value is equal to a given object .
156    fn m_index_of_object_identical_to_in_range(&self, object: T, range: NSRange) -> UInt {
157        unsafe { msg_send![self.m_self(), indexOfObjectIdenticalTo: object inRange: range] }
158    }
159
160    /* Comparing Arrays
161     */
162
163    /// Returns the first object contained in the receiving array that’s equal to an object in another given array.
164    fn m_first_object_common_with_array(&self, other: &NSArray<T>) -> Option<T>
165    where
166        T: PNSObject + FromId,
167    {
168        unsafe {
169            let id: id = msg_send![self.m_self(), firstObjectCommonWithArray: other.m_self()];
170            if id.is_null() {
171                None
172            } else {
173                Some(T::from_id(id))
174            }
175        }
176    }
177
178    /// Compares the receiving array to another array.
179    fn m_is_equal_to_array(&self, other: &NSArray<T>) -> bool {
180        unsafe { to_bool(msg_send![self.m_self(), isEqualToArray: other.m_self()]) }
181    }
182
183    /* Deriving New Arrays
184     */
185
186    /// Returns a new array that is a copy of the receiving array with a given object added to the end.
187    ///
188    /// # Safety
189    ///
190    /// This function dereferences a raw pointer
191    unsafe fn m_array_by_adding_object(&self, object: T) -> NSArray<T> {
192        NSArray::from_id(msg_send![self.m_self(), arrayByAddingObject: object])
193    }
194
195    /// Returns a new array that is a copy of the receiving array with the objects contained in another array added to the end.
196    ///
197    /// # Safety
198    ///
199    /// This function dereferences a raw pointer
200    unsafe fn m_array_by_adding_objects_from_array<A>(&self, objects: A) -> NSArray<T>
201    where
202        A: INSArray<T>,
203    {
204        NSArray::from_id(msg_send![self.m_self(), arrayByAddingObjectsFromArray: objects.m_self()])
205    }
206
207    /// Returns a new array containing the receiving array’s elements that fall within the limits specified by a given range.
208    ///
209    /// # Safety
210    ///
211    /// This function dereferences a raw pointer
212    unsafe fn m_subarray_with_range(&self, range: NSRange) -> NSArray<T> {
213        NSArray::from_id(msg_send![self.m_self(), subarrayWithRange: range])
214    }
215    /* Creating a Description
216     */
217
218    /// A string that represents the contents of the array, formatted as a property list.
219
220    /// Returns a string that represents the contents of the array, formatted as a property list.
221    fn m_description_with_locale(&self, locale: &NSLocale) -> NSString {
222        unsafe { msg_send![self.m_self(), descriptionWithLocale: locale.m_self()] }
223    }
224
225    /// Returns a string that represents the contents of the array, formatted as a property list.
226    fn m_description_with_locale_indent(&self, locale: &NSLocale, indent: UInt) -> NSString {
227        unsafe { msg_send![self.m_self(), descriptionWithLocale: locale.m_self() indent: indent] }
228    }
229}
230
231impl<T> INSArray<T> for NSArray<T> {}
232
233impl<T> Default for NSArray<T> {
234    fn default() -> Self {
235        Self::m_new()
236    }
237}
238
239impl<'a, T> IntoIterator for &'a NSArray<T>
240where
241    T: PNSObject + FromId,
242{
243    type Item = T;
244    type IntoIter = Iter<'a, T>;
245
246    fn into_iter(self) -> Self::IntoIter {
247        self.iter()
248    }
249}
250
251impl From<(*const c_char, usize)> for NSArray<UInt8> {
252    fn from((s, i): (*const c_char, usize)) -> Self {
253        let v = unsafe { slice::from_raw_parts(s as *const u8, i) };
254        NSArray::from(v)
255    }
256}
257
258impl<T> From<id> for NSArray<T> {
259    #[allow(clippy::not_unsafe_ptr_arg_deref)]
260    fn from(obj: id) -> Self {
261        unsafe { NSArray::from_id(obj) }
262    }
263}
264
265impl<T> From<&[T]> for NSArray<T>
266where
267    T: PNSObject,
268{
269    fn from(array: &[T]) -> Self {
270        unsafe {
271            let cls: *mut Object = msg_send![class!(NSArray),
272                arrayWithObjects:array.as_ptr()
273                count:array.len()
274            ];
275            NSArray::from(cls)
276        }
277    }
278}
279
280impl<T> From<Vec<T>> for NSArray<T>
281where
282    T: PNSObject,
283{
284    /// Given a set of `Object`s, creates an `Array` that holds them.
285    fn from(objects: Vec<T>) -> Self {
286        unsafe {
287            let cls: id = msg_send![class!(NSArray),
288                arrayWithObjects:objects.as_ptr()
289                count:objects.len()
290            ];
291            NSArray::from(cls)
292        }
293    }
294}
295
296impl From<Vec<i8>> for NSArray<NSNumber> {
297    /// Given a set of `Object`s, creates an `Array` that holds them.
298    fn from(objects: Vec<i8>) -> Self {
299        let objects: Vec<NSNumber> = objects.iter().map(|i| NSNumber::from(*i)).collect();
300        unsafe {
301            let cls: id = msg_send![class!(NSArray),
302                arrayWithObjects:objects.as_ptr()
303                count:objects.len()
304            ];
305            NSArray::from(cls)
306        }
307    }
308}
309
310impl From<Vec<i16>> for NSArray<NSNumber> {
311    /// Given a set of `Object`s, creates an `Array` that holds them.
312    fn from(objects: Vec<i16>) -> Self {
313        let objects: Vec<NSNumber> = objects.iter().map(|i| NSNumber::from(*i)).collect();
314        unsafe {
315            let cls: id = msg_send![class!(NSArray),
316                arrayWithObjects:objects.as_ptr()
317                count:objects.len()
318            ];
319            NSArray::from(cls)
320        }
321    }
322}
323
324impl From<Vec<i32>> for NSArray<NSNumber> {
325    /// Given a set of `Object`s, creates an `Array` that holds them.
326    fn from(objects: Vec<i32>) -> Self {
327        let objects: Vec<NSNumber> = objects.iter().map(|i| NSNumber::from(*i)).collect();
328        unsafe {
329            let cls: id = msg_send![class!(NSArray),
330                arrayWithObjects:objects.as_ptr()
331                count:objects.len()
332            ];
333            NSArray::from(cls)
334        }
335    }
336}
337
338impl From<Vec<i64>> for NSArray<NSNumber> {
339    /// Given a set of `Object`s, creates an `Array` that holds them.
340    fn from(objects: Vec<i64>) -> Self {
341        let objects: Vec<NSNumber> = objects.iter().map(|i| NSNumber::from(*i)).collect();
342        unsafe {
343            let cls: id = msg_send![class!(NSArray),
344                arrayWithObjects:objects.as_ptr()
345                count:objects.len()
346            ];
347            NSArray::from(cls)
348        }
349    }
350}
351
352impl From<Vec<u8>> for NSArray<NSNumber> {
353    /// Given a set of `Object`s, creates an `Array` that holds them.
354    fn from(objects: Vec<u8>) -> Self {
355        let objects: Vec<NSNumber> = objects.iter().map(|i| NSNumber::from(*i)).collect();
356        unsafe {
357            let cls: id = msg_send![class!(NSArray),
358                arrayWithObjects:objects.as_ptr()
359                count:objects.len()
360            ];
361            NSArray::from(cls)
362        }
363    }
364}
365
366impl From<Vec<u16>> for NSArray<NSNumber> {
367    /// Given a set of `Object`s, creates an `Array` that holds them.
368    fn from(objects: Vec<u16>) -> Self {
369        let objects: Vec<NSNumber> = objects.iter().map(|i| NSNumber::from(*i)).collect();
370        unsafe {
371            let cls: id = msg_send![class!(NSArray),
372                arrayWithObjects:objects.as_ptr()
373                count:objects.len()
374            ];
375            NSArray::from(cls)
376        }
377    }
378}
379
380impl From<Vec<u32>> for NSArray<NSNumber> {
381    /// Given a set of `Object`s, creates an `Array` that holds them.
382    fn from(objects: Vec<u32>) -> Self {
383        let objects: Vec<NSNumber> = objects.iter().map(|i| NSNumber::from(*i)).collect();
384        unsafe {
385            let cls: id = msg_send![class!(NSArray),
386                arrayWithObjects:objects.as_ptr()
387                count:objects.len()
388            ];
389            NSArray::from(cls)
390        }
391    }
392}
393
394impl From<Vec<u64>> for NSArray<NSNumber> {
395    /// Given a set of `Object`s, creates an `Array` that holds them.
396    fn from(objects: Vec<u64>) -> Self {
397        let objects: Vec<NSNumber> = objects.iter().map(|i| NSNumber::from(*i)).collect();
398        unsafe {
399            let cls: id = msg_send![class!(NSArray),
400                arrayWithObjects:objects.as_ptr()
401                count:objects.len()
402            ];
403            NSArray::from(cls)
404        }
405    }
406}
407
408impl From<&[u8]> for NSArray<u8> {
409    /// Given a set of `Object`s, creates an `Array` that holds them.
410    fn from(objects: &[u8]) -> Self {
411        unsafe {
412            let cls: id = msg_send![class!(NSArray),
413                arrayWithObjects:objects.as_ptr()
414                count:objects.len()
415            ];
416            NSArray::from(cls)
417        }
418    }
419}
420
421impl From<&[id]> for NSArray<u8> {
422    /// Given a set of `Object`s, creates an `Array` that holds them.
423    fn from(objects: &[id]) -> Self {
424        unsafe {
425            let cls: id = msg_send![class!(NSArray),
426                arrayWithObjects:objects.as_ptr()
427                count:objects.len()
428            ];
429            NSArray::from(cls)
430        }
431    }
432}
433
434impl From<Vec<id>> for NSArray<id> {
435    /// Given a set of `Object`s, creates an `Array` that holds them.
436    fn from(objects: Vec<id>) -> Self {
437        unsafe {
438            let cls: id = msg_send![class!(NSArray),
439                arrayWithObjects:objects.as_ptr()
440                count:objects.len()
441            ];
442            NSArray::from_id(cls)
443        }
444    }
445}
446
447impl From<Vec<&str>> for NSArray<NSString> {
448    fn from(objects: Vec<&str>) -> Self {
449        let objects: Vec<NSString> = objects.iter().map(|s| NSString::from(*s)).collect();
450        unsafe {
451            let cls: id = msg_send![class!(NSArray),
452                arrayWithObjects:objects.as_ptr()
453                count:objects.len()
454            ];
455            NSArray::from(cls)
456        }
457    }
458}
459
460impl From<Vec<String>> for NSArray<NSString> {
461    fn from(objects: Vec<String>) -> Self {
462        let objects: Vec<NSString> = objects.iter().map(|s| NSString::from(s.clone())).collect();
463        unsafe {
464            let cls: id = msg_send![class!(NSArray),
465                arrayWithObjects:objects.as_ptr()
466                count:objects.len()
467            ];
468            NSArray::from(cls)
469        }
470    }
471}
472
473impl<T> From<NSMutableArray<T>> for NSArray<T>
474where
475    T: PNSObject,
476{
477    /// Given an `Array` of `Object`s, creates a new `Array` that holds them.
478    fn from(array: NSMutableArray<T>) -> Self {
479        let cls: id = unsafe {
480            {
481                msg_send![class!(NSArray), arrayWithArray: array]
482            }
483        };
484        NSArray::from(cls)
485    }
486}
487
488#[cfg(test)]
489mod tests {
490    use super::*;
491
492    #[test]
493    fn test_array_from_vec() {
494        let array: NSArray<NSString> = vec!["foo", "bar"].into();
495        assert_eq!(array.count(), 2);
496        assert_eq!(array.m_object_at_index(0), NSString::from("foo"));
497        assert_eq!(array.m_object_at_index(1), NSString::from("bar"));
498    }
499
500    #[test]
501    fn test_first_common_object() {
502        let array: NSArray<NSString> = vec!["foo", "bar"].into();
503        let array2: NSArray<NSString> = vec!["foo", "bar"].into();
504        assert_eq!(
505            array.m_first_object_common_with_array(&array2),
506            Some(NSString::from("foo"))
507        );
508    }
509}