datafusion_ffi/expr/
columnar_value.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18use abi_stable::StableAbi;
19use datafusion_common::{DataFusionError, ScalarValue};
20use datafusion_expr::ColumnarValue;
21
22use crate::arrow_wrappers::WrappedArray;
23
24/// A stable struct for sharing [`ColumnarValue`] across FFI boundaries.
25/// Scalar values are passed as an Arrow array of length 1.
26#[repr(C)]
27#[derive(Debug, StableAbi)]
28pub enum FFI_ColumnarValue {
29    Array(WrappedArray),
30    Scalar(WrappedArray),
31}
32
33impl TryFrom<ColumnarValue> for FFI_ColumnarValue {
34    type Error = DataFusionError;
35    fn try_from(value: ColumnarValue) -> Result<Self, Self::Error> {
36        Ok(match value {
37            ColumnarValue::Array(v) => {
38                FFI_ColumnarValue::Array(WrappedArray::try_from(&v)?)
39            }
40            ColumnarValue::Scalar(v) => {
41                FFI_ColumnarValue::Scalar(WrappedArray::try_from(&v)?)
42            }
43        })
44    }
45}
46
47impl TryFrom<FFI_ColumnarValue> for ColumnarValue {
48    type Error = DataFusionError;
49    fn try_from(value: FFI_ColumnarValue) -> Result<Self, Self::Error> {
50        Ok(match value {
51            FFI_ColumnarValue::Array(v) => ColumnarValue::Array(v.try_into()?),
52            FFI_ColumnarValue::Scalar(v) => {
53                ColumnarValue::Scalar(ScalarValue::try_from(v)?)
54            }
55        })
56    }
57}
58
59#[cfg(test)]
60mod tests {
61    use arrow::array::create_array;
62    use datafusion_common::{DataFusionError, ScalarValue};
63    use datafusion_expr::ColumnarValue;
64
65    use crate::expr::columnar_value::FFI_ColumnarValue;
66
67    #[test]
68    fn ffi_columnar_value_round_trip() -> Result<(), DataFusionError> {
69        let array = create_array!(Int32, [1, 2, 3, 4, 5]);
70
71        for original in [
72            ColumnarValue::Array(array),
73            ColumnarValue::Scalar(ScalarValue::Int32(Some(1))),
74        ] {
75            let ffi_variant = FFI_ColumnarValue::try_from(original.clone())?;
76
77            let returned_value = ColumnarValue::try_from(ffi_variant)?;
78
79            assert_eq!(format!("{returned_value:?}"), format!("{original:?}"));
80        }
81
82        Ok(())
83    }
84}