Skip to main content

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 datafusion_common::{DataFusionError, ScalarValue};
19use datafusion_expr::ColumnarValue;
20
21use crate::arrow_wrappers::WrappedArray;
22
23/// A stable struct for sharing [`ColumnarValue`] across FFI boundaries.
24/// Scalar values are passed as an Arrow array of length 1.
25#[repr(C, u8)]
26#[derive(Debug)]
27pub enum FFI_ColumnarValue {
28    Array(WrappedArray),
29    Scalar(WrappedArray),
30}
31
32impl TryFrom<ColumnarValue> for FFI_ColumnarValue {
33    type Error = DataFusionError;
34    fn try_from(value: ColumnarValue) -> Result<Self, Self::Error> {
35        Ok(match value {
36            ColumnarValue::Array(v) => {
37                FFI_ColumnarValue::Array(WrappedArray::try_from(&v)?)
38            }
39            ColumnarValue::Scalar(v) => {
40                FFI_ColumnarValue::Scalar(WrappedArray::try_from(&v)?)
41            }
42        })
43    }
44}
45
46impl TryFrom<FFI_ColumnarValue> for ColumnarValue {
47    type Error = DataFusionError;
48    fn try_from(value: FFI_ColumnarValue) -> Result<Self, Self::Error> {
49        Ok(match value {
50            FFI_ColumnarValue::Array(v) => ColumnarValue::Array(v.try_into()?),
51            FFI_ColumnarValue::Scalar(v) => {
52                ColumnarValue::Scalar(ScalarValue::try_from(v)?)
53            }
54        })
55    }
56}
57
58#[cfg(test)]
59mod tests {
60    use arrow::array::create_array;
61    use datafusion_common::{DataFusionError, ScalarValue};
62    use datafusion_expr::ColumnarValue;
63
64    use crate::expr::columnar_value::FFI_ColumnarValue;
65
66    #[test]
67    fn ffi_columnar_value_round_trip() -> Result<(), DataFusionError> {
68        let array = create_array!(Int32, [1, 2, 3, 4, 5]);
69
70        for original in [
71            ColumnarValue::Array(array),
72            ColumnarValue::Scalar(ScalarValue::Int32(Some(1))),
73        ] {
74            let ffi_variant = FFI_ColumnarValue::try_from(original.clone())?;
75
76            let returned_value = ColumnarValue::try_from(ffi_variant)?;
77
78            assert_eq!(format!("{returned_value:?}"), format!("{original:?}"));
79        }
80
81        Ok(())
82    }
83}