clover 0.1.3

A scripting language.
Documentation
use crate::intermediate::ast::Document;
use std::collections::{HashMap, HashSet};

pub struct DependencySolver {
    dependencies: HashMap<String, u32>,
    references: HashMap<String, Vec<String>>,
    unsolved: HashSet<String>
}

impl DependencySolver {
    pub fn new() -> DependencySolver {
        DependencySolver {
            dependencies: HashMap::new(),
            references: HashMap::new(),
            unsolved: HashSet::new()
        }
    }

    pub fn is_empty(&self) -> bool {
        self.dependencies.is_empty()
    }

    pub fn get_cycle_reference_list(&self) -> Vec<String> {
        let mut list = Vec::new();

        for (filename, _) in self.dependencies.iter() {
            list.push(filename.clone());
        };

        list
    }

    pub fn get_unsolved_filename(&self) -> Option<String> {
        if let Some(filename) = self.unsolved.iter().next() {
            Some(filename.clone())
        } else {
            None
        }
    }

    pub fn get_next_no_dependency_filename(&self) -> Option<String> {
        for (filename, &dependency) in self.dependencies.iter() {
            if dependency == 0 {
                return Some(filename.clone());
            };
        };

        None
    }

    pub fn set_loaded(&mut self, filename: &str) {
        self.dependencies.remove(filename);

        if let Some(source_list) = self.references.remove(filename) {
            for source in source_list.iter() {
                self.decrease_dependency(source);
            }
        }
    }

    pub fn solve(&mut self, document: &Document, loaded_assemblies: &HashSet<String>) {
        if loaded_assemblies.contains(&document.filename) || self.dependencies.contains_key(&document.filename) {
            return;
        }

        self.add_dependencies(document, loaded_assemblies);

        if self.unsolved.contains(&document.filename) {
            self.unsolved.remove(&document.filename);
        };
    }

    fn add_reference(&mut self, source: &str, target: &str) {
        if !self.references.contains_key(target) {
            self.references.insert(target.to_string(), Vec::new());
        };

        let list = self.references.get_mut(target).unwrap();
        list.push(source.to_string());
    }

    fn increase_dependency(&mut self, source: &str) {
        if let Some(count) = self.dependencies.get_mut(source) {
            *count += 1;
        } else {
            self.dependencies.insert(source.to_string(), 1);
        };
    }

    fn decrease_dependency(&mut self, source: &str) {
        if let Some(count) = self.dependencies.get_mut(source) {
            *count -= 1;
        }
    }

    fn add_dependencies(&mut self, document: &Document, loaded_assemblies: &HashSet<String>) {
        self.dependencies.insert(document.filename.clone(), 0);

        for dependency_filename in document.get_dependencies().iter() {
            if !loaded_assemblies.contains(dependency_filename) {
                self.increase_dependency(&document.filename);
                self.add_reference(&document.filename, dependency_filename);

                if !self.dependencies.contains_key(dependency_filename) {
                    self.unsolved.insert(dependency_filename.to_string());
                }
            };
        };
    }
}