qc-cli 0.5.1

qc is designed to give you an instant breakdown of your codebase composition. It uses Memory Mapping (Mmap) and Parallel Directory Walking to scan tens of thousands of files in milliseconds.
use crate::result::{FileResult, Lang};
use serde::Serialize;
use std::collections::HashMap;
use std::time::Duration;

#[derive(Serialize)]
pub struct Report {
    pub totals: Totals,
    pub languages: Vec<LanguageStat>,
    pub files: Vec<FileStat>,
    pub elapsed_ms: u128,
}

#[derive(Serialize)]
pub struct Totals {
    pub code: usize,
    pub comment: usize,
    pub blank: usize,
    pub bytes: u64,
}

#[derive(Serialize)]
pub struct LanguageStat {
    pub lang: Lang,
    pub code: usize,
    pub comment: usize,
    pub blank: usize,
    pub bytes: u64,
}

#[derive(Serialize)]
pub struct FileStat {
    pub path: String,
    pub lang: Lang,
    pub code: usize,
    pub comment: usize,
    pub blank: usize,
    pub bytes: u64,
}

pub fn build_report(
    results: &[FileResult],
    elapsed: Duration,
    top_n: usize,
) -> Report {
    let mut totals = Totals {
        code: 0,
        comment: 0,
        blank: 0,
        bytes: 0,
    };

    let mut langs: HashMap<Lang, (usize, usize, usize, u64)> = HashMap::new();

    for r in results {
        totals.code += r.code;
        totals.comment += r.comment;
        totals.blank += r.blank;
        totals.bytes += r.bytes;

        let entry = langs.entry(r.lang.clone()).or_insert((0, 0, 0, 0));
        entry.0 += r.code;
        entry.1 += r.comment;
        entry.2 += r.blank;
        entry.3 += r.bytes;
    }

    let mut languages: Vec<_> = langs
        .into_iter()
        .map(|(lang, (c, m, b, by))| LanguageStat {
            lang,
            code: c,
            comment: m,
            blank: b,
            bytes: by,
        })
        .collect();

    languages.sort_unstable_by_key(|l| std::cmp::Reverse(l.code + l.comment));

    let mut files: Vec<_> = results
        .iter()
        .map(|r| FileStat {
            path: r.path.display().to_string(),
            lang: r.lang.clone(),
            code: r.code,
            comment: r.comment,
            blank: r.blank,
            bytes: r.bytes,
        })
        .collect();

    files.sort_unstable_by_key(|f| std::cmp::Reverse(f.code + f.comment));
    files.truncate(top_n);

    Report {
        totals,
        languages,
        files,
        elapsed_ms: elapsed.as_millis(),
    }
}