java2pyi 2.0.1

Java class files to Python stubs for mypy/pyright
use std::{
    collections::HashMap,
    sync::{
        Arc,
        atomic::{AtomicUsize, Ordering},
    },
};

use rayon::prelude::{IntoParallelRefIterator, ParallelIterator};

use crate::{
    exclude::Exclusions,
    index_tree::{GlobalIndexTree, PackageIndexTree},
    model::Root,
    status,
};

#[derive(Debug)]
pub struct Scope<'a> {
    pub root: &'a Root,
    pub index_tree: Arc<GlobalIndexTree<'a>>,
}

impl<'a> Scope<'a> {
    pub fn from_roots(roots: &'a [Arc<Root>], exclusions: &Exclusions<'a>) -> Box<[Self]> {
        status::update(&format!("Indexing Trees 0/{}", roots.len()));
        let package_index_trees = {
            let progress = AtomicUsize::new(0);
            let package_index_trees = roots
                .par_iter()
                .map(|root| {
                    let tree = PackageIndexTree::from_ir(root, exclusions);
                    let label = package_label(root.ir().package);
                    update_parallel_progress("Indexing Trees", &progress, roots.len(), label);
                    tree
                })
                .collect::<Vec<_>>();

            let mut groups: HashMap<String, PackageIndexTree<'a>> =
                HashMap::with_capacity(package_index_trees.len());

            for package_index_tree in package_index_trees {
                if let Some(target_index_tree) = groups.get_mut(package_index_tree.package()) {
                    target_index_tree.merge_with(&package_index_tree);
                } else {
                    groups.insert(package_index_tree.package().to_string(), package_index_tree);
                }
            }

            groups
        };

        let global_index_tree = Arc::new(GlobalIndexTree::from_iter(package_index_trees.values()));

        status::update(&format!("Indexing Scopes 0/{}", roots.len()));
        let progress = AtomicUsize::new(0);
        roots
            .par_iter()
            .map(|root| {
                let label = package_label(root.ir().package);
                update_parallel_progress("Indexing Scopes", &progress, roots.len(), label);

                Scope {
                    root: root.as_ref(),
                    index_tree: global_index_tree.clone(),
                }
            })
            .collect::<Vec<_>>()
            .into_boxed_slice()
    }
}

fn package_label(package: &str) -> &str {
    if package.is_empty() {
        "<root>"
    } else {
        package
    }
}

fn update_parallel_progress(stage: &str, progress: &AtomicUsize, total: usize, label: &str) {
    let completed = progress.fetch_add(1, Ordering::Relaxed) + 1;
    status::update(&format!("{} {}/{}: {}", stage, completed, total, label));
}