ninja-files-data 0.1.0

Core data structures for ninja files
Documentation
use std::collections::BTreeMap;

use crate::{
    Command, CommandBuilder, CommandBuilderError, InvalidVariable, InvalidVariableId, Rule,
    Variable, VariableId,
};

pub struct RuleBuilder {
    command: Option<Command>,
    shadow: BTreeMap<VariableId, Variable>,
    generator: bool,
    errors: Vec<RuleBuilderError>,
}

#[derive(Clone, Debug)]
pub enum RuleBuilderError {
    InvalidCommand(Vec<CommandBuilderError>),
    InvalidVariableId(InvalidVariableId),
    InvalidVariable(InvalidVariable),
    VariableAlreadyDefined {
        id: VariableId,
        previous: Variable,
        var: Variable,
    },
}

impl RuleBuilder {
    pub fn new<C>(command_builder: C) -> Self
    where
        C: Into<CommandBuilder>,
    {
        let mut command = None;
        let mut errors = vec![];
        match command_builder.into().build() {
            Ok(com) => command = Some(com),
            Err(err) => errors.push(RuleBuilderError::InvalidCommand(err)),
        };
        RuleBuilder {
            command,
            shadow: BTreeMap::new(),
            generator: false,
            errors,
        }
    }

    pub fn build(&self) -> Result<Rule, Vec<RuleBuilderError>> {
        let errors = self.errors.clone();
        let shadow = self.shadow.clone();
        let generator = self.generator;

        if !self.errors.is_empty() {
            return Err(errors);
        }

        //should be safe, as it should be an err thus early return
        let command = self.command.clone().unwrap();

        let rule = Rule {
            command,
            shadow,
            generator,
        };
        Ok(rule)
    }

    pub fn generator(mut self, generator: bool) -> Self {
        self.generator = generator;
        self
    }

    pub fn variable<Id, Var>(mut self, id: Id, var: Var) -> Self
    where
        Id: AsRef<str>,
        Var: AsRef<str>,
    {
        let id = VariableId::try_create(id);
        let var = Variable::try_create(var);
        match (id, var) {
            (Ok(id), Ok(var)) => match self.shadow.insert(id.clone(), var.clone()) {
                Some(previous) if var == previous => (),
                Some(previous) => {
                    self.errors
                        .push(RuleBuilderError::VariableAlreadyDefined { id, previous, var })
                }
                None => (),
            },
            (Ok(_), Err(v)) => self.errors.push(RuleBuilderError::InvalidVariable(v)),
            (Err(i), Ok(_)) => self.errors.push(RuleBuilderError::InvalidVariableId(i)),
            (Err(i), Err(v)) => {
                self.errors.push(RuleBuilderError::InvalidVariable(v));
                self.errors.push(RuleBuilderError::InvalidVariableId(i));
            }
        }
        self
    }
}

impl From<Rule> for RuleBuilder {
    fn from(value: Rule) -> Self {
        let mut builder = RuleBuilder::new(value.command).generator(value.generator);
        for (id, var) in value.shadow.into_iter() {
            builder = builder.variable(id, var);
        }
        builder
    }
}