1616// under the License.
1717
1818use std:: { any:: Any , ffi:: c_void, ops:: Deref } ;
19-
20- use abi_stable:: { std_types:: { RHashMap , RResult , RStr , RString , RVec } , RTuple , StableAbi } ;
21- use abi_stable:: std_types:: { ROption , Tuple3 } ;
19+ use std:: collections:: HashMap ;
20+ use abi_stable:: {
21+ std_types:: { RHashMap , ROption , RResult , RStr , RString , RVec , Tuple3 } ,
22+ RTuple , StableAbi ,
23+ } ;
2224use arrow:: { array:: ArrayRef , error:: ArrowError } ;
2325use datafusion:: {
2426 error:: { DataFusionError , Result } ,
2527 scalar:: ScalarValue ,
2628} ;
27- use datafusion_common:: config:: { ConfigEntry , ExtensionOptions } ;
29+ use datafusion_common:: config:: { ConfigEntry , ConfigExtension , ExtensionOptions } ;
2830use prost:: Message ;
29-
31+ use datafusion_common :: exec_err ;
3032use crate :: { arrow_wrappers:: WrappedArray , df_result, rresult, rresult_return} ;
3133
3234/// A stable struct for sharing [`ExtensionOptions`] across FFI boundaries.
@@ -38,10 +40,14 @@ use crate::{arrow_wrappers::WrappedArray, df_result, rresult, rresult_return};
3840pub struct FFI_ExtensionOptions {
3941 pub cloned : unsafe extern "C" fn ( & Self ) -> FFI_ExtensionOptions ,
4042
41- pub set : unsafe extern "C" fn ( & mut Self , key : RStr , value : RStr ) -> RResult < ( ) , RString > ,
43+ pub set :
44+ unsafe extern "C" fn ( & mut Self , key : RStr , value : RStr ) -> RResult < ( ) , RString > ,
4245
43- pub entries :
44- unsafe extern "C" fn ( & Self ) -> RVec < Tuple3 < RString , ROption < RString > , RStr > > ,
46+ pub entries : unsafe extern "C" fn (
47+ & Self ,
48+ ) -> RVec <
49+ Tuple3 < RString , ROption < RString > , RStr < ' static > > ,
50+ > ,
4551
4652 /// Release the memory of the private data when it is no longer being used.
4753 pub release : unsafe extern "C" fn ( & mut Self ) ,
@@ -55,24 +61,26 @@ unsafe impl Send for FFI_ExtensionOptions {}
5561unsafe impl Sync for FFI_ExtensionOptions { }
5662
5763pub struct ExtensionOptionsPrivateData {
58- pub options : Box < dyn ExtensionOptions > ,
64+ pub options : HashMap < String , String > ,
5965}
6066
6167impl FFI_ExtensionOptions {
6268 #[ inline]
63- unsafe fn inner_mut ( & mut self ) -> & mut Box < dyn ExtensionOptions > {
69+ unsafe fn inner_mut ( & mut self ) -> & mut HashMap < String , String > {
6470 let private_data = self . private_data as * mut ExtensionOptionsPrivateData ;
6571 & mut ( * private_data) . options
6672 }
6773
6874 #[ inline]
69- unsafe fn inner ( & self ) -> & dyn ExtensionOptions {
75+ unsafe fn inner ( & self ) -> & HashMap < String , String > {
7076 let private_data = self . private_data as * const ExtensionOptionsPrivateData ;
71- ( * private_data) . options . deref ( )
77+ & ( * private_data) . options
7278 }
7379}
7480
75- unsafe extern "C" fn cloned_fn_wrapper ( options : & FFI_ExtensionOptions ) -> FFI_ExtensionOptions {
81+ unsafe extern "C" fn cloned_fn_wrapper (
82+ options : & FFI_ExtensionOptions ,
83+ ) -> FFI_ExtensionOptions {
7684 options. inner ( ) . cloned ( ) . into ( )
7785}
7886
@@ -81,19 +89,24 @@ unsafe extern "C" fn set_fn_wrapper(
8189 key : RStr ,
8290 value : RStr ,
8391) -> RResult < ( ) , RString > {
84- let key = key. as_str ( ) ;
85- let value = value. as_str ( ) ;
86-
87- rresult ! ( options. inner_mut( ) . set( key, value) )
92+ rresult ! ( options. inner_mut( ) . set( key. into( ) , value. into( ) ) )
8893}
8994
9095unsafe extern "C" fn entries_fn_wrapper (
9196 options : & FFI_ExtensionOptions ,
92- ) -> RVec < Tuple3 < RString , ROption < RString > , RStr > > {
93- options. inner ( )
97+ ) -> RVec < Tuple3 < RString , ROption < RString > , RStr < ' static > > > {
98+ options
99+ . inner ( )
94100 . entries ( )
95101 . into_iter ( )
96- . map ( |entry| ( entry. key . into ( ) , entry. value . map ( Into :: into) . into ( ) , entry. description . into ( ) ) . into ( ) )
102+ . map ( |entry| {
103+ (
104+ entry. key . into ( ) ,
105+ entry. value . map ( Into :: into) . into ( ) ,
106+ entry. description . into ( ) ,
107+ )
108+ . into ( )
109+ } )
97110 . collect ( )
98111}
99112
@@ -103,9 +116,9 @@ unsafe extern "C" fn release_fn_wrapper(options: &mut FFI_ExtensionOptions) {
103116 drop ( private_data) ;
104117}
105118
106- impl From < Box < dyn ExtensionOptions > > for FFI_ExtensionOptions {
107- fn from ( options : Box < dyn ExtensionOptions > ) -> Self {
108- let private_data = ExtensionOptionsPrivateData { options } ;
119+ impl Default for FFI_ExtensionOptions {
120+ fn default ( ) -> Self {
121+ let private_data = ExtensionOptionsPrivateData { options : HashMap :: new ( ) } ;
109122
110123 Self {
111124 cloned : cloned_fn_wrapper,
@@ -135,12 +148,34 @@ pub struct ForeignExtensionOptions(FFI_ExtensionOptions);
135148unsafe impl Send for ForeignExtensionOptions { }
136149unsafe impl Sync for ForeignExtensionOptions { }
137150
138- impl From < FFI_ExtensionOptions > for ForeignExtensionOptions {
139- fn from ( options : FFI_ExtensionOptions ) -> Self {
140- Self ( options)
151+ impl < T : ConfigExtension + Default > TryFrom < FFI_ExtensionOptions > for T {
152+ type Error = DataFusionError ;
153+
154+ fn try_from ( options : & FFI_ExtensionOptions ) -> Result < Self , Self :: Error > {
155+ let mut config = T :: default ( ) ;
156+
157+ let mut found = false ;
158+ unsafe {
159+ for entry_tuple in ( options. entries ) ( & options)
160+ . into_iter ( ) {
161+ if let ROption :: RSome ( value) = entry_tuple. 1
162+ && let Some ( ( namespace, key) ) = entry_tuple. 0 . as_str ( ) . split_once ( '.' ) {
163+ if namespace == T :: PREFIX {
164+ found = true ;
165+ config. set ( key, value. as_str ( ) ) ?;
166+ }
167+ }
168+ }
169+ }
170+
171+ Ok ( config)
141172 }
142173}
143174
175+ impl ConfigExtension for ForeignExtensionOptions {
176+ const PREFIX : & ' static str = "datafusion_ffi" ;
177+ }
178+
144179impl ExtensionOptions for ForeignExtensionOptions {
145180 fn as_any ( & self ) -> & dyn Any {
146181 self
@@ -151,31 +186,44 @@ impl ExtensionOptions for ForeignExtensionOptions {
151186 }
152187
153188 fn cloned ( & self ) -> Box < dyn ExtensionOptions > {
154- ( self . 0 . cloned ) ( & self . 0 ) . into ( )
189+ unsafe { ( self . 0 . cloned ) ( & self . 0 ) . into ( ) }
155190 }
156191
157192 fn set ( & mut self , key : & str , value : & str ) -> Result < ( ) > {
158- df_result ! ( {
159- ( self . 0 . set) ( & mut self . 0 , key. into( ) , value. into( ) )
160- } )
193+ let Some ( ( namespace, key) ) = key. split_once ( '.' ) else {
194+ return exec_err ! ( "Unable to set FFI config value without namespace set" ) ;
195+ } ;
196+
197+ if namespace != ForeignExtensionOptions :: PREFIX {
198+ return exec_err ! ( "Unexpected namespace {namespace} set for FFI config" ) ;
199+ }
200+
201+ df_result ! ( unsafe { ( self . 0 . set) ( & mut self . 0 , key. into( ) , value. into( ) ) } )
161202 }
162203
163204 fn entries ( & self ) -> Vec < ConfigEntry > {
164- ( self . 0 . entries ) ( & self . 0 ) . into_iter ( )
165- . map ( |entry_tuple| ConfigEntry {
166- key : entry_tuple. 0 . into ( ) ,
167- value : entry_tuple. 1 . into ( ) ,
168- description : entry_tuple. 2 . into ( ) ,
169- } )
170- . collect ( )
205+ unsafe {
206+ ( self . 0 . entries ) ( & self . 0 )
207+ . into_iter ( )
208+ . map ( |entry_tuple| ConfigEntry {
209+ key : entry_tuple. 0 . into ( ) ,
210+ value : entry_tuple. 1 . map ( Into :: into) . into ( ) ,
211+ description : entry_tuple. 2 . into ( ) ,
212+ } )
213+ . collect ( )
214+ }
171215 }
172216}
173217
174218#[ cfg( test) ]
175219mod tests {
176220 use datafusion_common:: {
177- config:: ConfigExtension , config:: ConfigOptions , extensions_options,
221+ config:: { ConfigExtension , ConfigOptions , ExtensionOptions } ,
222+ extensions_options,
178223 } ;
224+
225+ use crate :: config_options:: FFI_ExtensionOptions ;
226+
179227 // Define a new configuration struct using the `extensions_options` macro
180228 extensions_options ! {
181229 /// My own config options.
@@ -194,10 +242,10 @@ mod tests {
194242
195243 #[ test]
196244 fn round_trip_ffi_extension_options ( ) {
197-
198245 // set up config struct and register extension
199246 let mut config = ConfigOptions :: default ( ) ;
200- config. extensions . insert ( MyConfig :: default ( ) ) ;
247+ config. extensions . insert ( FFI_ExtensionOptions :: default ( ) ) ;
248+ // config.extensions.insert(MyConfig::default());
201249
202250 // overwrite config default
203251 config. set ( "my_config.baz_count" , "42" ) . unwrap ( ) ;
@@ -207,5 +255,11 @@ mod tests {
207255 assert ! ( my_config. foo_to_bar, ) ;
208256 assert_eq ! ( my_config. baz_count, 42 , ) ;
209257
258+ // let boxed_config = Box::new(MyConfig::default()) as Box<dyn ExtensionOptions>;
259+ // let mut ffi_config = FFI_ExtensionOptions::from(boxed_config);
260+ // ffi_config.library_marker_id = crate::mock_foreign_marker_id;
261+ // let foreign_config: Box<dyn ExtensionOptions> = ffi_config.into();
262+ //
263+ // config.extensions.insert(foreign_config);
210264 }
211265}
0 commit comments