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, number(&self) -> u3215 Descending = 1, 16 } 17 18 impl 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 } class() -> &'static Class35 36 #[repr(C)] 37 #[derive(Clone, Copy)] 38 pub struct NSRange { 39 pub location: usize, 40 pub length: usize, 41 } my_object_set_number(this: &mut Object, _cmd: Sel, number: u32)42 43 impl 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 54 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; main()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 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 { 168 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 194 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 { 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 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 { 281 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 311 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 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 } 442