use super::{Environment, Process, ProcessId, Resource, ResourceId};
use crate::algos::dependency::Inventory;
use std::collections::{HashMap, HashSet};
pub struct EnvironmentBuilder<R, P> {
resources: HashMap<ResourceId, R>,
processes: HashMap<ProcessId, P>,
initial: Vec<ResourceId>,
}
impl<R, P> Default for EnvironmentBuilder<R, P> {
fn default() -> Self {
Self {
resources: HashMap::new(),
processes: HashMap::new(),
initial: Vec::new(),
}
}
}
impl<R: Resource, P: Process> EnvironmentBuilder<R, P> {
pub fn add_resource(&mut self, r: R) { self.resources.insert(r.id(), r); }
pub fn add_process(&mut self, p: P) { self.processes.insert(p.id(), p); }
pub fn add_initial(&mut self, id: ResourceId) { self.initial.push(id) }
fn get_resource_ids(&self) -> Vec<ResourceId> {
let mut result = HashSet::new();
for p in self.processes.values() {
for r in p
.tools()
.into_iter()
.chain(p.inputs().into_iter())
.chain(p.outputs().into_iter())
{
result.insert(r);
}
}
result.drain().collect()
}
pub fn build(self) -> Environment<R, P> {
for used_id in self.get_resource_ids() {
if !self.resources.contains_key(&used_id) {
panic!("Invalid Graph, a Process depends on Resource {used_id} which wasn't specified")
}
}
Environment::new(self.resources, self.processes, Inventory::with_list(&self.initial))
}
}
#[cfg(test)]
mod tests {
use super::{EnvironmentBuilder, ProcessId, ResourceId};
struct Process {
id: ProcessId,
inputs: Vec<ResourceId>,
reference: Vec<ResourceId>,
outputs: Vec<ResourceId>,
}
struct Resource {
id: ResourceId,
}
impl super::Process for Process {
type I = Vec<ResourceId>;
fn cost(&self) -> u64 { 64 }
fn id(&self) -> ProcessId { self.id }
fn inputs(&self) -> Self::I { self.inputs.clone() }
fn outputs(&self) -> Self::I { self.outputs.clone() }
fn tools(&self) -> Self::I { self.reference.clone() }
}
impl super::Resource for Resource {
fn id(&self) -> ResourceId { self.id.clone() }
}
#[test]
fn can_buid_graph() {
let mut dg = EnvironmentBuilder::default();
dg.add_process(Process {
id: 0,
reference: Vec::new(),
inputs: vec!["0".to_string()],
outputs: vec!["1".to_string()],
});
dg.add_process(Process {
id: 1,
reference: Vec::new(),
inputs: vec!["1".to_string()],
outputs: Vec::new(),
});
dg.add_resource(Resource { id: "0".to_string() });
dg.add_resource(Resource { id: "1".to_string() });
let _dg = dg.build();
}
}