glowdust 0.0.1

A DBMS with a data model based on functions and pattern matching
Documentation
pub mod csv;
pub mod memory;
pub mod serde;

use crate::compiler::cursor::FunctionCursor;
use crate::compiler::value::parameters::Parameter;
use crate::compiler::value::values::{
    FunctionDefinitionObject, FunctionValuesObject, TypeDefinition, Value,
};
use crate::{boolean_to_value, parameter_is_constant, parameter_to_constant};
use phf::phf_map;
use std::io::Error;

pub type NativeFn = fn(&[Value]) -> Value;

fn print(args: &[Value]) -> Value {
    for value in args {
        print!("{} ", value);
    }
    // because currently all functions must return a value
    boolean_to_value!(true)
}

static NATIVE_FUNCTIONS: phf::Map<&'static str, NativeFn> = phf_map! {
        "print" => print as _,
};

pub trait Store {
    fn is_function_name_defined(&self, name: &str) -> Result<bool, Error>;

    fn get_function_value(&self, name: &str, argument: &[Value]) -> Result<Option<Value>, Error>;

    fn set_function_value(
        &mut self,
        name: &str,
        argument: &[Value],
        value: Value,
    ) -> Result<(), Error>;

    fn get_function_definition(
        &self,
        name: &str,
        argument: &[Value],
    ) -> Result<Option<FunctionDefinitionObject>, Error>;

    fn get_native_function(&self, name: &str) -> Result<Option<&NativeFn>, Error> {
        Ok(NATIVE_FUNCTIONS.get(name))
    }

    fn set_function_definition(
        &mut self,
        name: &str,
        parameters: &[Parameter], // I don't think this is necessary. FDO already has a formal args field
        function: FunctionDefinitionObject,
    ) -> Result<(), Error>;

    fn function_cursor(&self, name: &str) -> FunctionCursor;

    fn has_values(&self, name: &str) -> bool;

    fn domain_arity(&self, name: &str) -> Option<u8>;

    fn codomain_arity(&self, name: &str) -> Option<u8>;

    fn set_type_definition(&mut self, name: &str, the_type: TypeDefinition) -> Result<(), Error>;

    fn type_definition_by_name(&self, name: &str) -> Result<Option<TypeDefinition>, Error>;
}

pub(crate) fn arguments_match_value(formal_arguments: &[Parameter], argument: &[Value]) -> bool {
    if formal_arguments.len() != argument.len() {
        return false;
    }
    for (def_param_index, def_param) in formal_arguments.iter().enumerate() {
        let arg_param = &argument[def_param_index];
        if parameter_is_constant!(def_param) {
            if !(parameter_to_constant!(def_param).equals(arg_param)) {
                return false;
            }
        }
    }
    true
}

#[cfg(test)]
pub mod test_mock {
    use crate::compiler::cursor::{FunctionCursor, VectorFunctionCursor};
    use crate::compiler::value::parameters::Parameter;
    use crate::compiler::value::values::{FunctionDefinitionObject, TypeDefinition, Value};
    use crate::store::Store;
    use crate::{empty_tuple_value, vector_to_value};
    use std::collections::HashMap;
    use std::io::Error;

    pub struct StoreHasAllValuesMock {
        pub arities: HashMap<String, (u8, u8)>,
    }

    impl Store for StoreHasAllValuesMock {
        fn is_function_name_defined(&self, _name: &str) -> Result<bool, Error> {
            Ok(true)
        }

        fn get_function_value(
            &self,
            _name: &str,
            _argument: &[Value],
        ) -> Result<Option<Value>, Error> {
            Ok(Some(empty_tuple_value!()))
        }

        fn set_function_value(
            &mut self,
            _name: &str,
            _argument: &[Value],
            _value: Value,
        ) -> Result<(), Error> {
            Ok(())
        }

        fn get_function_definition(
            &self,
            _name: &str,
            _argument: &[Value],
        ) -> Result<Option<FunctionDefinitionObject>, Error> {
            Ok(Some(FunctionDefinitionObject::default()))
        }

        fn set_function_definition(
            &mut self,
            _name: &str,
            _parameters: &[Parameter],
            _function: FunctionDefinitionObject,
        ) -> Result<(), Error> {
            Ok(())
        }

        fn function_cursor(&self, name: &str) -> FunctionCursor {
            FunctionCursor::Vector(VectorFunctionCursor::new(vec![], vec![], name))
        }

        fn has_values(&self, name: &str) -> bool {
            self.arities.contains_key(name)
        }

        fn domain_arity(&self, name: &str) -> Option<u8> {
            return match self.arities.get(name) {
                None => None,
                Some((domain, _codomain)) => Some(*domain),
            };
        }

        fn codomain_arity(&self, name: &str) -> Option<u8> {
            return match self.arities.get(name) {
                None => None,
                Some((_domain, codomain)) => Some(*codomain),
            };
        }

        fn set_type_definition(
            &mut self,
            _name: &str,
            _the_type: TypeDefinition,
        ) -> Result<(), Error> {
            todo!()
        }

        fn type_definition_by_name(&self, _name: &str) -> Result<Option<TypeDefinition>, Error> {
            todo!()
        }
    }
}