@@ -27,17 +27,23 @@ use datafusion_common::{Result, exec_err};
2727use crate :: df_result;
2828
2929/// A stable struct for sharing [`ExtensionOptions`] across FFI boundaries.
30- /// For an explanation of each field, see the corresponding function
31- /// defined in [`ExtensionOptions`].
30+ ///
31+ /// Unlike other FFI structs in this crate, we do not construct a foreign
32+ /// variant of this object. This is due to the typical method for interacting
33+ /// with extension options is by creating a local struct of your concrete type.
34+ /// To support this methodology use the `to_extension` method instead.
3235#[ repr( C ) ]
3336#[ derive( Debug , StableAbi ) ]
3437#[ allow( non_camel_case_types) ]
3538pub struct FFI_ExtensionOptions {
39+ /// Return a deep clone of this [`ExtensionOptions`]
3640 pub cloned : unsafe extern "C" fn ( & Self ) -> FFI_ExtensionOptions ,
3741
42+ /// Set the given `key`, `value` pair
3843 pub set :
3944 unsafe extern "C" fn ( & mut Self , key : RStr , value : RStr ) -> RResult < ( ) , RString > ,
4045
46+ /// Returns the [`ConfigEntry`] stored in this [`ExtensionOptions`]
4147 pub entries : unsafe extern "C" fn ( & Self ) -> RVec < Tuple2 < RString , RString > > ,
4248
4349 /// Release the memory of the private data when it is no longer being used.
@@ -48,19 +54,6 @@ pub struct FFI_ExtensionOptions {
4854 pub private_data : * mut c_void ,
4955}
5056
51- // TODO(tsaucer) We have a problem in datafusion_common::config::Extension::get
52- // which relies on knowing the concrete types of the extensions so that we can
53- // use their PREFIX for insertion of configs. We cannot work around this using
54- // things like `fn namespace() -> &'static str` because we must be able to do
55- // this without having an instance. Instead we will go to an approach of having
56- // a concrete FFI_ForeignConfigExtension and add a check into all of the methods
57- // in the above `get` (and similar) methods to check to see if we have an FFI
58- // configs. If so we get the concrete FFI config and then have a method that will
59- // convert from FFI_ForeignExtensionConfig into the concrete type. Somehow our
60- // FFI library will need to make this as easy an experience as they are used to
61- // so maybe we need to implement something at the `Extensions` level in addition
62- // to the ConfigExtension.
63-
6457unsafe impl Send for FFI_ExtensionOptions { }
6558unsafe impl Sync for FFI_ExtensionOptions { }
6659
@@ -147,41 +140,7 @@ impl Drop for FFI_ExtensionOptions {
147140
148141impl Clone for FFI_ExtensionOptions {
149142 fn clone ( & self ) -> Self {
150- unsafe { ( self . cloned ) ( & self ) }
151- }
152- }
153-
154- /// This struct is used to access an UDF provided by a foreign
155- /// library across a FFI boundary.
156- ///
157- /// The ForeignExtensionOptions is to be used by the caller of the UDF, so it has
158- /// no knowledge or access to the private data. All interaction with the UDF
159- /// must occur through the functions defined in FFI_ExtensionOptions.
160- // #[derive(Debug)]
161- // pub struct ForeignExtensionOptions(FFI_ExtensionOptions);
162- //
163- // unsafe impl Send for ForeignExtensionOptions {}
164- // unsafe impl Sync for ForeignExtensionOptions {}
165-
166- impl FFI_ExtensionOptions {
167- pub fn add_config < C : ConfigExtension > ( & mut self , config : & C ) -> Result < ( ) > {
168- for entry in config. entries ( ) {
169- if let Some ( value) = entry. value {
170- let key = format ! ( "{}.{}" , C :: PREFIX , entry. key) ;
171- self . set ( key. as_str ( ) , value. as_str ( ) ) ?;
172- }
173- }
174-
175- Ok ( ( ) )
176- }
177-
178- pub fn merge ( & mut self , other : & FFI_ExtensionOptions ) -> Result < ( ) > {
179- for entry in other. entries ( ) {
180- if let Some ( value) = entry. value {
181- self . set ( entry. key . as_str ( ) , value. as_str ( ) ) ?;
182- }
183- }
184- Ok ( ( ) )
143+ unsafe { ( self . cloned ) ( self ) }
185144 }
186145}
187146
@@ -199,7 +158,7 @@ impl ExtensionOptions for FFI_ExtensionOptions {
199158 }
200159
201160 fn cloned ( & self ) -> Box < dyn ExtensionOptions > {
202- let ffi_options = unsafe { ( self . cloned ) ( & self ) } ;
161+ let ffi_options = unsafe { ( self . cloned ) ( self ) } ;
203162 Box :: new ( ffi_options)
204163 }
205164
@@ -213,7 +172,7 @@ impl ExtensionOptions for FFI_ExtensionOptions {
213172
214173 fn entries ( & self ) -> Vec < ConfigEntry > {
215174 unsafe {
216- ( self . entries ) ( & self )
175+ ( self . entries ) ( self )
217176 . into_iter ( )
218177 . map ( |entry_tuple| ConfigEntry {
219178 key : entry_tuple. 0 . into ( ) ,
@@ -226,11 +185,38 @@ impl ExtensionOptions for FFI_ExtensionOptions {
226185}
227186
228187impl FFI_ExtensionOptions {
188+ /// Add all of the values in a concrete configuration extension to the
189+ /// FFI variant. This is safe to call on either side of the FFI
190+ /// boundary.
191+ pub fn add_config < C : ConfigExtension > ( & mut self , config : & C ) -> Result < ( ) > {
192+ for entry in config. entries ( ) {
193+ if let Some ( value) = entry. value {
194+ let key = format ! ( "{}.{}" , C :: PREFIX , entry. key) ;
195+ self . set ( key. as_str ( ) , value. as_str ( ) ) ?;
196+ }
197+ }
198+
199+ Ok ( ( ) )
200+ }
201+
202+ /// Merge another `FFI_ExtensionOptions` configurations into this one.
203+ /// This is safe to call on either side of the FFI boundary.
204+ pub fn merge ( & mut self , other : & FFI_ExtensionOptions ) -> Result < ( ) > {
205+ for entry in other. entries ( ) {
206+ if let Some ( value) = entry. value {
207+ self . set ( entry. key . as_str ( ) , value. as_str ( ) ) ?;
208+ }
209+ }
210+ Ok ( ( ) )
211+ }
212+
213+ /// Create a concrete extension type from the FFI variant.
214+ /// This is safe to call on either side of the FFI boundary.
229215 pub fn to_extension < C : ConfigExtension + Default > ( & self ) -> Result < C > {
230216 let mut result = C :: default ( ) ;
231217
232218 unsafe {
233- for entry in ( self . entries ) ( & self ) {
219+ for entry in ( self . entries ) ( self ) {
234220 let key = entry. 0 . as_str ( ) ;
235221 let value = entry. 1 . as_str ( ) ;
236222
0 commit comments