1 use std::cmp::Ordering;
2 use std::marker::PhantomData;
3 use std::ops::{Index, Range};
4
5 use objc::runtime::{Class, Object};
6 use objc_id::{Id, Owned, Ownership, Shared, ShareId};
7
8 use {INSCopying, INSFastEnumeration, INSMutableCopying, INSObject, NSEnumerator};
9
10 #[repr(isize)]
11 #[derive(Clone, Copy)]
12 pub enum NSComparisonResult {
13 Ascending = -1,
14 Same = 0,
15 Descending = 1,
16 }
17
18 impl NSComparisonResult {
from_ordering(order: Ordering) -> NSComparisonResult19 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
as_ordering(&self) -> Ordering27 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)]
38 pub struct NSRange {
39 pub location: usize,
40 pub length: usize,
41 }
42
43 impl NSRange {
from_range(range: Range<usize>) -> NSRange44 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
as_range(&self) -> Range<usize>49 pub fn as_range(&self) -> Range<usize> {
50 Range { start: self.location, end: self.location + self.length }
51 }
52 }
53
from_refs<A>(refs: &[&A::Item]) -> Id<A> where A: INSArray54 unsafe 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
62 pub trait INSArray : INSObject {
63 type Item: INSObject;
64 type Own: Ownership;
65
count(&self) -> usize66 fn count(&self) -> usize {
67 unsafe {
68 msg_send![self, count]
69 }
70 }
71
object_at(&self, index: usize) -> &Self::Item72 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
first_object(&self) -> Option<&Self::Item>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
last_object(&self) -> Option<&Self::Item>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
object_enumerator(&self) -> NSEnumerator<Self::Item>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
from_vec(vec: Vec<Id<Self::Item, Self::Own>>) -> Id<Self>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
objects_in_range(&self, range: Range<usize>) -> Vec<&Self::Item>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
to_vec(&self) -> Vec<&Self::Item>117 fn to_vec(&self) -> Vec<&Self::Item> {
118 self.objects_in_range(0..self.count())
119 }
120
into_vec(array: Id<Self>) -> Vec<Id<Self::Item, Self::Own>>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
mut_object_at(&mut self, index: usize) -> &mut Self::Item where Self: INSArray<Own=Owned>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
shared_object_at(&self, index: usize) -> ShareId<Self::Item> where Self: INSArray<Own=Shared>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
from_slice(slice: &[ShareId<Self::Item>]) -> Id<Self> where Self: INSArray<Own=Shared>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
to_shared_vec(&self) -> Vec<ShareId<Self::Item>> where Self: INSArray<Own=Shared>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
161 pub struct NSArray<T, O = Owned> {
162 item: PhantomData<Id<T, O>>,
163 }
164
165 object_impl!(NSArray<T, O>);
166
167 impl<T, O> INSObject for NSArray<T, O> where T: INSObject, O: Ownership {
class() -> &'static Class168 fn class() -> &'static Class {
169 Class::get("NSArray").unwrap()
170 }
171 }
172
173 impl<T, O> INSArray for NSArray<T, O> where T: INSObject, O: Ownership {
174 type Item = T;
175 type Own = O;
176 }
177
178 impl<T> INSCopying for NSArray<T, Shared> where T: INSObject {
179 type Output = NSSharedArray<T>;
180 }
181
182 impl<T> INSMutableCopying for NSArray<T, Shared> where T: INSObject {
183 type Output = NSMutableSharedArray<T>;
184 }
185
186 impl<T, O> INSFastEnumeration for NSArray<T, O>
187 where T: INSObject, O: Ownership {
188 type Item = T;
189 }
190
191 impl<T, O> Index<usize> for NSArray<T, O> where T: INSObject, O: Ownership {
192 type Output = T;
193
index(&self, index: usize) -> &T194 fn index(&self, index: usize) -> &T {
195 self.object_at(index)
196 }
197 }
198
199 pub type NSSharedArray<T> = NSArray<T, Shared>;
200
201 pub trait INSMutableArray : INSArray {
add_object(&mut self, obj: Id<Self::Item, Self::Own>)202 fn add_object(&mut self, obj: Id<Self::Item, Self::Own>) {
203 unsafe {
204 let _: () = msg_send![self, addObject:&*obj];
205 }
206 }
207
insert_object_at(&mut self, index: usize, obj: Id<Self::Item, Self::Own>)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
replace_object_at(&mut self, index: usize, obj: Id<Self::Item, Self::Own>) -> Id<Self::Item, Self::Own>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
remove_object_at(&mut self, index: usize) -> Id<Self::Item, Self::Own>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
remove_last_object(&mut self) -> Id<Self::Item, Self::Own>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
remove_all_objects(&mut self)250 fn remove_all_objects(&mut self) {
251 unsafe {
252 let _: () = msg_send![self, removeAllObjects];
253 }
254 }
255
sort_by<F>(&mut self, compare: F) where F: FnMut(&Self::Item, &Self::Item) -> Ordering256 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
274 pub struct NSMutableArray<T, O = Owned> {
275 item: PhantomData<Id<T, O>>,
276 }
277
278 object_impl!(NSMutableArray<T, O>);
279
280 impl<T, O> INSObject for NSMutableArray<T, O> where T: INSObject, O: Ownership {
class() -> &'static Class281 fn class() -> &'static Class {
282 Class::get("NSMutableArray").unwrap()
283 }
284 }
285
286 impl<T, O> INSArray for NSMutableArray<T, O> where T: INSObject, O: Ownership {
287 type Item = T;
288 type Own = O;
289 }
290
291 impl<T, O> INSMutableArray for NSMutableArray<T, O>
292 where T: INSObject, O: Ownership { }
293
294 impl<T> INSCopying for NSMutableArray<T, Shared> where T: INSObject {
295 type Output = NSSharedArray<T>;
296 }
297
298 impl<T> INSMutableCopying for NSMutableArray<T, Shared> where T: INSObject {
299 type Output = NSMutableSharedArray<T>;
300 }
301
302 impl<T, O> INSFastEnumeration for NSMutableArray<T, O>
303 where T: INSObject, O: Ownership {
304 type Item = T;
305 }
306
307 impl<T, O> Index<usize> for NSMutableArray<T, O>
308 where T: INSObject, O: Ownership {
309 type Output = T;
310
index(&self, index: usize) -> &T311 fn index(&self, index: usize) -> &T {
312 self.object_at(index)
313 }
314 }
315
316 pub type NSMutableSharedArray<T> = NSMutableArray<T, Shared>;
317
318 #[cfg(test)]
319 mod tests {
320 use objc_id::Id;
321 use {INSObject, INSString, NSObject, NSString};
322 use super::{INSArray, INSMutableArray, NSArray, NSMutableArray};
323
sample_array(len: usize) -> Id<NSArray<NSObject>>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]
test_count()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]
test_object_at()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]
test_object_enumerator()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]
test_objects_in_range()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]
test_into_vec()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]
test_add_object()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]
test_replace_object()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]
test_remove_object()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]
test_sort()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 }
442