objc_foundation/
array.rs

1use std::cmp::Ordering;
2use std::marker::PhantomData;
3use std::ops::{Index, Range};
4
5use objc::runtime::{Class, Object};
6use objc_id::{Id, Owned, Ownership, Shared, ShareId};
7
8use {INSCopying, INSFastEnumeration, INSMutableCopying, INSObject, NSEnumerator};
9
10#[repr(isize)]
11#[derive(Clone, Copy)]
12pub enum NSComparisonResult {
13    Ascending  = -1,
14    Same       = 0,
15    Descending = 1,
16}
17
18impl NSComparisonResult {
19    pub fn from_ordering(order: Ordering) -> NSComparisonResult {
20        match order {
21            Ordering::Less => NSComparisonResult::Ascending,
22            Ordering::Equal => NSComparisonResult::Same,
23            Ordering::Greater => NSComparisonResult::Descending,
24        }
25    }
26
27    pub fn as_ordering(&self) -> Ordering {
28        match *self {
29            NSComparisonResult::Ascending => Ordering::Less,
30            NSComparisonResult::Same => Ordering::Equal,
31            NSComparisonResult::Descending => Ordering::Greater,
32        }
33    }
34}
35
36#[repr(C)]
37#[derive(Clone, Copy)]
38pub struct NSRange {
39    pub location: usize,
40    pub length: usize,
41}
42
43impl NSRange {
44    pub fn from_range(range: Range<usize>) -> NSRange {
45        assert!(range.end >= range.start);
46        NSRange { location: range.start, length: range.end - range.start }
47    }
48
49    pub fn as_range(&self) -> Range<usize> {
50        Range { start: self.location, end: self.location + self.length }
51    }
52}
53
54unsafe fn from_refs<A>(refs: &[&A::Item]) -> Id<A> where A: INSArray {
55    let cls = A::class();
56    let obj: *mut A = msg_send![cls, alloc];
57    let obj: *mut A = msg_send![obj, initWithObjects:refs.as_ptr()
58                                               count:refs.len()];
59    Id::from_retained_ptr(obj)
60}
61
62pub trait INSArray : INSObject {
63    type Item: INSObject;
64    type Own: Ownership;
65
66    fn count(&self) -> usize {
67        unsafe {
68            msg_send![self, count]
69        }
70    }
71
72    fn object_at(&self, index: usize) -> &Self::Item {
73        unsafe {
74            let obj: *const Self::Item = msg_send![self, objectAtIndex:index];
75            &*obj
76        }
77    }
78
79    fn first_object(&self) -> Option<&Self::Item> {
80        unsafe {
81            let obj: *const Self::Item = msg_send![self, firstObject];
82            if obj.is_null() { None } else { Some(&*obj) }
83        }
84    }
85
86    fn last_object(&self) -> Option<&Self::Item> {
87        unsafe {
88            let obj: *const Self::Item = msg_send![self, lastObject];
89            if obj.is_null() { None } else { Some(&*obj) }
90        }
91    }
92
93    fn object_enumerator(&self) -> NSEnumerator<Self::Item> {
94        unsafe {
95            let result: *mut Object = msg_send![self, objectEnumerator];
96            NSEnumerator::from_ptr(result)
97        }
98    }
99
100    fn from_vec(vec: Vec<Id<Self::Item, Self::Own>>) -> Id<Self> {
101        let refs: Vec<&Self::Item> = vec.iter().map(|obj| &**obj).collect();
102        unsafe {
103            from_refs(&refs)
104        }
105    }
106
107    fn objects_in_range(&self, range: Range<usize>) -> Vec<&Self::Item> {
108        let range = NSRange::from_range(range);
109        let mut vec = Vec::with_capacity(range.length);
110        unsafe {
111            let _: () = msg_send![self, getObjects:vec.as_ptr() range:range];
112            vec.set_len(range.length);
113        }
114        vec
115    }
116
117    fn to_vec(&self) -> Vec<&Self::Item> {
118        self.objects_in_range(0..self.count())
119    }
120
121    fn into_vec(array: Id<Self>) -> Vec<Id<Self::Item, Self::Own>> {
122        array.to_vec().into_iter().map(|obj| unsafe {
123            let obj_ptr: *const Self::Item = obj;
124            Id::from_ptr(obj_ptr as *mut Self::Item)
125        }).collect()
126    }
127
128    fn mut_object_at(&mut self, index: usize) -> &mut Self::Item
129            where Self: INSArray<Own=Owned> {
130        unsafe {
131            let result: *mut Self::Item = msg_send![self, objectAtIndex:index];
132            &mut *result
133        }
134    }
135
136    fn shared_object_at(&self, index: usize) -> ShareId<Self::Item>
137            where Self: INSArray<Own=Shared> {
138        let obj = self.object_at(index);
139        unsafe {
140            Id::from_ptr(obj as *const _ as *mut Self::Item)
141        }
142    }
143
144    fn from_slice(slice: &[ShareId<Self::Item>]) -> Id<Self>
145            where Self: INSArray<Own=Shared> {
146        let refs: Vec<&Self::Item> = slice.iter().map(|obj| &**obj).collect();
147        unsafe {
148            from_refs(&refs)
149        }
150    }
151
152    fn to_shared_vec(&self) -> Vec<ShareId<Self::Item>>
153            where Self: INSArray<Own=Shared> {
154        self.to_vec().into_iter().map(|obj| unsafe {
155            let obj_ptr: *const Self::Item = obj;
156            Id::from_ptr(obj_ptr as *mut Self::Item)
157        }).collect()
158    }
159}
160
161pub struct NSArray<T, O = Owned> {
162    item: PhantomData<Id<T, O>>,
163}
164
165object_impl!(NSArray<T, O>);
166
167impl<T, O> INSObject for NSArray<T, O> where T: INSObject, O: Ownership {
168    fn class() -> &'static Class {
169        Class::get("NSArray").unwrap()
170    }
171}
172
173impl<T, O> INSArray for NSArray<T, O> where T: INSObject, O: Ownership {
174    type Item = T;
175    type Own = O;
176}
177
178impl<T> INSCopying for NSArray<T, Shared> where T: INSObject {
179    type Output = NSSharedArray<T>;
180}
181
182impl<T> INSMutableCopying for NSArray<T, Shared> where T: INSObject {
183    type Output = NSMutableSharedArray<T>;
184}
185
186impl<T, O> INSFastEnumeration for NSArray<T, O>
187        where T: INSObject, O: Ownership {
188    type Item = T;
189}
190
191impl<T, O> Index<usize> for NSArray<T, O> where T: INSObject, O: Ownership {
192    type Output = T;
193
194    fn index(&self, index: usize) -> &T {
195        self.object_at(index)
196    }
197}
198
199pub type NSSharedArray<T> = NSArray<T, Shared>;
200
201pub trait INSMutableArray : INSArray {
202    fn add_object(&mut self, obj: Id<Self::Item, Self::Own>) {
203        unsafe {
204            let _: () = msg_send![self, addObject:&*obj];
205        }
206    }
207
208    fn insert_object_at(&mut self, index: usize, obj: Id<Self::Item, Self::Own>) {
209        unsafe {
210            let _: () = msg_send![self, insertObject:&*obj atIndex:index];
211        }
212    }
213
214    fn replace_object_at(&mut self, index: usize, obj: Id<Self::Item, Self::Own>) ->
215            Id<Self::Item, Self::Own> {
216        let old_obj = unsafe {
217            let obj = self.object_at(index);
218            Id::from_ptr(obj as *const _ as *mut Self::Item)
219        };
220        unsafe {
221            let _: () = msg_send![self, replaceObjectAtIndex:index
222                                                  withObject:&*obj];
223        }
224        old_obj
225    }
226
227    fn remove_object_at(&mut self, index: usize) -> Id<Self::Item, Self::Own> {
228        let obj = unsafe {
229            let obj = self.object_at(index);
230            Id::from_ptr(obj as *const _ as *mut Self::Item)
231        };
232        unsafe {
233            let _: () = msg_send![self, removeObjectAtIndex:index];
234        }
235        obj
236    }
237
238    fn remove_last_object(&mut self) -> Id<Self::Item, Self::Own> {
239        let obj = self.last_object().map(|obj| unsafe {
240            Id::from_ptr(obj as *const _ as *mut Self::Item)
241        });
242        unsafe {
243            let _: () = msg_send![self, removeLastObject];
244        }
245        // removeLastObject would have failed if the array is empty,
246        // so we know this won't be None
247        obj.unwrap()
248    }
249
250    fn remove_all_objects(&mut self) {
251        unsafe {
252            let _: () = msg_send![self, removeAllObjects];
253        }
254    }
255
256    fn sort_by<F>(&mut self, compare: F)
257            where F: FnMut(&Self::Item, &Self::Item) -> Ordering {
258        extern fn compare_with_closure<T, F>(obj1: &T, obj2: &T,
259                compare: &mut F) -> NSComparisonResult
260                where F: FnMut(&T, &T) -> Ordering {
261            NSComparisonResult::from_ordering((*compare)(obj1, obj2))
262        }
263
264        let f: extern fn(&Self::Item, &Self::Item, &mut F) -> NSComparisonResult =
265            compare_with_closure;
266        let mut closure = compare;
267        unsafe {
268            let _: () = msg_send![self, sortUsingFunction:f
269                                                  context:&mut closure];
270        }
271    }
272}
273
274pub struct NSMutableArray<T, O = Owned> {
275    item: PhantomData<Id<T, O>>,
276}
277
278object_impl!(NSMutableArray<T, O>);
279
280impl<T, O> INSObject for NSMutableArray<T, O> where T: INSObject, O: Ownership {
281    fn class() -> &'static Class {
282        Class::get("NSMutableArray").unwrap()
283    }
284}
285
286impl<T, O> INSArray for NSMutableArray<T, O> where T: INSObject, O: Ownership {
287    type Item = T;
288    type Own = O;
289}
290
291impl<T, O> INSMutableArray for NSMutableArray<T, O>
292        where T: INSObject, O: Ownership { }
293
294impl<T> INSCopying for NSMutableArray<T, Shared> where T: INSObject {
295    type Output = NSSharedArray<T>;
296}
297
298impl<T> INSMutableCopying for NSMutableArray<T, Shared> where T: INSObject {
299    type Output = NSMutableSharedArray<T>;
300}
301
302impl<T, O> INSFastEnumeration for NSMutableArray<T, O>
303        where T: INSObject, O: Ownership {
304    type Item = T;
305}
306
307impl<T, O> Index<usize> for NSMutableArray<T, O>
308        where T: INSObject, O: Ownership {
309    type Output = T;
310
311    fn index(&self, index: usize) -> &T {
312        self.object_at(index)
313    }
314}
315
316pub type NSMutableSharedArray<T> = NSMutableArray<T, Shared>;
317
318#[cfg(test)]
319mod tests {
320    use objc_id::Id;
321    use {INSObject, INSString, NSObject, NSString};
322    use super::{INSArray, INSMutableArray, NSArray, NSMutableArray};
323
324    fn sample_array(len: usize) -> Id<NSArray<NSObject>> {
325        let mut vec = Vec::with_capacity(len);
326        for _ in 0..len {
327            vec.push(NSObject::new());
328        }
329        NSArray::from_vec(vec)
330    }
331
332    #[test]
333    fn test_count() {
334        let empty_array = NSArray::<NSObject>::new();
335        assert!(empty_array.count() == 0);
336
337        let array = sample_array(4);
338        assert!(array.count() == 4);
339    }
340
341    #[test]
342    fn test_object_at() {
343        let array = sample_array(4);
344        assert!(array.object_at(0) != array.object_at(3));
345        assert!(array.first_object().unwrap() == array.object_at(0));
346        assert!(array.last_object().unwrap() == array.object_at(3));
347
348        let empty_array: Id<NSArray<NSObject>> = INSObject::new();
349        assert!(empty_array.first_object().is_none());
350        assert!(empty_array.last_object().is_none());
351    }
352
353    #[test]
354    fn test_object_enumerator() {
355        let array = sample_array(4);
356
357        assert!(array.object_enumerator().count() == 4);
358        assert!(array.object_enumerator()
359                     .enumerate()
360                     .all(|(i, obj)| obj == array.object_at(i)));
361    }
362
363    #[test]
364    fn test_objects_in_range() {
365        let array = sample_array(4);
366
367        let middle_objs = array.objects_in_range(1..3);
368        assert!(middle_objs.len() == 2);
369        assert!(middle_objs[0] == array.object_at(1));
370        assert!(middle_objs[1] == array.object_at(2));
371
372        let empty_objs = array.objects_in_range(1..1);
373        assert!(empty_objs.len() == 0);
374
375        let all_objs = array.objects_in_range(0..4);
376        assert!(all_objs.len() == 4);
377    }
378
379    #[test]
380    fn test_into_vec() {
381        let array = sample_array(4);
382
383        let vec = INSArray::into_vec(array);
384        assert!(vec.len() == 4);
385    }
386
387    #[test]
388    fn test_add_object() {
389        let mut array = NSMutableArray::new();
390        let obj = NSObject::new();
391        array.add_object(obj);
392
393        assert!(array.count() == 1);
394        assert!(array.object_at(0) == array.object_at(0));
395
396        let obj = NSObject::new();
397        array.insert_object_at(0, obj);
398        assert!(array.count() == 2);
399    }
400
401    #[test]
402    fn test_replace_object() {
403        let mut array = NSMutableArray::new();
404        let obj = NSObject::new();
405        array.add_object(obj);
406
407        let obj = NSObject::new();
408        let old_obj = array.replace_object_at(0, obj);
409        assert!(&*old_obj != array.object_at(0));
410    }
411
412    #[test]
413    fn test_remove_object() {
414        let mut array = NSMutableArray::new();
415        for _ in 0..4 {
416            array.add_object(NSObject::new());
417        }
418
419        array.remove_object_at(1);
420        assert!(array.count() == 3);
421
422        array.remove_last_object();
423        assert!(array.count() == 2);
424
425        array.remove_all_objects();
426        assert!(array.count() == 0);
427    }
428
429    #[test]
430    fn test_sort() {
431        let strings = vec![
432            NSString::from_str("hello"),
433            NSString::from_str("hi"),
434        ];
435        let mut strings = NSMutableArray::from_vec(strings);
436
437        strings.sort_by(|s1, s2| s1.as_str().len().cmp(&s2.as_str().len()));
438        assert!(strings[0].as_str() == "hi");
439        assert!(strings[1].as_str() == "hello");
440    }
441}