glowdust 0.0.1

A DBMS with a data model based on functions and pattern matching
Documentation
use crate::compiler::value::values::Value;
use crate::store::csv::CsvFunctionValueCursor;
use std::fmt::Debug;
use std::io;
use tracing::debug;

#[derive(Debug)]
pub struct VectorFunctionCursor {
    domain: Vec<Vec<Value>>,
    codomain: Vec<Vec<Value>>,
    index: usize,
    function_name: String,
}

/*
 * This is just a simple pattern for avoiding boxed trait return types. All the FunctionCursor
 * implementations must implement FunctionCursorMethods trait, be added here and the
 * FunctionCursorMethods trait impl for the enum below. Stores then can return FunctionCursor
 * and no runtime dispatch will happen anymore.
 * The same trick is used in the test code, for Store implementations.
 *
 * The enum_dispatch crate does basically this. I think the spelled out implementation in this file
 * is sufficiently readable and tractable, so I won't bother with macros now. If this becomes too
 * complex to maintain, I may change my mind.
 */
#[derive(Debug)]
pub enum FunctionCursor {
    Vector(VectorFunctionCursor),
    Csv(CsvFunctionValueCursor),
}

impl FunctionCursorMethods for FunctionCursor {
    fn next(&mut self) -> Option<Vec<Value>> {
        match self {
            FunctionCursor::Vector(v) => v.next(),
            FunctionCursor::Csv(v) => v.next(),
        }
    }

    fn reset(&mut self) {
        return match self {
            FunctionCursor::Vector(v) => v.reset(),
            FunctionCursor::Csv(v) => v.reset(),
        };
    }
}

pub trait FunctionCursorMethods {
    fn next(&mut self) -> Option<Vec<Value>>;

    fn reset(&mut self);
}

impl VectorFunctionCursor {
    pub fn new(domain: Vec<Vec<Value>>, codomain: Vec<Vec<Value>>, name: &str) -> Self {
        VectorFunctionCursor {
            domain,
            codomain,
            index: 0,
            function_name: name.to_string(),
        }
    }

    pub fn empty() -> Self {
        VectorFunctionCursor {
            domain: vec![],
            codomain: vec![],
            index: 0,
            function_name: "".to_string(),
        }
    }
}

impl FunctionCursorMethods for VectorFunctionCursor {
    fn next(&mut self) -> Option<Vec<Value>> {
        if self.index >= self.domain.len() {
            // debug!("FunctionCursor({}) done", self.function_name);
            return None;
        }
        let mut result = vec![];
        for dom_val in self.domain.get(self.index).unwrap() {
            result.push(dom_val.clone());
        }
        for codom_val in self.codomain.get(self.index).unwrap() {
            result.push(codom_val.clone());
        }
        self.index += 1;
        let result = Some(result);
        // debug!(
        //     "FunctionCursor({}) returning {:?}",
        //     self.function_name, result
        // );
        result
    }

    fn reset(&mut self) {
        debug!("Function cursor for {} resetting", self.function_name);
        self.index = 0;
    }
}