time_series_data_packer_rs 0.4.1

Time series data packer written in Rust language for data intensive IoT and IIoT projects.
Documentation
use crate::TSPackedSamples;
use crate::TSSamples;

use crate::TSPackAttributes;
use crate::TSPackStrategyType;
use crate::TimeSeriesDataPacker;

fn f64_to_bits(v: f64) -> u64 {
    v.to_bits()
}

fn bits_to_f64(b: u64) -> f64 {
    f64::from_bits(b)
}

pub fn xor_pack(samples: &[TSSamples]) -> Vec<TSPackedSamples> {
    if samples.is_empty() {
        return Vec::new();
    }

    let mut result: Vec<TSPackedSamples> = Vec::new();

    let mut prev_bits = f64_to_bits(samples[0].1);
    result.push(((samples[0].0, samples[0].0), samples[0].1));

    for &(ts, val) in &samples[1..] {
        let bits = f64_to_bits(val);
        let xor = prev_bits ^ bits;

        let xor_as_f64 = bits_to_f64(xor);
        result.push(((ts, ts), xor_as_f64));
        prev_bits = bits;
    }

    result
}

pub fn xor_unpack(packed: &[TSPackedSamples]) -> Vec<TSSamples> {
    if packed.is_empty() {
        return Vec::new();
    }

    let mut result: Vec<TSSamples> = Vec::new();

    let first_val = packed[0].1;
    result.push((packed[0].0 .0, first_val));

    let mut prev_bits = f64_to_bits(first_val);

    for &((ts, _), xor_as_f64) in &packed[1..] {
        let xor_bits = f64_to_bits(xor_as_f64);
        let new_bits = prev_bits ^ xor_bits;
        let new_val = bits_to_f64(new_bits);
        result.push((ts, new_val));
        prev_bits = new_bits;
    }

    result
}

#[cfg(test)]
mod xor_gorilla_tests {
    use super::*;

    #[test]
    fn test_xor_pack_unpack_roundtrip() {
        let samples = vec![(0.0, 100.0), (0.1, 101.0), (0.2, 105.5), (0.3, -50.25)];

        let packed = xor_pack(&samples);
        let unpacked = xor_unpack(&packed);

        assert_eq!(samples.len(), unpacked.len());
        for (orig, rec) in samples.iter().zip(unpacked.iter()) {
            assert!((orig.0 - rec.0).abs() < 1e-12);
            assert!((orig.1 - rec.1).abs() < 1e-12);
        }
    }

    #[test]
    fn test_xor_strategy_integration() {
        let samples = vec![(0.0, 10.0), (0.1, 20.0), (0.2, 30.0)];

        let mut packer = TimeSeriesDataPacker::new();
        let attrs = TSPackAttributes {
            strategy_types: vec![TSPackStrategyType::TSPackXorStrategy],
            microseconds_time_window: 1_000_000,
        };

        let packed = packer.pack(samples.clone(), attrs).unwrap();
        let unpacked = xor_unpack(&packed);

        assert_eq!(samples.len(), unpacked.len());
        for (orig, rec) in samples.iter().zip(unpacked.iter()) {
            assert!((orig.1 - rec.1).abs() < 1e-12);
        }
    }

    #[test]
    fn test_xor_empty() {
        let samples: Vec<TSSamples> = vec![];
        let packed = xor_pack(&samples);
        let unpacked = xor_unpack(&packed);
        assert!(packed.is_empty());
        assert!(unpacked.is_empty());
    }
}