diff-coverage 0.6.1

Diff-coverage, supercharged in Rust. Fast, memory-efficient coverage on changed lines for CI.
use std::collections::HashMap;
use std::path::PathBuf;

use crate::cli;

use super::error::AppError;

pub(crate) struct OutputPlan {
    order: Vec<cli::OutputFormat>,
    paths: HashMap<cli::OutputFormat, PathBuf>,
}

impl OutputPlan {
    pub(crate) fn wants_non_cli(&self) -> bool {
        self.order
            .iter()
            .any(|format| !matches!(format, cli::OutputFormat::Cli | cli::OutputFormat::Summary))
    }

    pub(crate) fn order(&self) -> &[cli::OutputFormat] {
        &self.order
    }

    pub(crate) fn path_for(&self, format: &cli::OutputFormat) -> Option<&PathBuf> {
        self.paths.get(format)
    }
}

pub(crate) fn build_output_plan(
    output_targets: Vec<cli::OutputTarget>,
) -> Result<OutputPlan, AppError> {
    let mut output_paths = HashMap::new();
    let mut output_order = Vec::new();
    for target in output_targets {
        if output_order.contains(&target.format) {
            return Err(AppError::usage(format!(
                "--output {} can only be provided once",
                target.format.label()
            )));
        }
        match target.format {
            cli::OutputFormat::Cli | cli::OutputFormat::Summary => {
                if target.path.is_some() {
                    return Err(AppError::usage(format!(
                        "--output {} does not accept a path",
                        target.format.label()
                    )));
                }
            }
            _ => {
                let path = match target.path {
                    Some(path) => path,
                    None => {
                        return Err(AppError::usage(format!(
                            "--output {} requires a path",
                            target.format.label()
                        )));
                    }
                };
                output_paths.insert(target.format, path);
            }
        }
        output_order.push(target.format);
    }
    if output_order.is_empty() {
        output_order.push(cli::DEFAULT_OUTPUT_FORMAT);
    }

    Ok(OutputPlan {
        order: output_order,
        paths: output_paths,
    })
}