@@ -5,24 +5,9 @@ use std::marker::PhantomData;
5
5
use std:: ops:: { Deref , DerefMut } ;
6
6
7
7
use objc:: Message ;
8
+ use objc:: rc:: { StrongPtr , WeakPtr } ;
8
9
use objc:: runtime:: Object ;
9
10
10
- #[ link( name = "objc" , kind = "dylib" ) ]
11
- extern {
12
- fn objc_retain ( obj : * mut Object ) -> * mut Object ;
13
- fn objc_release ( obj : * mut Object ) ;
14
- }
15
-
16
- struct StrongPtr ( * mut Object ) ;
17
-
18
- impl Drop for StrongPtr {
19
- fn drop ( & mut self ) {
20
- unsafe {
21
- objc_release ( self . 0 ) ;
22
- }
23
- }
24
- }
25
-
26
11
/// A type used to mark that a struct owns the object(s) it contains,
27
12
/// so it has the sole references to them.
28
13
pub enum Owned { }
@@ -65,7 +50,7 @@ impl<T, O> Id<T, O> where T: Message, O: Ownership {
65
50
/// the caller must ensure the ownership is correct.
66
51
pub unsafe fn from_ptr ( ptr : * mut T ) -> Id < T , O > {
67
52
assert ! ( !ptr. is_null( ) , "Attempted to construct an Id from a null pointer" ) ;
68
- Id :: new ( StrongPtr ( objc_retain ( ptr as * mut Object ) ) )
53
+ Id :: new ( StrongPtr :: retain ( ptr as * mut Object ) )
69
54
}
70
55
71
56
/// Constructs an `Id` from a pointer to a retained object; this won't
@@ -75,7 +60,7 @@ impl<T, O> Id<T, O> where T: Message, O: Ownership {
75
60
/// the caller must ensure the ownership is correct.
76
61
pub unsafe fn from_retained_ptr ( ptr : * mut T ) -> Id < T , O > {
77
62
assert ! ( !ptr. is_null( ) , "Attempted to construct an Id from a null pointer" ) ;
78
- Id :: new ( StrongPtr ( ptr as * mut Object ) )
63
+ Id :: new ( StrongPtr :: new ( ptr as * mut Object ) )
79
64
}
80
65
}
81
66
@@ -90,7 +75,7 @@ impl<T> Id<T, Owned> where T: Message {
90
75
impl < T > Clone for Id < T , Shared > where T : Message {
91
76
fn clone ( & self ) -> ShareId < T > {
92
77
unsafe {
93
- Id :: new ( StrongPtr ( objc_retain ( self . ptr . 0 ) ) )
78
+ Id :: new ( self . ptr . clone ( ) )
94
79
}
95
80
}
96
81
}
@@ -105,13 +90,13 @@ impl<T, O> Deref for Id<T, O> {
105
90
type Target = T ;
106
91
107
92
fn deref ( & self ) -> & T {
108
- unsafe { & * ( self . ptr . 0 as * mut T ) }
93
+ unsafe { & * ( * self . ptr as * mut T ) }
109
94
}
110
95
}
111
96
112
97
impl < T > DerefMut for Id < T , Owned > {
113
98
fn deref_mut ( & mut self ) -> & mut T {
114
- unsafe { & mut * ( self . ptr . 0 as * mut T ) }
99
+ unsafe { & mut * ( * self . ptr as * mut T ) }
115
100
}
116
101
}
117
102
@@ -141,25 +126,57 @@ impl<T, O> fmt::Debug for Id<T, O> where T: fmt::Debug {
141
126
142
127
impl < T , O > fmt:: Pointer for Id < T , O > {
143
128
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
144
- fmt:: Pointer :: fmt ( & self . ptr . 0 , f)
129
+ fmt:: Pointer :: fmt ( & self . ptr , f)
145
130
}
146
131
}
147
132
148
133
/// A convenient alias for a shared `Id`.
149
134
pub type ShareId < T > = Id < T , Shared > ;
150
135
136
+ /// A pointer type for a weak reference to an Objective-C reference counted
137
+ /// object.
138
+ pub struct WeakId < T > {
139
+ ptr : WeakPtr ,
140
+ item : PhantomData < T > ,
141
+ }
142
+
143
+ impl < T > WeakId < T > where T : Message {
144
+ /// Construct a new `WeakId` referencing the given `ShareId`.
145
+ pub fn new ( obj : & ShareId < T > ) -> WeakId < T > {
146
+ WeakId {
147
+ ptr : obj. ptr . weak ( ) ,
148
+ item : PhantomData ,
149
+ }
150
+ }
151
+
152
+ /// Load a `ShareId` from the `WeakId` if the object still exists.
153
+ /// Returns `None` if the object has been deallocated.
154
+ pub fn load ( & self ) -> Option < ShareId < T > > {
155
+ let obj = self . ptr . load ( ) ;
156
+ if obj. is_null ( ) {
157
+ None
158
+ } else {
159
+ Some ( unsafe { Id :: new ( obj) } )
160
+ }
161
+ }
162
+ }
163
+
164
+ unsafe impl < T > Sync for WeakId < T > where T : Sync { }
165
+
166
+ unsafe impl < T > Send for WeakId < T > where T : Sync { }
167
+
151
168
#[ cfg( test) ]
152
169
mod tests {
153
- use objc:: runtime:: { Class , Object } ;
154
- use super :: Id ;
170
+ use objc:: runtime:: Object ;
171
+ use super :: { Id , ShareId , WeakId } ;
155
172
156
173
fn retain_count ( obj : & Object ) -> usize {
157
174
unsafe { msg_send ! [ obj, retainCount] }
158
175
}
159
176
160
177
#[ test]
161
178
fn test_clone ( ) {
162
- let cls = Class :: get ( " NSObject" ) . unwrap ( ) ;
179
+ let cls = class ! ( NSObject ) ;
163
180
let obj: Id < Object > = unsafe {
164
181
let obj: * mut Object = msg_send ! [ cls, alloc] ;
165
182
let obj: * mut Object = msg_send ! [ obj, init] ;
@@ -177,4 +194,24 @@ mod tests {
177
194
drop ( obj) ;
178
195
assert ! ( retain_count( & cloned) == 1 ) ;
179
196
}
197
+
198
+ #[ test]
199
+ fn test_weak ( ) {
200
+ let cls = class ! ( NSObject ) ;
201
+ let obj: ShareId < Object > = unsafe {
202
+ let obj: * mut Object = msg_send ! [ cls, alloc] ;
203
+ let obj: * mut Object = msg_send ! [ obj, init] ;
204
+ Id :: from_retained_ptr ( obj)
205
+ } ;
206
+
207
+ let weak = WeakId :: new ( & obj) ;
208
+ let strong = weak. load ( ) . unwrap ( ) ;
209
+ let strong_ptr: * const Object = & * strong;
210
+ let obj_ptr: * const Object = & * obj;
211
+ assert ! ( strong_ptr == obj_ptr) ;
212
+ drop ( strong) ;
213
+
214
+ drop ( obj) ;
215
+ assert ! ( weak. load( ) . is_none( ) ) ;
216
+ }
180
217
}
0 commit comments