1
1
use crate :: types:: size_t;
2
2
use std:: cmp:: min;
3
3
use std:: ffi:: CStr ;
4
+ use std:: marker:: PhantomData ;
4
5
use std:: os:: raw:: c_char;
6
+ use std:: ptr:: NonNull ;
5
7
use std:: sync:: Arc ;
6
8
7
9
pub unsafe fn ptr_to_cstr ( ptr : * const c_char ) -> Option < & ' static str > {
@@ -71,35 +73,269 @@ macro_rules! make_c_str {
71
73
#[ cfg( test) ]
72
74
pub ( crate ) use make_c_str;
73
75
74
- /// Defines a pointer manipulation API for non-shared heap-allocated data.
76
+ mod sealed {
77
+ pub trait Sealed { }
78
+ }
79
+
80
+ pub trait Ownership : sealed:: Sealed { }
81
+
82
+ pub struct Exclusive ;
83
+ impl sealed:: Sealed for Exclusive { }
84
+ impl Ownership for Exclusive { }
85
+
86
+ pub struct Shared ;
87
+ impl sealed:: Sealed for Shared { }
88
+ impl Ownership for Shared { }
89
+
90
+ pub struct Borrowed ;
91
+ impl sealed:: Sealed for Borrowed { }
92
+ impl Ownership for Borrowed { }
93
+
94
+ pub trait Mutability : sealed:: Sealed { }
95
+
96
+ pub struct Const ;
97
+ impl sealed:: Sealed for Const { }
98
+ impl Mutability for Const { }
99
+
100
+ pub struct Mut ;
101
+ impl sealed:: Sealed for Mut { }
102
+ impl Mutability for Mut { }
103
+
104
+ pub trait Properties {
105
+ type Ownership : Ownership ;
106
+ type Mutability : Mutability ;
107
+ }
108
+
109
+ impl < O : Ownership , M : Mutability > Properties for ( O , M ) {
110
+ type Ownership = O ;
111
+ type Mutability = M ;
112
+ }
113
+
114
+ /// An exclusive pointer type, generic over mutability.
115
+ pub type CassExclusivePtr < T , M > = CassPtr < T , ( Exclusive , M ) > ;
116
+
117
+ /// An exclusive const pointer. Should be used for Box-allocated objects
118
+ /// that need to be read-only.
119
+ pub type CassExclusiveConstPtr < T > = CassExclusivePtr < T , Const > ;
120
+
121
+ /// An exclusive mutable pointer. Should be used for Box-allocated objects
122
+ /// that need to be mutable.
123
+ pub type CassExclusiveMutPtr < T > = CassExclusivePtr < T , Mut > ;
124
+
125
+ /// A shared const pointer. Should be used for Arc-allocated objects.
75
126
///
76
- /// Implement this trait for types that are allocated by the driver via [`Box::new`],
77
- /// and then returned to the user as a pointer. The user is responsible for freeing
78
- /// the memory associated with the pointer using corresponding driver's API function.
79
- pub trait BoxFFI {
80
- fn into_ptr ( self : Box < Self > ) -> * mut Self {
81
- #[ allow( clippy:: disallowed_methods) ]
82
- Box :: into_raw ( self )
127
+ /// Notice that this type does not provide interior mutability itself.
128
+ /// It is the responsiblity of the user of this API, to provide soundness
129
+ /// in this matter (aliasing ^ mutability).
130
+ /// Take for example [`CassDataType`](crate::cass_types::CassDataType). It
131
+ /// holds underlying data in [`UnsafeCell`](std::cell::UnsafeCell) to provide
132
+ /// interior mutability.
133
+ pub type CassSharedPtr < T > = CassPtr < T , ( Shared , Const ) > ;
134
+
135
+ /// A borrowed const pointer. Should be used for objects that reference
136
+ /// some field of already allocated object.
137
+ ///
138
+ /// When operating on the pointer of this type, we do not make any assumptions
139
+ /// about the origin of the pointer, apart from the fact that it is obtained
140
+ /// from some valid reference.
141
+ ///
142
+ /// In particular, it may be a reference obtained from `Box/Arc::as_ref()`.
143
+ /// Notice, however, that we do not allow to convert such pointer back to `Box/Arc`,
144
+ /// since we do not have a guarantee that corresponding memory was allocated certain way.
145
+ /// OTOH, we can safely convert the pointer to a valid reference (assuming user did not
146
+ /// provide a pointer pointing to some garbage memory).
147
+ pub type CassBorrowedPtr < T > = CassPtr < T , ( Borrowed , Const ) > ;
148
+
149
+ // repr(transparent), so the struct has the same layout as underlying Option<NonNull<T>>.
150
+ // Thanks to https://doc.rust-lang.org/std/option/#representation optimization,
151
+ // we are guaranteed, that for T: Sized, our struct has the same layout
152
+ // and function call ABI as simply NonNull<T>.
153
+ #[ repr( transparent) ]
154
+ pub struct CassPtr < T : Sized , P : Properties > {
155
+ ptr : Option < NonNull < T > > ,
156
+ _phantom : PhantomData < P > ,
157
+ }
158
+
159
+ impl < T : Sized , P : Properties > Copy for CassPtr < T , P > { }
160
+
161
+ impl < T : Sized , P : Properties > Clone for CassPtr < T , P > {
162
+ fn clone ( & self ) -> Self {
163
+ * self
83
164
}
84
- unsafe fn from_ptr ( ptr : * mut Self ) -> Box < Self > {
85
- #[ allow( clippy:: disallowed_methods) ]
86
- Box :: from_raw ( ptr)
165
+ }
166
+
167
+ /// Methods for any pointer kind.
168
+ ///
169
+ /// Notice that there are no constructors except from null(), which is trivial.
170
+ /// Thanks to that, we can make some assumptions and guarantees based on
171
+ /// the origin of the pointer. For these, see `SAFETY` comments.
172
+ impl < T : Sized , P : Properties > CassPtr < T , P > {
173
+ fn null ( ) -> Self {
174
+ CassPtr {
175
+ ptr : None ,
176
+ _phantom : PhantomData ,
177
+ }
87
178
}
88
- unsafe fn as_maybe_ref < ' a > ( ptr : * const Self ) -> Option < & ' a Self > {
179
+
180
+ fn is_null ( & self ) -> bool {
181
+ self . ptr . is_none ( )
182
+ }
183
+
184
+ /// Converts a pointer to an optional valid reference.
185
+ fn into_ref < ' a > ( self ) -> Option < & ' a T > {
186
+ // SAFETY: We know that our pointers either come from a valid allocation (Box or Arc),
187
+ // or were created based on the reference to the field of some allocated object.
188
+ // Thus, if the pointer is non-null, we are guaranteed that it's valid.
189
+ unsafe { self . ptr . map ( |p| p. as_ref ( ) ) }
190
+ }
191
+ }
192
+
193
+ /// Methods for any exclusive pointers (no matter the mutability).
194
+ impl < T , M : Mutability > CassPtr < T , ( Exclusive , M ) > {
195
+ /// Creates a pointer based on a VALID Box allocation.
196
+ /// This is the only way to obtain such pointer.
197
+ fn from_box ( b : Box < T > ) -> Self {
89
198
#[ allow( clippy:: disallowed_methods) ]
90
- ptr. as_ref ( )
199
+ let ptr = Box :: into_raw ( b) ;
200
+ CassPtr {
201
+ ptr : NonNull :: new ( ptr) ,
202
+ _phantom : PhantomData ,
203
+ }
204
+ }
205
+
206
+ /// Converts the pointer back to the owned Box (if not null).
207
+ fn into_box ( self ) -> Option < Box < T > > {
208
+ // SAFETY: We are guaranteed that if ptr is Some, then it was obtained
209
+ // from a valid Box allocation (see new() implementation).
210
+ unsafe {
211
+ self . ptr . map ( |p| {
212
+ #[ allow( clippy:: disallowed_methods) ]
213
+ Box :: from_raw ( p. as_ptr ( ) )
214
+ } )
215
+ }
216
+ }
217
+ }
218
+
219
+ /// Methods for exclusive mutable pointers.
220
+ impl < T > CassPtr < T , ( Exclusive , Mut ) > {
221
+ fn null_mut ( ) -> Self {
222
+ CassPtr {
223
+ ptr : None ,
224
+ _phantom : PhantomData ,
225
+ }
91
226
}
92
- unsafe fn as_ref < ' a > ( ptr : * const Self ) -> & ' a Self {
227
+
228
+ /// Converts a pointer to an optional valid, and mutable reference.
229
+ fn into_mut_ref < ' a > ( self ) -> Option < & ' a mut T > {
230
+ // SAFETY: We are guaranteed that if ptr is Some, then it was obtained
231
+ // from a valid Box allocation (see new() implementation).
232
+ unsafe { self . ptr . map ( |mut p| p. as_mut ( ) ) }
233
+ }
234
+ }
235
+
236
+ /// Define this conversion for test purposes.
237
+ /// User receives a mutable exclusive pointer from constructor,
238
+ /// but following function calls need a const exclusive pointer.
239
+ #[ cfg( test) ]
240
+ impl < T > CassPtr < T , ( Exclusive , Mut ) > {
241
+ pub fn into_const ( self ) -> CassPtr < T , ( Exclusive , Const ) > {
242
+ CassPtr {
243
+ ptr : self . ptr ,
244
+ _phantom : PhantomData ,
245
+ }
246
+ }
247
+ }
248
+
249
+ /// Methods for Shared pointers.
250
+ impl < T : Sized > CassSharedPtr < T > {
251
+ /// Creates a pointer based on a VALID Arc allocation.
252
+ fn from_arc ( a : Arc < T > ) -> Self {
93
253
#[ allow( clippy:: disallowed_methods) ]
94
- ptr. as_ref ( ) . unwrap ( )
254
+ let ptr = Arc :: into_raw ( a) ;
255
+ CassPtr {
256
+ ptr : NonNull :: new ( ptr as * mut T ) ,
257
+ _phantom : PhantomData ,
258
+ }
95
259
}
96
- unsafe fn as_mut_ref < ' a > ( ptr : * mut Self ) -> & ' a mut Self {
260
+
261
+ /// Creates a pointer which borrows from a VALID Arc allocation.
262
+ fn from_ref ( a : & Arc < T > ) -> Self {
97
263
#[ allow( clippy:: disallowed_methods) ]
98
- ptr. as_mut ( ) . unwrap ( )
264
+ let ptr = Arc :: as_ptr ( a) ;
265
+ CassPtr {
266
+ ptr : NonNull :: new ( ptr as * mut T ) ,
267
+ _phantom : PhantomData ,
268
+ }
269
+ }
270
+
271
+ /// Converts the pointer back to the Arc.
272
+ fn into_arc ( self ) -> Option < Arc < T > > {
273
+ // SAFETY: The pointer can only be obtained via new() or from_ref(),
274
+ // both of which accept an Arc.
275
+ // It means that the pointer comes from a valid allocation.
276
+ unsafe {
277
+ self . ptr . map ( |p| {
278
+ #[ allow( clippy:: disallowed_methods) ]
279
+ Arc :: from_raw ( p. as_ptr ( ) )
280
+ } )
281
+ }
282
+ }
283
+
284
+ /// Converts the pointer to an Arc, by increasing its reference count.
285
+ fn clone_arced ( self ) -> Option < Arc < T > > {
286
+ // SAFETY: The pointer can only be obtained via new() or from_ref(),
287
+ // both of which accept an Arc.
288
+ // It means that the pointer comes from a valid allocation.
289
+ unsafe {
290
+ self . ptr . map ( |p| {
291
+ let ptr = p. as_ptr ( ) ;
292
+ #[ allow( clippy:: disallowed_methods) ]
293
+ Arc :: increment_strong_count ( ptr) ;
294
+ #[ allow( clippy:: disallowed_methods) ]
295
+ Arc :: from_raw ( ptr)
296
+ } )
297
+ }
298
+ }
299
+ }
300
+
301
+ /// Methods for borrowed pointers.
302
+ impl < T : Sized > CassPtr < T , ( Borrowed , Const ) > {
303
+ fn from_ref ( r : & T ) -> Self {
304
+ Self {
305
+ ptr : Some ( NonNull :: from ( r) ) ,
306
+ _phantom : PhantomData ,
307
+ }
308
+ }
309
+ }
310
+
311
+ /// Defines a pointer manipulation API for non-shared heap-allocated data.
312
+ ///
313
+ /// Implement this trait for types that are allocated by the driver via [`Box::new`],
314
+ /// and then returned to the user as a pointer. The user is responsible for freeing
315
+ /// the memory associated with the pointer using corresponding driver's API function.
316
+ pub trait BoxFFI : Sized {
317
+ fn into_ptr < M : Mutability > ( self : Box < Self > ) -> CassExclusivePtr < Self , M > {
318
+ CassExclusivePtr :: from_box ( self )
319
+ }
320
+ fn from_ptr < M : Mutability > ( ptr : CassExclusivePtr < Self , M > ) -> Option < Box < Self > > {
321
+ ptr. into_box ( )
322
+ }
323
+ fn as_ref < ' a , M : Mutability > ( ptr : CassExclusivePtr < Self , M > ) -> Option < & ' a Self > {
324
+ ptr. into_ref ( )
325
+ }
326
+ fn as_mut_ref < ' a > ( ptr : CassExclusiveMutPtr < Self > ) -> Option < & ' a mut Self > {
327
+ ptr. into_mut_ref ( )
99
328
}
100
- unsafe fn free ( ptr : * mut Self ) {
329
+ fn free ( ptr : CassExclusiveMutPtr < Self > ) {
101
330
std:: mem:: drop ( BoxFFI :: from_ptr ( ptr) ) ;
102
331
}
332
+ #[ cfg( test) ]
333
+ fn null ( ) -> CassExclusiveConstPtr < Self > {
334
+ CassExclusiveConstPtr :: null ( )
335
+ }
336
+ fn null_mut ( ) -> CassExclusiveMutPtr < Self > {
337
+ CassExclusiveMutPtr :: null_mut ( )
338
+ }
103
339
}
104
340
105
341
/// Defines a pointer manipulation API for shared heap-allocated data.
@@ -108,36 +344,31 @@ pub trait BoxFFI {
108
344
/// The data should be allocated via [`Arc::new`], and then returned to the user as a pointer.
109
345
/// The user is responsible for freeing the memory associated
110
346
/// with the pointer using corresponding driver's API function.
111
- pub trait ArcFFI {
112
- fn as_ptr ( self : & Arc < Self > ) -> * const Self {
113
- #[ allow( clippy:: disallowed_methods) ]
114
- Arc :: as_ptr ( self )
347
+ pub trait ArcFFI : Sized {
348
+ fn as_ptr ( self : & Arc < Self > ) -> CassSharedPtr < Self > {
349
+ CassSharedPtr :: from_ref ( self )
115
350
}
116
- fn into_ptr ( self : Arc < Self > ) -> * const Self {
117
- #[ allow( clippy:: disallowed_methods) ]
118
- Arc :: into_raw ( self )
351
+ fn into_ptr ( self : Arc < Self > ) -> CassSharedPtr < Self > {
352
+ CassSharedPtr :: from_arc ( self )
119
353
}
120
- unsafe fn from_ptr ( ptr : * const Self ) -> Arc < Self > {
121
- #[ allow( clippy:: disallowed_methods) ]
122
- Arc :: from_raw ( ptr)
354
+ fn from_ptr ( ptr : CassSharedPtr < Self > ) -> Option < Arc < Self > > {
355
+ ptr. into_arc ( )
123
356
}
124
- unsafe fn cloned_from_ptr ( ptr : * const Self ) -> Arc < Self > {
125
- #[ allow( clippy:: disallowed_methods) ]
126
- Arc :: increment_strong_count ( ptr) ;
127
- #[ allow( clippy:: disallowed_methods) ]
128
- Arc :: from_raw ( ptr)
357
+ fn cloned_from_ptr ( ptr : CassSharedPtr < Self > ) -> Option < Arc < Self > > {
358
+ ptr. clone_arced ( )
129
359
}
130
- unsafe fn as_maybe_ref < ' a > ( ptr : * const Self ) -> Option < & ' a Self > {
131
- #[ allow( clippy:: disallowed_methods) ]
132
- ptr. as_ref ( )
133
- }
134
- unsafe fn as_ref < ' a > ( ptr : * const Self ) -> & ' a Self {
135
- #[ allow( clippy:: disallowed_methods) ]
136
- ptr. as_ref ( ) . unwrap ( )
360
+ fn as_ref < ' a > ( ptr : CassSharedPtr < Self > ) -> Option < & ' a Self > {
361
+ ptr. into_ref ( )
137
362
}
138
- unsafe fn free ( ptr : * const Self ) {
363
+ fn free ( ptr : CassSharedPtr < Self > ) {
139
364
std:: mem:: drop ( ArcFFI :: from_ptr ( ptr) ) ;
140
365
}
366
+ fn null ( ) -> CassSharedPtr < Self > {
367
+ CassSharedPtr :: null ( )
368
+ }
369
+ fn is_null ( ptr : CassSharedPtr < Self > ) -> bool {
370
+ ptr. is_null ( )
371
+ }
141
372
}
142
373
143
374
/// Defines a pointer manipulation API for data owned by some other object.
@@ -148,12 +379,17 @@ pub trait ArcFFI {
148
379
/// For example: lifetime of CassRow is bound by the lifetime of CassResult.
149
380
/// There is no API function that frees the CassRow. It should be automatically
150
381
/// freed when user calls cass_result_free.
151
- pub trait RefFFI {
152
- fn as_ptr ( & self ) -> * const Self {
153
- self as * const Self
382
+ pub trait RefFFI : Sized {
383
+ fn as_ptr ( & self ) -> CassBorrowedPtr < Self > {
384
+ CassBorrowedPtr :: from_ref ( self )
154
385
}
155
- unsafe fn as_ref < ' a > ( ptr : * const Self ) -> & ' a Self {
156
- #[ allow( clippy:: disallowed_methods) ]
157
- ptr. as_ref ( ) . unwrap ( )
386
+ fn as_ref < ' a > ( ptr : CassBorrowedPtr < Self > ) -> Option < & ' a Self > {
387
+ ptr. into_ref ( )
388
+ }
389
+ fn null ( ) -> CassBorrowedPtr < Self > {
390
+ CassBorrowedPtr :: null ( )
391
+ }
392
+ fn is_null ( ptr : CassBorrowedPtr < Self > ) -> bool {
393
+ ptr. is_null ( )
158
394
}
159
395
}
0 commit comments