10
10
use std:: {
11
11
borrow, cmp, fmt, hash,
12
12
ops:: { self , RangeBounds } ,
13
- sync:: Arc ,
13
+ ptr:: NonNull ,
14
+ sync:: atomic:: AtomicUsize ,
14
15
} ;
15
16
16
17
#[ cfg( feature = "serde" ) ]
@@ -22,7 +23,7 @@ pub struct Bytes {
22
23
slice : & ' static [ u8 ] ,
23
24
// The `bytes`` field is used to ensure that the underlying bytes are freed when there are no
24
25
// more references to the `Bytes` object. For static buffers the field is `None`.
25
- bytes : Option < Arc < dyn UnderlyingBytes > > ,
26
+ bytes : Option < RefCountedCell > ,
26
27
}
27
28
28
29
/// The underlying bytes that the `Bytes` object references.
@@ -34,6 +35,27 @@ unsafe impl Send for Bytes {}
34
35
unsafe impl Sync for Bytes { }
35
36
36
37
impl Bytes {
38
+ #[ inline]
39
+ /// Creates a new `Bytes` from the given slice data and the refcount
40
+ ///
41
+ /// # Safety
42
+ ///
43
+ /// * the pointer should be valid for the given length
44
+ /// * the pointer should be valid for reads as long as the refcount or any of it's clone is not
45
+ /// dropped
46
+ pub const unsafe fn from_raw_refcount (
47
+ ptr : NonNull < u8 > ,
48
+ len : usize ,
49
+ refcount : RefCountedCell ,
50
+ ) -> Self {
51
+ // SAFETY: The caller must ensure that the pointer is valid and that the length is correct.
52
+ let slice = unsafe { std:: slice:: from_raw_parts ( ptr. as_ptr ( ) , len) } ;
53
+ Self {
54
+ slice,
55
+ bytes : Some ( refcount) ,
56
+ }
57
+ }
58
+
37
59
/// Creates empty `Bytes`.
38
60
#[ inline]
39
61
pub const fn empty ( ) -> Self {
@@ -186,9 +208,16 @@ impl Bytes {
186
208
// private
187
209
188
210
fn from_underlying ( value : impl UnderlyingBytes ) -> Self {
189
- Self {
190
- slice : unsafe { std:: mem:: transmute :: < & ' _ [ u8 ] , & ' static [ u8 ] > ( value. as_ref ( ) ) } ,
191
- bytes : Some ( Arc :: new ( value) ) ,
211
+ unsafe {
212
+ // SAFETY:
213
+ // * the pointer associated with a slice is non null and valid for the length of the
214
+ // slice
215
+ // * it stays valid as long as value is not dopped
216
+ let ( ptr, len) = {
217
+ let s = value. as_ref ( ) ;
218
+ ( NonNull :: new_unchecked ( s. as_ptr ( ) . cast_mut ( ) ) , s. len ( ) )
219
+ } ;
220
+ Self :: from_raw_refcount ( ptr, len, make_refcounted ( value) )
192
221
}
193
222
}
194
223
@@ -291,6 +320,118 @@ impl Serialize for Bytes {
291
320
}
292
321
}
293
322
323
+ pub struct RefCountedCell {
324
+ data : NonNull < ( ) > ,
325
+ vtable : & ' static RefCountedCellVTable ,
326
+ }
327
+
328
+ unsafe impl Send for RefCountedCell { }
329
+ unsafe impl Sync for RefCountedCell { }
330
+
331
+ impl RefCountedCell {
332
+ #[ inline]
333
+ /// Creates a new `RefCountedCell` from the given data and vtable.
334
+ ///
335
+ /// The data pointer can be used to store arbitrary data, that won't be dropped until the last
336
+ /// clone to the `RefCountedCell` is dropped.
337
+ /// The vtable customizes the behavior of a Waker which gets created from a RawWaker. For each
338
+ /// operation on the Waker, the associated function in the vtable of the underlying RawWaker
339
+ /// will be called.
340
+ ///
341
+ /// # Safety
342
+ ///
343
+ /// * The value pointed to by `data` must be 'static + Send + Sync
344
+ pub const unsafe fn from_raw ( data : NonNull < ( ) > , vtable : & ' static RefCountedCellVTable ) -> Self {
345
+ RefCountedCell { data, vtable }
346
+ }
347
+ }
348
+
349
+ impl Clone for RefCountedCell {
350
+ fn clone ( & self ) -> Self {
351
+ unsafe { ( self . vtable . clone ) ( self . data ) }
352
+ }
353
+ }
354
+
355
+ impl Drop for RefCountedCell {
356
+ fn drop ( & mut self ) {
357
+ unsafe { ( self . vtable . drop ) ( self . data ) }
358
+ }
359
+ }
360
+
361
+ pub struct RefCountedCellVTable {
362
+ pub clone : unsafe fn ( NonNull < ( ) > ) -> RefCountedCell ,
363
+ pub drop : unsafe fn ( NonNull < ( ) > ) ,
364
+ }
365
+
366
+ /// Creates a refcounted cell.
367
+ ///
368
+ /// The data passed to this cell will only be dopped when the last
369
+ /// clone of the cell is dropped.
370
+ fn make_refcounted < T : Send + Sync + ' static > ( data : T ) -> RefCountedCell {
371
+ /// A custom Arc implementation that contains only the strong count
372
+ ///
373
+ /// This struct is not exposed to the outside of this functions and is
374
+ /// only interacted with through the `RefCountedCell` API.
375
+ struct CustomArc < T > {
376
+ rc : AtomicUsize ,
377
+ #[ allow( unused) ]
378
+ data : T ,
379
+ }
380
+
381
+ unsafe fn custom_arc_clone < T > ( data : NonNull < ( ) > ) -> RefCountedCell {
382
+ let custom_arc = data. cast :: < CustomArc < T > > ( ) . as_ref ( ) ;
383
+ custom_arc
384
+ . rc
385
+ . fetch_add ( 1 , std:: sync:: atomic:: Ordering :: Relaxed ) ;
386
+ RefCountedCell :: from_raw (
387
+ data,
388
+ & RefCountedCellVTable {
389
+ clone : custom_arc_clone :: < T > ,
390
+ drop : custom_arc_drop :: < T > ,
391
+ } ,
392
+ )
393
+ }
394
+
395
+ unsafe fn custom_arc_drop < T > ( data : NonNull < ( ) > ) {
396
+ let custom_arc = data. cast :: < CustomArc < T > > ( ) . as_ref ( ) ;
397
+ if custom_arc
398
+ . rc
399
+ . fetch_sub ( 1 , std:: sync:: atomic:: Ordering :: Release )
400
+ != 1
401
+ {
402
+ return ;
403
+ }
404
+
405
+ // Run drop + free memory on the data manually rather than casting back to a box
406
+ // because otherwise miri complains
407
+
408
+ // See standard library documentation for std::sync::Arc to see why this is needed.
409
+ // https://github.com/rust-lang/rust/blob/2a5da7acd4c3eae638aa1c46f3a537940e60a0e4/library/alloc/src/sync.rs#L2647-L2675
410
+ std:: sync:: atomic:: fence ( std:: sync:: atomic:: Ordering :: Acquire ) ;
411
+ {
412
+ let custom_arc = data. cast :: < CustomArc < T > > ( ) . as_mut ( ) ;
413
+ std:: ptr:: drop_in_place ( custom_arc) ;
414
+ }
415
+
416
+ std:: alloc:: dealloc (
417
+ data. as_ptr ( ) as * mut u8 ,
418
+ std:: alloc:: Layout :: new :: < CustomArc < T > > ( ) ,
419
+ ) ;
420
+ }
421
+
422
+ let rc = Box :: leak ( Box :: new ( CustomArc {
423
+ rc : AtomicUsize :: new ( 1 ) ,
424
+ data,
425
+ } ) ) as * mut _ as * const ( ) ;
426
+ RefCountedCell {
427
+ data : unsafe { NonNull :: new_unchecked ( rc as * mut ( ) ) } ,
428
+ vtable : & RefCountedCellVTable {
429
+ clone : custom_arc_clone :: < T > ,
430
+ drop : custom_arc_drop :: < T > ,
431
+ } ,
432
+ }
433
+ }
434
+
294
435
#[ cfg( feature = "bytes_string" ) ]
295
436
mod bytes_string;
296
437
#[ cfg( feature = "bytes_string" ) ]
0 commit comments