From 9fbb332b38f87ea4b4491dfda253e920b4320026 Mon Sep 17 00:00:00 2001 From: Adam Gastineau Date: Wed, 19 Jul 2023 13:40:51 -0700 Subject: [PATCH] Idiomatic NSArray iteration (#97) --- src/appkit/app/delegate.rs | 12 ++++++----- src/foundation/array.rs | 44 +++++++++++++++++++++++++++----------- src/pasteboard/mod.rs | 2 +- 3 files changed, 40 insertions(+), 18 deletions(-) diff --git a/src/appkit/app/delegate.rs b/src/appkit/app/delegate.rs index b833c46..0e90c2f 100644 --- a/src/appkit/app/delegate.rs +++ b/src/appkit/app/delegate.rs @@ -187,13 +187,12 @@ extern "C" fn accepted_cloudkit_share(this: &Object, _: Sel, _: /// Fires when the application receives an `application:openURLs` message. extern "C" fn open_urls(this: &Object, _: Sel, _: id, file_urls: id) { let urls = NSArray::retain(file_urls) - .map(|url| { + .iter() + .filter_map(|url| { 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(); app::(this).open_urls(urls); @@ -263,7 +262,10 @@ extern "C" fn print_files( settings: id, show_print_panels: BOOL ) -> 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); diff --git a/src/foundation/array.rs b/src/foundation/array.rs index cbeb772..800156c 100644 --- a/src/foundation/array.rs +++ b/src/foundation/array.rs @@ -41,21 +41,41 @@ impl NSArray { unsafe { msg_send![&*self.0, count] } } - /// A helper method for mapping over the backing `NSArray` items and producing a Rust `Vec`. - /// Often times we need to map in this framework to convert between Rust types, so isolating - /// this out makes life much easier. - pub fn map T>(&self, transform: F) -> Vec { - let count = self.count(); - let objc = &*self.0; + /// Returns an iterator over the `NSArray` + pub fn iter<'a>(&'a self) -> NSArrayIterator<'a> { + NSArrayIterator { + next_index: 0, + count: self.count(), + 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 { // 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. - (0..count) - .map(|index| { - let item: id = unsafe { msg_send![objc, objectAtIndex: index] }; - transform(item) - }) - .collect() + if self.next_index < self.count { + let objc = &*self.array.0; + let index = self.next_index; + + let item: id = unsafe { msg_send![objc, objectAtIndex: index] }; + + self.next_index += 1; + Some(item) + } else { + None + } } } diff --git a/src/pasteboard/mod.rs b/src/pasteboard/mod.rs index c15764c..3847ff4 100644 --- a/src/pasteboard/mod.rs +++ b/src/pasteboard/mod.rs @@ -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) }