2021-02-20 18:53:11 +01:00
|
|
|
use crate::domain::{Record, Value};
|
|
|
|
use std::collections::HashMap;
|
|
|
|
|
2021-02-28 22:18:51 +01:00
|
|
|
pub type ActionConstructor = Box<dyn Fn(ModuleArgs) -> Box<dyn Action>>;
|
|
|
|
pub type FilterConstructor = Box<dyn Fn(ModuleArgs) -> Box<dyn Filter>>;
|
2021-02-20 18:53:11 +01:00
|
|
|
|
2021-02-28 22:18:51 +01:00
|
|
|
pub struct Modules {
|
|
|
|
available_actions: HashMap<String, ActionConstructor>,
|
|
|
|
available_filters: HashMap<String, FilterConstructor>,
|
2021-02-20 18:53:11 +01:00
|
|
|
}
|
|
|
|
|
2021-02-28 22:18:51 +01:00
|
|
|
impl Modules {
|
|
|
|
pub fn new() -> Modules {
|
|
|
|
Modules {
|
|
|
|
available_actions: HashMap::new(),
|
|
|
|
available_filters: HashMap::new(),
|
|
|
|
}
|
|
|
|
}
|
2021-02-20 18:53:11 +01:00
|
|
|
|
2021-02-28 22:18:51 +01:00
|
|
|
pub fn register_action(&mut self, name: String, cons: ActionConstructor) {
|
|
|
|
self.available_actions.insert(name, cons);
|
2021-02-20 18:53:11 +01:00
|
|
|
}
|
|
|
|
|
2021-02-28 22:18:51 +01:00
|
|
|
pub fn register_filter(&mut self, name: String, cons: FilterConstructor) {
|
|
|
|
self.available_filters.insert(name, cons);
|
|
|
|
}
|
2021-02-20 18:53:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
pub enum Module {
|
|
|
|
Action(Box<dyn Action>),
|
|
|
|
Filter(Box<dyn Filter>),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Module {
|
2021-02-28 22:18:51 +01:00
|
|
|
pub fn new(name: String, args: ModuleArgs, available: &Modules) -> Result<Module, ()> {
|
|
|
|
if let Some(a) = available.available_actions.get(&name) {
|
2021-02-20 18:53:11 +01:00
|
|
|
Ok(Module::Action(a(args)))
|
2021-02-28 22:18:51 +01:00
|
|
|
} else if let Some(f) = available.available_filters.get(&name) {
|
2021-02-20 18:53:11 +01:00
|
|
|
Ok(Module::Filter(f(args)))
|
|
|
|
} else {
|
|
|
|
Err(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-28 22:18:51 +01:00
|
|
|
pub fn run(&mut self, record: &mut Record) -> Result<bool, ()> {
|
2021-02-20 18:53:11 +01:00
|
|
|
match self {
|
|
|
|
Module::Action(a) => match a.act(record) {
|
|
|
|
Ok(()) => Ok(true),
|
|
|
|
Err(()) => Err(()),
|
|
|
|
},
|
|
|
|
Module::Filter(f) => Ok(f.filter(record)),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-28 22:18:51 +01:00
|
|
|
pub trait Action {
|
|
|
|
fn act(&mut self, record: &mut Record) -> Result<(), ()>;
|
2021-02-20 18:53:11 +01:00
|
|
|
}
|
|
|
|
|
2021-02-28 22:18:51 +01:00
|
|
|
pub trait Filter {
|
|
|
|
fn filter(&mut self, record: &mut Record) -> bool;
|
2021-02-20 18:53:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
pub type ModuleArgs = HashMap<String, Value>;
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2021-02-28 22:18:51 +01:00
|
|
|
use super::{Module, Modules, Record, Value};
|
2021-02-20 18:53:11 +01:00
|
|
|
use crate::domain::test_util::*;
|
|
|
|
use std::collections::HashMap;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn available_action_can_be_generated_and_run() {
|
|
|
|
// Given
|
2021-02-28 22:18:51 +01:00
|
|
|
let mut mods = Modules::new();
|
|
|
|
mods.register_action(ACT_NAME.to_string(), Box::new(|_| Box::new(FakeAction {})));
|
2021-02-20 18:53:11 +01:00
|
|
|
let mut record: Record = HashMap::new();
|
|
|
|
|
|
|
|
// When
|
2021-02-28 22:18:51 +01:00
|
|
|
let mut module = Module::new(ACT_NAME.to_string(), HashMap::new(), &mods).unwrap();
|
2021-02-20 18:53:11 +01:00
|
|
|
|
|
|
|
// Then
|
|
|
|
assert!(module.run(&mut record) == Ok(true));
|
|
|
|
assert!(record.contains_key(ACT_NAME));
|
|
|
|
assert!(record[ACT_NAME] == Value::Int(1));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn available_filter_can_be_generated_and_run() {
|
|
|
|
// Given
|
2021-02-28 22:18:51 +01:00
|
|
|
let mut mods = Modules::new();
|
|
|
|
mods.register_filter(FLT_NAME.to_string(), Box::new(|_| Box::new(FakeFilter {})));
|
2021-02-20 18:53:11 +01:00
|
|
|
let mut record: Record = HashMap::new();
|
|
|
|
|
|
|
|
// When
|
2021-02-28 22:18:51 +01:00
|
|
|
let mut module = Module::new(FLT_NAME.to_string(), HashMap::new(), &mods).unwrap();
|
2021-02-20 18:53:11 +01:00
|
|
|
|
|
|
|
// Then
|
|
|
|
assert!(module.run(&mut record) == Ok(false));
|
|
|
|
assert!(record.contains_key(FLT_NAME));
|
|
|
|
assert!(record[FLT_NAME] == Value::Int(1));
|
|
|
|
}
|
|
|
|
}
|