Skip to main content

datafusion_ffi/expr/
distribution.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
18//! FFI types for the deprecated Statistics V2 [`Distribution`] framework.
19//!
20//! These FFI types mirror the deprecated probabilistic distribution types.
21//! See <https://github.com/apache/datafusion/pull/22071> for details.
22
23#![allow(deprecated)]
24
25use datafusion_common::DataFusionError;
26use datafusion_expr::statistics::{
27    BernoulliDistribution, Distribution, ExponentialDistribution, GaussianDistribution,
28    GenericDistribution, UniformDistribution,
29};
30
31use crate::arrow_wrappers::WrappedArray;
32use crate::expr::interval::FFI_Interval;
33
34/// A stable struct for sharing [`Distribution`] across FFI boundaries.
35/// See ['Distribution'] for the meaning of each variant.
36#[repr(C)]
37#[derive(Debug)]
38#[expect(clippy::large_enum_variant)]
39pub enum FFI_Distribution {
40    Uniform(FFI_UniformDistribution),
41    Exponential(FFI_ExponentialDistribution),
42    Gaussian(FFI_GaussianDistribution),
43    Bernoulli(FFI_BernoulliDistribution),
44    Generic(FFI_GenericDistribution),
45}
46
47impl TryFrom<&Distribution> for FFI_Distribution {
48    type Error = DataFusionError;
49    fn try_from(value: &Distribution) -> Result<Self, Self::Error> {
50        match value {
51            Distribution::Uniform(d) => Ok(FFI_Distribution::Uniform(d.try_into()?)),
52            Distribution::Exponential(d) => {
53                Ok(FFI_Distribution::Exponential(d.try_into()?))
54            }
55            Distribution::Gaussian(d) => Ok(FFI_Distribution::Gaussian(d.try_into()?)),
56            Distribution::Bernoulli(d) => Ok(FFI_Distribution::Bernoulli(d.try_into()?)),
57            Distribution::Generic(d) => Ok(FFI_Distribution::Generic(d.try_into()?)),
58        }
59    }
60}
61
62impl TryFrom<FFI_Distribution> for Distribution {
63    type Error = DataFusionError;
64    fn try_from(value: FFI_Distribution) -> Result<Self, Self::Error> {
65        match value {
66            FFI_Distribution::Uniform(d) => d.try_into(),
67            FFI_Distribution::Exponential(d) => d.try_into(),
68            FFI_Distribution::Gaussian(d) => d.try_into(),
69            FFI_Distribution::Bernoulli(d) => d.try_into(),
70            FFI_Distribution::Generic(d) => d.try_into(),
71        }
72    }
73}
74
75#[repr(C)]
76#[derive(Debug)]
77pub struct FFI_UniformDistribution {
78    interval: FFI_Interval,
79}
80
81#[repr(C)]
82#[derive(Debug)]
83pub struct FFI_ExponentialDistribution {
84    rate: WrappedArray,
85    offset: WrappedArray,
86    positive_tail: bool,
87}
88
89#[repr(C)]
90#[derive(Debug)]
91pub struct FFI_GaussianDistribution {
92    mean: WrappedArray,
93    variance: WrappedArray,
94}
95
96#[repr(C)]
97#[derive(Debug)]
98pub struct FFI_BernoulliDistribution {
99    p: WrappedArray,
100}
101
102#[repr(C)]
103#[derive(Debug)]
104pub struct FFI_GenericDistribution {
105    mean: WrappedArray,
106    median: WrappedArray,
107    variance: WrappedArray,
108    range: FFI_Interval,
109}
110
111impl TryFrom<&UniformDistribution> for FFI_UniformDistribution {
112    type Error = DataFusionError;
113    fn try_from(value: &UniformDistribution) -> Result<Self, Self::Error> {
114        Ok(Self {
115            interval: value.range().try_into()?,
116        })
117    }
118}
119
120impl TryFrom<&ExponentialDistribution> for FFI_ExponentialDistribution {
121    type Error = DataFusionError;
122    fn try_from(value: &ExponentialDistribution) -> Result<Self, Self::Error> {
123        let rate = value.rate().try_into()?;
124        let offset = value.offset().try_into()?;
125
126        Ok(Self {
127            rate,
128            offset,
129            positive_tail: value.positive_tail(),
130        })
131    }
132}
133
134impl TryFrom<&GaussianDistribution> for FFI_GaussianDistribution {
135    type Error = DataFusionError;
136    fn try_from(value: &GaussianDistribution) -> Result<Self, Self::Error> {
137        let mean = value.mean().try_into()?;
138        let variance = value.variance().try_into()?;
139
140        Ok(Self { mean, variance })
141    }
142}
143
144impl TryFrom<&BernoulliDistribution> for FFI_BernoulliDistribution {
145    type Error = DataFusionError;
146    fn try_from(value: &BernoulliDistribution) -> Result<Self, Self::Error> {
147        let p = value.p_value().try_into()?;
148
149        Ok(Self { p })
150    }
151}
152
153impl TryFrom<&GenericDistribution> for FFI_GenericDistribution {
154    type Error = DataFusionError;
155    fn try_from(value: &GenericDistribution) -> Result<Self, Self::Error> {
156        let mean = value.mean().try_into()?;
157        let median = value.median().try_into()?;
158        let variance = value.variance().try_into()?;
159
160        Ok(Self {
161            mean,
162            median,
163            variance,
164            range: value.range().try_into()?,
165        })
166    }
167}
168
169impl TryFrom<FFI_UniformDistribution> for Distribution {
170    type Error = DataFusionError;
171    fn try_from(value: FFI_UniformDistribution) -> Result<Self, Self::Error> {
172        let interval = value.interval.try_into()?;
173        Distribution::new_uniform(interval)
174    }
175}
176
177impl TryFrom<FFI_ExponentialDistribution> for Distribution {
178    type Error = DataFusionError;
179    fn try_from(value: FFI_ExponentialDistribution) -> Result<Self, Self::Error> {
180        let rate = value.rate.try_into()?;
181        let offset = value.offset.try_into()?;
182
183        Distribution::new_exponential(rate, offset, value.positive_tail)
184    }
185}
186
187impl TryFrom<FFI_GaussianDistribution> for Distribution {
188    type Error = DataFusionError;
189    fn try_from(value: FFI_GaussianDistribution) -> Result<Self, Self::Error> {
190        let mean = value.mean.try_into()?;
191        let variance = value.variance.try_into()?;
192
193        Distribution::new_gaussian(mean, variance)
194    }
195}
196
197impl TryFrom<FFI_BernoulliDistribution> for Distribution {
198    type Error = DataFusionError;
199    fn try_from(value: FFI_BernoulliDistribution) -> Result<Self, Self::Error> {
200        let p = value.p.try_into()?;
201
202        Distribution::new_bernoulli(p)
203    }
204}
205
206impl TryFrom<FFI_GenericDistribution> for Distribution {
207    type Error = DataFusionError;
208    fn try_from(value: FFI_GenericDistribution) -> Result<Self, Self::Error> {
209        let mean = value.mean.try_into()?;
210        let median = value.median.try_into()?;
211        let variance = value.variance.try_into()?;
212        let range = value.range.try_into()?;
213
214        Distribution::new_generic(mean, median, variance, range)
215    }
216}