@@ -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,39 @@ 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+ let allocator = CFAllocator :: new ( CFAllocatorContext {
58+ info : info,
59+ version : 0 ,
60+ retain : None ,
61+ reallocate : None ,
62+ release : None ,
63+ copyDescription : None ,
64+ allocate : None ,
65+ deallocate : Some ( deallocate :: < T > ) ,
66+ preferredSize : None ,
67+ } ) ;
68+ let data_ref =
69+ CFDataCreateWithBytesNoCopy ( kCFAllocatorDefault, ptr, len, allocator. as_CFTypeRef ( ) ) ;
70+ TCFType :: wrap_under_create_rule ( data_ref)
71+ }
72+ }
73+
3874 /// Returns a pointer to the underlying bytes in this data. Note that this byte buffer is
3975 /// read-only.
4076 #[ inline]
@@ -61,3 +97,46 @@ impl Deref for CFData {
6197 self . bytes ( )
6298 }
6399}
100+
101+ #[ cfg( test) ]
102+ mod test {
103+ use super :: CFData ;
104+ use std:: sync:: Arc ;
105+
106+ #[ test]
107+ fn test_data_provider ( ) {
108+ let l = vec ! [ 5 ] ;
109+ CFData :: from_arc ( Arc :: new ( l) ) ;
110+
111+ let l = vec ! [ 5 ] ;
112+ CFData :: from_arc ( Arc :: new ( l. into_boxed_slice ( ) ) ) ;
113+
114+ // Make sure the buffer is actually dropped
115+ use std:: sync:: atomic:: { AtomicBool , Ordering :: SeqCst } ;
116+ struct VecWrapper {
117+ inner : Vec < u8 > ,
118+ dropped : Arc < AtomicBool > ,
119+ }
120+
121+ impl Drop for VecWrapper {
122+ fn drop ( & mut self ) {
123+ self . dropped . store ( true , SeqCst )
124+ }
125+ }
126+
127+ impl std:: convert:: AsRef < [ u8 ] > for VecWrapper {
128+ fn as_ref ( & self ) -> & [ u8 ] {
129+ & self . inner
130+ }
131+ }
132+
133+ let dropped = Arc :: new ( AtomicBool :: default ( ) ) ;
134+ let l = Arc :: new ( VecWrapper { inner : vec ! [ 5 ] , dropped : dropped. clone ( ) } ) ;
135+ let m = l. clone ( ) ;
136+ let dp = CFData :: from_arc ( l) ;
137+ drop ( m) ;
138+ assert ! ( !dropped. load( SeqCst ) ) ;
139+ drop ( dp) ;
140+ assert ! ( dropped. load( SeqCst ) )
141+ }
142+ }
0 commit comments