Skip to content

Commit 669352b

Browse files
committed
TMP improve NSEnumerator
TMP TMP2 TMP3 TMP Fix Complete somewhat Add explicit lifetime bounds on iterators To help catch possible soundness mistakes in the future. Fixes
1 parent de30882 commit 669352b

File tree

20 files changed

+1290
-334
lines changed

20 files changed

+1290
-334
lines changed

crates/header-translator/src/data/Foundation.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,28 @@ data! {
1212
unsafe -removeAllObjects;
1313
}
1414

15+
// SAFETY: `NSEnumerator` and subclasses are safe as mutable because even
16+
// though the items it contains are not mutable, the enumerator itself is
17+
// (and it is important that the methods below are marked `&mut` as well).
18+
//
19+
// However, instances of this are only safe for others to create if
20+
// they're ready to pass ownership to the enumerator, or if they somehow
21+
// add a lifetime parameter (to prevent the original collection from
22+
// being modified).
23+
//
24+
// So e.g. `Id<NSArray<T>> -> Id<NSEnumerator<T>>` is safe, as is
25+
// `&Id<NSArray<T: IsCloneable>> -> Id<NSEnumerator<T>>`, and so is
26+
// `&'a NSArray<T: IsCloneable> -> Id<NSEnumerator<T>> + 'a`.
27+
class NSEnumerator: Mutable {
28+
// SAFETY: This removes the object from the internal collection, so it
29+
// may safely return `Id<T>`.
30+
unsafe -nextObject;
31+
// SAFETY: The objects are removed from the internal collection and as
32+
// such are safe to give ownership over.
33+
unsafe -allObjects;
34+
}
35+
class NSDirectoryEnumerator: Mutable {}
36+
1537
class NSString: ImmutableWithMutableSubclass<Foundation::NSMutableString> {
1638
unsafe -init;
1739
unsafe -compare;

crates/header-translator/translation-config.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -574,6 +574,10 @@ skipped = true
574574
[struct.NSDecimal]
575575
skipped = true
576576

577+
# Uses `c_ulong` which means we need to specify the encoding manually.
578+
[struct.NSFastEnumerationState]
579+
skipped = true
580+
577581
# Uses stuff from core Darwin libraries which we have not yet mapped
578582
[class.NSAppleEventDescriptor.methods]
579583
descriptorWithDescriptorType_bytes_length = { skipped = true }
@@ -1551,6 +1555,8 @@ definition-skipped = true
15511555
definition-skipped = true
15521556
[class.NSMutableOrderedSet]
15531557
definition-skipped = true
1558+
[class.NSEnumerator]
1559+
definition-skipped = true
15541560

15551561
# These protocol impls would return the wrong types
15561562
[class.NSSimpleCString]

crates/icrate/src/Foundation/additions/array.rs

Lines changed: 95 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1+
//! Utilities for the `NSArray` and `NSMutableArray` classes.
12
#![cfg(feature = "Foundation_NSArray")]
23
use alloc::vec::Vec;
34
use core::fmt;
45
use core::mem;
56
use core::ops::{Index, IndexMut, Range};
67
use core::panic::{RefUnwindSafe, UnwindSafe};
78

8-
use objc2::msg_send;
99
use objc2::mutability::{IsMutable, IsRetainable};
1010

11+
use super::iter;
1112
use super::util;
1213
use crate::common::*;
1314
#[cfg(feature = "Foundation_NSMutableArray")]
@@ -220,15 +221,6 @@ extern_methods!(
220221
);
221222

222223
impl<T: Message> NSArray<T> {
223-
#[doc(alias = "objectEnumerator")]
224-
#[cfg(feature = "Foundation_NSEnumerator")]
225-
pub fn iter(&self) -> Foundation::NSEnumerator2<'_, T> {
226-
unsafe {
227-
let result: *mut Object = msg_send![self, objectEnumerator];
228-
Foundation::NSEnumerator2::from_ptr(result)
229-
}
230-
}
231-
232224
unsafe fn objects_in_range_unchecked(&self, range: Range<usize>) -> Vec<&T> {
233225
let range = Foundation::NSRange::from(range);
234226
let mut vec: Vec<NonNull<T>> = Vec::with_capacity(range.length);
@@ -340,33 +332,109 @@ impl<T: Message> NSMutableArray<T> {
340332
}
341333
}
342334

343-
unsafe impl<T: Message> Foundation::NSFastEnumeration2 for NSArray<T> {
335+
impl<T: Message> NSArray<T> {
336+
#[doc(alias = "objectEnumerator")]
337+
#[inline]
338+
pub fn iter(&self) -> Iter<'_, T> {
339+
Iter(super::iter::Iter::new(self))
340+
}
341+
342+
#[doc(alias = "objectEnumerator")]
343+
#[inline]
344+
pub fn iter_mut(&mut self) -> IterMut<'_, T>
345+
where
346+
T: IsMutable,
347+
{
348+
IterMut(super::iter::IterMut::new(self))
349+
}
350+
351+
#[doc(alias = "objectEnumerator")]
352+
#[inline]
353+
pub fn iter_retained(&self) -> IterRetained<'_, T>
354+
where
355+
T: IsIdCloneable,
356+
{
357+
IterRetained(super::iter::IterRetained::new(self))
358+
}
359+
}
360+
361+
unsafe impl<T: Message> iter::FastEnumerationHelper for NSArray<T> {
344362
type Item = T;
363+
364+
#[inline]
365+
fn maybe_len(&self) -> Option<usize> {
366+
Some(self.len())
367+
}
345368
}
346369

347370
#[cfg(feature = "Foundation_NSMutableArray")]
348-
unsafe impl<T: Message> Foundation::NSFastEnumeration2 for NSMutableArray<T> {
371+
unsafe impl<T: Message> iter::FastEnumerationHelper for NSMutableArray<T> {
349372
type Item = T;
373+
374+
#[inline]
375+
fn maybe_len(&self) -> Option<usize> {
376+
Some(self.len())
377+
}
350378
}
351379

352-
impl<'a, T: Message> IntoIterator for &'a NSArray<T> {
353-
type Item = &'a T;
354-
type IntoIter = Foundation::NSFastEnumerator2<'a, NSArray<T>>;
380+
/// Immutable `NSArray` iterator.
381+
#[derive(Debug)]
382+
pub struct Iter<'a, T: Message>(iter::Iter<'a, NSArray<T>>);
355383

356-
fn into_iter(self) -> Self::IntoIter {
357-
use Foundation::NSFastEnumeration2;
358-
self.iter_fast()
359-
}
384+
__impl_iter! {
385+
impl<'a, T: Message> Iterator<Item = &'a T> for Iter<'a, T> { ... }
360386
}
361387

362-
#[cfg(feature = "Foundation_NSMutableArray")]
363-
impl<'a, T: Message> IntoIterator for &'a NSMutableArray<T> {
364-
type Item = &'a T;
365-
type IntoIter = Foundation::NSFastEnumerator2<'a, NSMutableArray<T>>;
388+
/// Mutable `NSArray` iterator.
389+
#[derive(Debug)]
390+
pub struct IterMut<'a, T: Message>(iter::IterMut<'a, NSArray<T>>);
391+
392+
__impl_iter! {
393+
impl<'a, T: IsMutable> Iterator<Item = &'a mut T> for IterMut<'a, T> { ... }
394+
}
395+
396+
/// Retained `NSArray` iterator.
397+
#[derive(Debug)]
398+
pub struct IterRetained<'a, T: Message>(iter::IterRetained<'a, NSArray<T>>);
399+
400+
__impl_iter! {
401+
impl<'a, T: IsIdCloneable> Iterator<Item = Id<T>> for IterRetained<'a, T> { ... }
402+
}
403+
404+
/// Consuming `NSArray` iterator.
405+
#[derive(Debug)]
406+
pub struct IntoIter<T: Message>(iter::IntoIter<NSArray<T>>);
407+
408+
__impl_iter! {
409+
impl<'a, T: Message> Iterator<Item = Id<T>> for IntoIter<T> { ... }
410+
}
411+
412+
__impl_into_iter! {
413+
impl<T: Message> IntoIterator for &NSArray<T> {
414+
type IntoIter = Iter<'_, T>;
415+
}
416+
417+
#[cfg(feature = "Foundation_NSMutableArray")]
418+
impl<T: Message> IntoIterator for &NSMutableArray<T> {
419+
type IntoIter = Iter<'_, T>;
420+
}
421+
422+
impl<T: IsMutable> IntoIterator for &mut NSArray<T> {
423+
type IntoIter = IterMut<'_, T>;
424+
}
425+
426+
#[cfg(feature = "Foundation_NSMutableArray")]
427+
impl<T: IsMutable> IntoIterator for &mut NSMutableArray<T> {
428+
type IntoIter = IterMut<'_, T>;
429+
}
430+
431+
impl<T: IsIdCloneable> IntoIterator for Id<NSArray<T>> {
432+
type IntoIter = IntoIter<T>;
433+
}
366434

367-
fn into_iter(self) -> Self::IntoIter {
368-
use Foundation::NSFastEnumeration2;
369-
self.iter_fast()
435+
#[cfg(feature = "Foundation_NSMutableArray")]
436+
impl<T: Message> IntoIterator for Id<NSMutableArray<T>> {
437+
type IntoIter = IntoIter<T>;
370438
}
371439
}
372440

@@ -403,8 +471,7 @@ impl<T: IsMutable> IndexMut<usize> for NSMutableArray<T> {
403471
impl<T: fmt::Debug + Message> fmt::Debug for NSArray<T> {
404472
#[inline]
405473
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
406-
use Foundation::NSFastEnumeration2;
407-
f.debug_list().entries(self.iter_fast()).finish()
474+
f.debug_list().entries(self).finish()
408475
}
409476
}
410477

0 commit comments

Comments
 (0)