1
1
//! Helper traits for Id.
2
2
3
3
use super :: Id ;
4
- use crate :: mutability:: IsAllocableAnyThread ;
4
+ use crate :: mutability:: { IsAllocableAnyThread , IsMutable } ;
5
5
6
6
/// Helper trait to implement [`Default`] on [`Id`].
7
7
// TODO: Maybe make this `unsafe` and provide a default implementation?
@@ -19,3 +19,192 @@ impl<T: ?Sized + DefaultId> Default for Id<T> {
19
19
T :: default_id ( )
20
20
}
21
21
}
22
+
23
+ /// Helper trait to implement [`IntoIterator`] on [`Id`].
24
+ ///
25
+ /// This should be implemented in exactly the same fashion as if you were
26
+ /// implementing `IntoIterator` for your type normally.
27
+ //
28
+ // Note that [`Box<T>` gets to cheat with regards moves][box-move], so
29
+ // `boxed.into_iter()` is possible, while `id.into_iter()` is not possible
30
+ // without this helper trait.
31
+ //
32
+ // [box-move]: https://doc.rust-lang.org/reference/expressions.html#moved-and-copied-types
33
+ pub trait IdIntoIterator {
34
+ /// The type of the elements being iterated over.
35
+ type Item ;
36
+
37
+ /// Which kind of iterator are we turning this into?
38
+ type IntoIter : Iterator < Item = Self :: Item > ;
39
+
40
+ /// Creates an iterator from an [`Id`].
41
+ ///
42
+ /// You would normally not call this function directly; instead, you'd
43
+ /// just call [`into_iter`](IntoIterator::into_iter) on an [`Id`].
44
+ fn id_into_iter ( this : Id < Self > ) -> Self :: IntoIter ;
45
+ }
46
+
47
+ // Note: These `IntoIterator` implementations conflict with an `Iterator`
48
+ // implementation for `Id`.
49
+ //
50
+ // For our case however (in contrast with `Box`), that is the better tradeoff,
51
+ // which I will show with an example:
52
+ //
53
+ // ```
54
+ // let xs = Box::new(vec![]);
55
+ // for x in &xs { // Doesn't compile, `&Box` doesn't implement `IntoIterator`
56
+ // // ...
57
+ // }
58
+ // ```
59
+ //
60
+ // Here, you're expected to write `xs.iter()` or `&**xs` instead, which is
61
+ // fairly acceptable, since usually people don't wrap things in boxes so much;
62
+ // but in Objective-C, _everything_ is wrapped in an `Id`, and hence we should
63
+ // attempt to make that common case easier:
64
+ //
65
+ // ```
66
+ // let obj = NSArray::new(); // `Id<NSArray<_>>`
67
+ // for item in &obj { // Should compile
68
+ // // ...
69
+ // }
70
+ // ```
71
+ //
72
+ // The loss of the `Iterator` impl is a bit unfortunate, but not a big deal,
73
+ // since there is only one iterator in Objective-C anyhow, `NSEnumerator`, and
74
+ // for that we can make other abstractions instead.
75
+ impl < T : ?Sized + IdIntoIterator > IntoIterator for Id < T > {
76
+ type Item = <T as IdIntoIterator >:: Item ;
77
+ type IntoIter = <T as IdIntoIterator >:: IntoIter ;
78
+
79
+ #[ inline]
80
+ fn into_iter ( self ) -> Self :: IntoIter {
81
+ T :: id_into_iter ( self )
82
+ }
83
+ }
84
+
85
+ impl < ' a , T : ?Sized > IntoIterator for & ' a Id < T >
86
+ where
87
+ & ' a T : IntoIterator ,
88
+ {
89
+ type Item = <& ' a T as IntoIterator >:: Item ;
90
+ type IntoIter = <& ' a T as IntoIterator >:: IntoIter ;
91
+
92
+ #[ inline]
93
+ fn into_iter ( self ) -> Self :: IntoIter {
94
+ ( & * * self ) . into_iter ( )
95
+ }
96
+ }
97
+
98
+ impl < ' a , T : ?Sized + IsMutable > IntoIterator for & ' a mut Id < T >
99
+ where
100
+ & ' a mut T : IntoIterator ,
101
+ {
102
+ type Item = <& ' a mut T as IntoIterator >:: Item ;
103
+ type IntoIter = <& ' a mut T as IntoIterator >:: IntoIter ;
104
+
105
+ #[ inline]
106
+ fn into_iter ( self ) -> Self :: IntoIter {
107
+ ( & mut * * self ) . into_iter ( )
108
+ }
109
+ }
110
+
111
+
112
+ #[ cfg( test) ]
113
+ mod tests {
114
+ use super :: * ;
115
+ use crate :: mutability:: Mutable ;
116
+ use crate :: runtime:: NSObject ;
117
+ use crate :: { declare_class, msg_send_id, ClassType } ;
118
+
119
+ declare_class ! (
120
+ #[ derive( PartialEq , Eq , Hash , Debug ) ]
121
+ struct Collection ;
122
+
123
+ unsafe impl ClassType for Collection {
124
+ type Super = NSObject ;
125
+ type Mutability = Mutable ;
126
+ const NAME : & ' static str = "MyCustomCollection" ;
127
+ }
128
+ ) ;
129
+
130
+ impl DefaultId for Collection {
131
+ fn default_id ( ) -> Id < Self > {
132
+ unsafe { msg_send_id ! [ Collection :: class( ) , new] }
133
+ }
134
+ }
135
+
136
+ struct Iter < ' a > ( & ' a Collection ) ;
137
+
138
+ impl < ' a > Iterator for Iter < ' a > {
139
+ type Item = & ' a NSObject ;
140
+ fn next ( & mut self ) -> Option < Self :: Item > {
141
+ None
142
+ }
143
+ }
144
+
145
+ impl < ' a > IntoIterator for & ' a Collection {
146
+ type Item = & ' a NSObject ;
147
+ type IntoIter = Iter < ' a > ;
148
+
149
+ fn into_iter ( self ) -> Self :: IntoIter {
150
+ Iter ( self )
151
+ }
152
+ }
153
+
154
+ struct IterMut < ' a > ( & ' a mut Collection ) ;
155
+
156
+ impl < ' a > Iterator for IterMut < ' a > {
157
+ type Item = & ' a mut NSObject ;
158
+ fn next ( & mut self ) -> Option < Self :: Item > {
159
+ None
160
+ }
161
+ }
162
+
163
+ impl < ' a > IntoIterator for & ' a mut Collection {
164
+ // Usually only valid if a mutable object is stored in the collection.
165
+ type Item = & ' a mut NSObject ;
166
+ type IntoIter = IterMut < ' a > ;
167
+
168
+ fn into_iter ( self ) -> Self :: IntoIter {
169
+ IterMut ( self )
170
+ }
171
+ }
172
+
173
+ struct IntoIter ( Id < Collection > ) ;
174
+
175
+ impl Iterator for IntoIter {
176
+ type Item = Id < NSObject > ;
177
+ fn next ( & mut self ) -> Option < Self :: Item > {
178
+ None
179
+ }
180
+ }
181
+
182
+ impl < ' a > IntoIterator for Id < Collection > {
183
+ type Item = Id < NSObject > ;
184
+ type IntoIter = IntoIter ;
185
+
186
+ fn into_iter ( self ) -> Self :: IntoIter {
187
+ IntoIter ( self )
188
+ }
189
+ }
190
+
191
+ #[ test]
192
+ fn test_default ( ) {
193
+ let obj1: Id < Collection > = Default :: default ( ) ;
194
+ let obj2 = Collection :: default_id ( ) ;
195
+ assert_ne ! ( obj1, obj2) ;
196
+ }
197
+
198
+ #[ test]
199
+ fn test_into_iter ( ) {
200
+ let mut obj: Id < Collection > = Default :: default ( ) ;
201
+
202
+ for _ in & * obj { }
203
+ for _ in & obj { }
204
+
205
+ for _ in & mut * obj { }
206
+ for _ in & mut obj { }
207
+
208
+ for _ in obj { }
209
+ }
210
+ }
0 commit comments