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