use std::sync::Arc;
use arrow::array::{ArrayRef, Float64Array, Int64Array};
use crate::preprocess::{Interpolator, PreprocessConfig, PreprocessPipeline, Smoother};
#[derive(Debug)]
pub struct ArrowPreprocessResult {
pub values: Float64Array,
pub timestamps: Int64Array,
pub gaps_filled: usize,
}
impl ArrowPreprocessResult {
pub fn values_array_ref(&self) -> ArrayRef {
Arc::new(self.values.clone())
}
pub fn timestamps_array_ref(&self) -> ArrayRef {
Arc::new(self.timestamps.clone())
}
}
pub fn arrow_interpolate(
interpolator: &Interpolator,
timestamps: &Int64Array,
values: &Float64Array,
expected_interval_ns: i64,
) -> Result<ArrowPreprocessResult, crate::preprocess::interpolation::InterpolationError> {
let ts_slice = timestamps.values().as_ref();
let val_slice = values.values().as_ref();
let (out_ts, out_vals, gaps_filled, _gaps_skipped) =
interpolator.fill(ts_slice, val_slice, expected_interval_ns)?;
Ok(ArrowPreprocessResult {
values: Float64Array::from(out_vals),
timestamps: Int64Array::from(out_ts),
gaps_filled,
})
}
pub fn arrow_smooth(smoother: &Smoother, values: &Float64Array) -> Float64Array {
let slice = values.values().as_ref();
Float64Array::from(smoother.smooth(slice))
}
pub fn arrow_preprocess(
config: &PreprocessConfig,
timestamps: &Int64Array,
values: &Float64Array,
) -> Result<ArrowPreprocessResult, crate::preprocess::PreprocessError> {
let ts_slice = timestamps.values().as_ref();
let val_slice = values.values().as_ref();
let result = PreprocessPipeline::run(config, ts_slice, val_slice)?;
Ok(ArrowPreprocessResult {
values: Float64Array::from(result.values),
timestamps: Int64Array::from(result.timestamps),
gaps_filled: result.gaps_filled,
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn arrow_interpolate_zero_copy() {
let ts = Int64Array::from(vec![0, 1_000_000_000, 3_000_000_000, 4_000_000_000]);
let vals = Float64Array::from(vec![1.0, 2.0, 4.0, 5.0]);
let result = arrow_interpolate(&Interpolator::Linear, &ts, &vals, 1_000_000_000).unwrap();
assert!(result.gaps_filled > 0);
assert!(result.values.len() >= 4);
assert!(result.timestamps.len() == result.values.len());
}
#[test]
fn arrow_smooth_produces_float64array() {
let vals = Float64Array::from(vec![1.0, 3.0, 5.0, 7.0, 9.0, 11.0]);
let smoother = Smoother::MovingAverage { window: 3 };
let smoothed = arrow_smooth(&smoother, &vals);
assert_eq!(smoothed.len(), vals.len());
assert!((smoothed.value(2) - 5.0).abs() < 1e-10);
}
#[test]
fn arrow_preprocess_pipeline() {
let ts = Int64Array::from(vec![0i64, 1_000_000_000, 2_000_000_000, 3_000_000_000]);
let vals = Float64Array::from(vec![10.0, 20.0, 30.0, 40.0]);
let config = PreprocessConfig {
smoothing: Some(Smoother::Exponential { alpha: 0.3 }),
..PreprocessConfig::default()
};
let result = arrow_preprocess(&config, &ts, &vals).unwrap();
assert_eq!(result.values.len(), 4);
}
#[test]
fn arrow_result_array_refs() {
let result = ArrowPreprocessResult {
values: Float64Array::from(vec![1.0, 2.0]),
timestamps: Int64Array::from(vec![100, 200]),
gaps_filled: 0,
};
let val_ref = result.values_array_ref();
assert_eq!(val_ref.len(), 2);
let ts_ref = result.timestamps_array_ref();
assert_eq!(ts_ref.len(), 2);
}
}