@@ -14,6 +14,8 @@ use core_foundation_sys::base::CFIndex;
1414use core_foundation_sys:: base:: { kCFAllocatorDefault} ;
1515use std:: ops:: Deref ;
1616use std:: slice;
17+ use std:: sync:: Arc ;
18+
1719
1820use base:: { CFIndexConvertible , TCFType } ;
1921
@@ -26,6 +28,7 @@ impl_TCFType!(CFData, CFDataRef, CFDataGetTypeID);
2628impl_CFTypeDescription ! ( CFData ) ;
2729
2830impl CFData {
31+ /// Creates a CFData around a copy `buffer`
2932 pub fn from_buffer ( buffer : & [ u8 ] ) -> CFData {
3033 unsafe {
3134 let data_ref = CFDataCreate ( kCFAllocatorDefault,
@@ -35,6 +38,41 @@ impl CFData {
3538 }
3639 }
3740
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+
3876 /// Returns a pointer to the underlying bytes in this data. Note that this byte buffer is
3977 /// read-only.
4078 #[ inline]
@@ -61,3 +99,46 @@ impl Deref for CFData {
6199 self . bytes ( )
62100 }
63101}
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