Idiomatic NSArray iteration (#97)

This commit is contained in:
Adam Gastineau 2023-07-19 13:40:51 -07:00 committed by GitHub
parent 01507f7642
commit 9fbb332b38
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 40 additions and 18 deletions

View file

@ -187,13 +187,12 @@ extern "C" fn accepted_cloudkit_share<T: AppDelegate>(this: &Object, _: Sel, _:
/// Fires when the application receives an `application:openURLs` message. /// Fires when the application receives an `application:openURLs` message.
extern "C" fn open_urls<T: AppDelegate>(this: &Object, _: Sel, _: id, file_urls: id) { extern "C" fn open_urls<T: AppDelegate>(this: &Object, _: Sel, _: id, file_urls: id) {
let urls = NSArray::retain(file_urls) let urls = NSArray::retain(file_urls)
.map(|url| { .iter()
.filter_map(|url| {
let uri = NSString::retain(unsafe { msg_send![url, absoluteString] }); let uri = NSString::retain(unsafe { msg_send![url, absoluteString] });
Url::parse(uri.to_str()) Url::parse(uri.to_str()).ok()
}) })
.into_iter()
.filter_map(|url| url.ok())
.collect(); .collect();
app::<T>(this).open_urls(urls); app::<T>(this).open_urls(urls);
@ -263,7 +262,10 @@ extern "C" fn print_files<T: AppDelegate>(
settings: id, settings: id,
show_print_panels: BOOL show_print_panels: BOOL
) -> NSUInteger { ) -> NSUInteger {
let files = NSArray::retain(files).map(|file| NSString::retain(file).to_str().to_string()); let files = NSArray::retain(files)
.iter()
.map(|file| NSString::retain(file).to_str().to_string())
.collect();
let settings = PrintSettings::with_inner(settings); let settings = PrintSettings::with_inner(settings);

View file

@ -41,21 +41,41 @@ impl NSArray {
unsafe { msg_send![&*self.0, count] } unsafe { msg_send![&*self.0, count] }
} }
/// A helper method for mapping over the backing `NSArray` items and producing a Rust `Vec<T>`. /// Returns an iterator over the `NSArray`
/// Often times we need to map in this framework to convert between Rust types, so isolating pub fn iter<'a>(&'a self) -> NSArrayIterator<'a> {
/// this out makes life much easier. NSArrayIterator {
pub fn map<T, F: Fn(id) -> T>(&self, transform: F) -> Vec<T> { next_index: 0,
let count = self.count(); count: self.count(),
let objc = &*self.0; array: self
}
}
}
#[derive(Debug)]
pub struct NSArrayIterator<'a> {
next_index: usize,
count: usize,
array: &'a NSArray
}
impl Iterator for NSArrayIterator<'_> {
type Item = id;
fn next(&mut self) -> Option<Self::Item> {
// I don't know if it's worth trying to get in with NSFastEnumeration here. I'm content to // I don't know if it's worth trying to get in with NSFastEnumeration here. I'm content to
// just rely on Rust, but someone is free to profile it if they want. // just rely on Rust, but someone is free to profile it if they want.
(0..count) if self.next_index < self.count {
.map(|index| { let objc = &*self.array.0;
let index = self.next_index;
let item: id = unsafe { msg_send![objc, objectAtIndex: index] }; let item: id = unsafe { msg_send![objc, objectAtIndex: index] };
transform(item)
}) self.next_index += 1;
.collect() Some(item)
} else {
None
}
} }
} }

View file

@ -106,7 +106,7 @@ impl Pasteboard {
})); }));
} }
let urls = NSArray::retain(contents).map(|url| NSURL::retain(url)).into_iter().collect(); let urls = NSArray::retain(contents).iter().map(|url| NSURL::retain(url)).collect();
Ok(urls) Ok(urls)
} }