1use std::sync::Arc;
19
20use abi_stable::std_types::{RResult, RString, RVec};
21use arrow::datatypes::{DataType, Field};
22use arrow::ffi::FFI_ArrowSchema;
23use arrow_schema::FieldRef;
24
25use crate::arrow_wrappers::WrappedSchema;
26
27pub type FFIResult<T> = RResult<T, RString>;
33
34#[macro_export]
37macro_rules! df_result {
38 ( $x:expr ) => {
39 match $x {
40 abi_stable::std_types::RResult::ROk(v) => Ok(v),
41 abi_stable::std_types::RResult::RErr(err) => {
42 datafusion_common::ffi_err!("{err}")
43 }
44 }
45 };
46}
47
48#[macro_export]
50macro_rules! rresult {
51 ( $x:expr ) => {
52 match $x {
53 Ok(v) => abi_stable::std_types::RResult::ROk(v),
54 Err(e) => abi_stable::std_types::RResult::RErr(
55 abi_stable::std_types::RString::from(e.to_string()),
56 ),
57 }
58 };
59}
60
61#[macro_export]
65macro_rules! rresult_return {
66 ( $x:expr ) => {
67 match $x {
68 Ok(v) => v,
69 Err(e) => {
70 return abi_stable::std_types::RResult::RErr(
71 abi_stable::std_types::RString::from(e.to_string()),
72 )
73 }
74 }
75 };
76}
77
78pub fn vec_fieldref_to_rvec_wrapped(
81 fields: &[FieldRef],
82) -> Result<RVec<WrappedSchema>, arrow::error::ArrowError> {
83 Ok(fields
84 .iter()
85 .map(FFI_ArrowSchema::try_from)
86 .collect::<Result<Vec<_>, arrow::error::ArrowError>>()?
87 .into_iter()
88 .map(WrappedSchema)
89 .collect())
90}
91
92pub fn rvec_wrapped_to_vec_fieldref(
95 fields: &RVec<WrappedSchema>,
96) -> Result<Vec<FieldRef>, arrow::error::ArrowError> {
97 fields
98 .iter()
99 .map(|d| Field::try_from(&d.0).map(Arc::new))
100 .collect()
101}
102
103pub fn vec_datatype_to_rvec_wrapped(
106 data_types: &[DataType],
107) -> Result<RVec<WrappedSchema>, arrow::error::ArrowError> {
108 Ok(data_types
109 .iter()
110 .map(FFI_ArrowSchema::try_from)
111 .collect::<Result<Vec<_>, arrow::error::ArrowError>>()?
112 .into_iter()
113 .map(WrappedSchema)
114 .collect())
115}
116
117pub fn rvec_wrapped_to_vec_datatype(
120 data_types: &RVec<WrappedSchema>,
121) -> Result<Vec<DataType>, arrow::error::ArrowError> {
122 data_types
123 .iter()
124 .map(|d| DataType::try_from(&d.0))
125 .collect()
126}
127
128#[cfg(test)]
129pub(crate) mod tests {
130 use std::sync::Arc;
131
132 use abi_stable::std_types::{RResult, RString};
133 use datafusion::error::DataFusionError;
134 use datafusion::prelude::SessionContext;
135 use datafusion_execution::TaskContextProvider;
136
137 use crate::execution::FFI_TaskContextProvider;
138 use crate::util::FFIResult;
139
140 pub(crate) fn test_session_and_ctx() -> (Arc<SessionContext>, FFI_TaskContextProvider)
141 {
142 let ctx = Arc::new(SessionContext::new());
143 let task_ctx_provider = Arc::clone(&ctx) as Arc<dyn TaskContextProvider>;
144 let task_ctx_provider = FFI_TaskContextProvider::from(&task_ctx_provider);
145
146 (ctx, task_ctx_provider)
147 }
148
149 fn wrap_result(result: Result<String, DataFusionError>) -> FFIResult<String> {
150 RResult::ROk(rresult_return!(result))
151 }
152
153 #[test]
154 fn test_conversion() {
155 const VALID_VALUE: &str = "valid_value";
156 const ERROR_VALUE: &str = "error_value";
157
158 let ok_r_result: FFIResult<RString> =
159 RResult::ROk(VALID_VALUE.to_string().into());
160 let err_r_result: FFIResult<RString> =
161 RResult::RErr(ERROR_VALUE.to_string().into());
162
163 let returned_ok_result = df_result!(ok_r_result);
164 assert!(returned_ok_result.is_ok());
165 assert!(returned_ok_result.unwrap().to_string() == VALID_VALUE);
166
167 let returned_err_result = df_result!(err_r_result);
168 assert!(returned_err_result.is_err());
169 assert!(
170 returned_err_result.unwrap_err().strip_backtrace()
171 == format!("FFI error: {ERROR_VALUE}")
172 );
173
174 let ok_result: Result<String, DataFusionError> = Ok(VALID_VALUE.to_string());
175 let err_result: Result<String, DataFusionError> =
176 datafusion_common::ffi_err!("{ERROR_VALUE}");
177
178 let returned_ok_r_result = wrap_result(ok_result);
179 assert!(returned_ok_r_result == RResult::ROk(VALID_VALUE.into()));
180
181 let returned_err_r_result = wrap_result(err_result);
182 assert!(returned_err_r_result.is_err());
183 assert!(
184 returned_err_r_result
185 .unwrap_err()
186 .starts_with(format!("FFI error: {ERROR_VALUE}").as_str())
187 );
188 }
189}