@@ -14,6 +14,8 @@ use core_foundation_sys::base::CFIndex;
14
14
use core_foundation_sys:: base:: { kCFAllocatorDefault} ;
15
15
use std:: ops:: Deref ;
16
16
use std:: slice;
17
+ use std:: sync:: Arc ;
18
+
17
19
18
20
use base:: { CFIndexConvertible , TCFType } ;
19
21
@@ -26,6 +28,7 @@ impl_TCFType!(CFData, CFDataRef, CFDataGetTypeID);
26
28
impl_CFTypeDescription ! ( CFData ) ;
27
29
28
30
impl CFData {
31
+ /// Creates a CFData around a copy `buffer`
29
32
pub fn from_buffer ( buffer : & [ u8 ] ) -> CFData {
30
33
unsafe {
31
34
let data_ref = CFDataCreate ( kCFAllocatorDefault,
@@ -35,6 +38,41 @@ impl CFData {
35
38
}
36
39
}
37
40
41
+ /// Creates a CFData referencing `buffer` without creating a copy
42
+ pub fn from_arc < T : AsRef < [ u8 ] > + Sync + Send > ( buffer : Arc < T > ) -> Self {
43
+ use std:: os:: raw:: c_void;
44
+ use crate :: base:: { CFAllocator , CFAllocatorContext } ;
45
+
46
+ unsafe {
47
+ let ptr = ( * buffer) . as_ref ( ) . as_ptr ( ) as * const _ ;
48
+ let len = ( * buffer) . as_ref ( ) . len ( ) . to_CFIndex ( ) ;
49
+ let info = Arc :: into_raw ( buffer) as * mut c_void ;
50
+
51
+ extern "C" fn deallocate < T > ( _: * mut c_void , info : * mut c_void ) {
52
+ unsafe {
53
+ drop ( Arc :: from_raw ( info as * mut T ) ) ;
54
+ }
55
+ }
56
+
57
+ // Use a separate allocator for each allocation because
58
+ // we need `info` to do the deallocation vs. `ptr`
59
+ let allocator = CFAllocator :: new ( CFAllocatorContext {
60
+ info,
61
+ version : 0 ,
62
+ retain : None ,
63
+ reallocate : None ,
64
+ release : None ,
65
+ copyDescription : None ,
66
+ allocate : None ,
67
+ deallocate : Some ( deallocate :: < T > ) ,
68
+ preferredSize : None ,
69
+ } ) ;
70
+ let data_ref =
71
+ CFDataCreateWithBytesNoCopy ( kCFAllocatorDefault, ptr, len, allocator. as_CFTypeRef ( ) ) ;
72
+ TCFType :: wrap_under_create_rule ( data_ref)
73
+ }
74
+ }
75
+
38
76
/// Returns a pointer to the underlying bytes in this data. Note that this byte buffer is
39
77
/// read-only.
40
78
#[ inline]
@@ -61,3 +99,46 @@ impl Deref for CFData {
61
99
self . bytes ( )
62
100
}
63
101
}
102
+
103
+ #[ cfg( test) ]
104
+ mod test {
105
+ use super :: CFData ;
106
+ use std:: sync:: Arc ;
107
+
108
+ #[ test]
109
+ fn test_data_provider ( ) {
110
+ let l = vec ! [ 5 ] ;
111
+ CFData :: from_arc ( Arc :: new ( l) ) ;
112
+
113
+ let l = vec ! [ 5 ] ;
114
+ CFData :: from_arc ( Arc :: new ( l. into_boxed_slice ( ) ) ) ;
115
+
116
+ // Make sure the buffer is actually dropped
117
+ use std:: sync:: atomic:: { AtomicBool , Ordering :: SeqCst } ;
118
+ struct VecWrapper {
119
+ inner : Vec < u8 > ,
120
+ dropped : Arc < AtomicBool > ,
121
+ }
122
+
123
+ impl Drop for VecWrapper {
124
+ fn drop ( & mut self ) {
125
+ self . dropped . store ( true , SeqCst )
126
+ }
127
+ }
128
+
129
+ impl std:: convert:: AsRef < [ u8 ] > for VecWrapper {
130
+ fn as_ref ( & self ) -> & [ u8 ] {
131
+ & self . inner
132
+ }
133
+ }
134
+
135
+ let dropped = Arc :: new ( AtomicBool :: default ( ) ) ;
136
+ let l = Arc :: new ( VecWrapper { inner : vec ! [ 5 ] , dropped : dropped. clone ( ) } ) ;
137
+ let m = l. clone ( ) ;
138
+ let dp = CFData :: from_arc ( l) ;
139
+ drop ( m) ;
140
+ assert ! ( !dropped. load( SeqCst ) ) ;
141
+ drop ( dp) ;
142
+ assert ! ( dropped. load( SeqCst ) )
143
+ }
144
+ }
0 commit comments