oxygengine-pws 0.20.0

Oxygen Engine procedural world simulation
#![allow(dead_code)]

use crate::Scalar;
use std::{fs::File, io::Write, path::Path};

pub trait DataAggregatorRenderer {
    fn render_columns(&self, columns: &mut Vec<String>);
}

impl DataAggregatorRenderer for Scalar {
    fn render_columns(&self, columns: &mut Vec<String>) {
        columns.push(self.to_string());
    }
}

impl<T> DataAggregatorRenderer for Vec<T>
where
    T: ToString,
{
    fn render_columns(&self, columns: &mut Vec<String>) {
        for item in self {
            columns.push(item.to_string());
        }
    }
}

impl<T> DataAggregatorRenderer for [T]
where
    T: ToString,
{
    fn render_columns(&self, columns: &mut Vec<String>) {
        for item in self {
            columns.push(item.to_string());
        }
    }
}

impl<T0, T1> DataAggregatorRenderer for (T0, T1)
where
    T0: ToString,
    T1: ToString,
{
    fn render_columns(&self, columns: &mut Vec<String>) {
        columns.push(self.0.to_string());
        columns.push(self.1.to_string());
    }
}

impl<T0, T1, T2> DataAggregatorRenderer for (T0, T1, T2)
where
    T0: ToString,
    T1: ToString,
    T2: ToString,
{
    fn render_columns(&self, columns: &mut Vec<String>) {
        columns.push(self.0.to_string());
        columns.push(self.1.to_string());
        columns.push(self.2.to_string());
    }
}

impl<T0, T1, T2, T3> DataAggregatorRenderer for (T0, T1, T2, T3)
where
    T0: ToString,
    T1: ToString,
    T2: ToString,
    T3: ToString,
{
    fn render_columns(&self, columns: &mut Vec<String>) {
        columns.push(self.0.to_string());
        columns.push(self.1.to_string());
        columns.push(self.2.to_string());
        columns.push(self.3.to_string());
    }
}

impl<T0, T1, T2, T3, T4> DataAggregatorRenderer for (T0, T1, T2, T3, T4)
where
    T0: ToString,
    T1: ToString,
    T2: ToString,
    T3: ToString,
    T4: ToString,
{
    fn render_columns(&self, columns: &mut Vec<String>) {
        columns.push(self.0.to_string());
        columns.push(self.1.to_string());
        columns.push(self.2.to_string());
        columns.push(self.3.to_string());
        columns.push(self.4.to_string());
    }
}

impl<T0, T1, T2, T3, T4, T5> DataAggregatorRenderer for (T0, T1, T2, T3, T4, T5)
where
    T0: ToString,
    T1: ToString,
    T2: ToString,
    T3: ToString,
    T4: ToString,
    T5: ToString,
{
    fn render_columns(&self, columns: &mut Vec<String>) {
        columns.push(self.0.to_string());
        columns.push(self.1.to_string());
        columns.push(self.2.to_string());
        columns.push(self.3.to_string());
        columns.push(self.4.to_string());
        columns.push(self.5.to_string());
    }
}

impl<T0, T1, T2, T3, T4, T5, T6> DataAggregatorRenderer for (T0, T1, T2, T3, T4, T5, T6)
where
    T0: ToString,
    T1: ToString,
    T2: ToString,
    T3: ToString,
    T4: ToString,
    T5: ToString,
    T6: ToString,
{
    fn render_columns(&self, columns: &mut Vec<String>) {
        columns.push(self.0.to_string());
        columns.push(self.1.to_string());
        columns.push(self.2.to_string());
        columns.push(self.3.to_string());
        columns.push(self.4.to_string());
        columns.push(self.5.to_string());
        columns.push(self.6.to_string());
    }
}

impl<T0, T1, T2, T3, T4, T5, T6, T7> DataAggregatorRenderer for (T0, T1, T2, T3, T4, T5, T6, T7)
where
    T0: ToString,
    T1: ToString,
    T2: ToString,
    T3: ToString,
    T4: ToString,
    T5: ToString,
    T6: ToString,
    T7: ToString,
{
    fn render_columns(&self, columns: &mut Vec<String>) {
        columns.push(self.0.to_string());
        columns.push(self.1.to_string());
        columns.push(self.2.to_string());
        columns.push(self.3.to_string());
        columns.push(self.4.to_string());
        columns.push(self.5.to_string());
        columns.push(self.6.to_string());
        columns.push(self.7.to_string());
    }
}

pub struct DataAggregator<T>
where
    T: DataAggregatorRenderer,
{
    result: File,
    rows: Vec<T>,
    auto_flush: Option<usize>,
}

impl<T> DataAggregator<T>
where
    T: DataAggregatorRenderer,
{
    pub fn new<P>(result_path: P) -> Self
    where
        P: AsRef<Path>,
    {
        Self {
            result: File::create(result_path).unwrap(),
            rows: vec![],
            auto_flush: None,
        }
    }

    pub fn auto_flush(&self) -> Option<usize> {
        self.auto_flush
    }

    pub fn set_auto_flush(&mut self, rows_count: Option<usize>) {
        self.auto_flush = rows_count;
    }

    pub fn push(&mut self, item: T) {
        self.rows.push(item);
        if let Some(count) = self.auto_flush {
            if self.rows.len() >= count {
                self.flush();
            }
        }
    }

    pub fn flush(&mut self) {
        if self.rows.is_empty() {
            return;
        }
        let mut columns = vec![];
        for row in &self.rows {
            columns.clear();
            row.render_columns(&mut columns);
            self.result
                .write_fmt(format_args!("{}\r\n", columns.join("\t")))
                .unwrap();
        }
        self.rows.clear();
        self.result.flush().unwrap();
    }
}

impl<T> Drop for DataAggregator<T>
where
    T: DataAggregatorRenderer,
{
    fn drop(&mut self) {
        self.flush();
    }
}