Skip to content

Commit 280e815

Browse files
committed
wip
1 parent e9fd408 commit 280e815

1 file changed

Lines changed: 94 additions & 40 deletions

File tree

datafusion/ffi/src/config_options.rs

Lines changed: 94 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,19 @@
1616
// under the License.
1717

1818
use 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+
};
2224
use arrow::{array::ArrayRef, error::ArrowError};
2325
use datafusion::{
2426
error::{DataFusionError, Result},
2527
scalar::ScalarValue,
2628
};
27-
use datafusion_common::config::{ConfigEntry, ExtensionOptions};
29+
use datafusion_common::config::{ConfigEntry, ConfigExtension, ExtensionOptions};
2830
use prost::Message;
29-
31+
use datafusion_common::exec_err;
3032
use 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};
3840
pub 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 {}
5561
unsafe impl Sync for FFI_ExtensionOptions {}
5662

5763
pub struct ExtensionOptionsPrivateData {
58-
pub options: Box<dyn ExtensionOptions>,
64+
pub options: HashMap<String, String>,
5965
}
6066

6167
impl 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

9095
unsafe 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);
135148
unsafe impl Send for ForeignExtensionOptions {}
136149
unsafe 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+
144179
impl 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)]
175219
mod 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

Comments
 (0)