cargo-coupling 0.3.7

A coupling analysis tool for Rust projects - measuring the 'right distance' in your code
Documentation
use std::collections::HashMap;

use crate::metrics::coupling::CouplingMetrics;
use crate::metrics::dimensions::Subdomain;
use crate::metrics::project::ProjectMetrics;

pub(crate) fn build_target_subdomain_map(
    metrics: &ProjectMetrics,
) -> HashMap<String, Option<Subdomain>> {
    let mut targets = HashMap::new();

    for (module_key, module) in &metrics.modules {
        let Some(subdomain) = module.subdomain else {
            continue;
        };

        insert_subdomain_alias(&mut targets, module_key, subdomain);
        insert_subdomain_alias(&mut targets, &module.name, subdomain);

        if let Some(short_name) = module_key.rsplit("::").next() {
            insert_subdomain_alias(&mut targets, short_name, subdomain);
        }
        if let Some(short_name) = module.name.rsplit("::").next() {
            insert_subdomain_alias(&mut targets, short_name, subdomain);
        }
        if let Some(file_stem) = module.path.file_stem().and_then(|stem| stem.to_str()) {
            insert_subdomain_alias(&mut targets, file_stem, subdomain);
        }

        for type_name in module.type_definitions.keys() {
            insert_subdomain_alias(&mut targets, type_name, subdomain);
        }
        for function_name in module.function_definitions.keys() {
            insert_subdomain_alias(&mut targets, function_name, subdomain);
        }
    }

    targets
}

fn insert_subdomain_alias(
    targets: &mut HashMap<String, Option<Subdomain>>,
    alias: &str,
    subdomain: Subdomain,
) {
    if !alias.is_empty() {
        targets
            .entry(alias.to_string())
            .and_modify(|existing| {
                if *existing != Some(subdomain) {
                    *existing = None;
                }
            })
            .or_insert(Some(subdomain));
    }
}

pub(crate) fn coupling_with_essential_volatility(
    coupling: &CouplingMetrics,
    target_subdomains: &HashMap<String, Option<Subdomain>>,
) -> CouplingMetrics {
    let Some(subdomain) = target_subdomain_for_coupling(&coupling.target, target_subdomains) else {
        return coupling.clone();
    };

    let mut effective = coupling.clone();
    effective.volatility = subdomain.expected_volatility();
    effective
}

fn target_subdomain_for_coupling(
    target: &str,
    target_subdomains: &HashMap<String, Option<Subdomain>>,
) -> Option<Subdomain> {
    target_subdomains
        .get(target)
        .copied()
        .flatten()
        .or_else(|| {
            target
                .rsplit("::")
                .find_map(|part| target_subdomains.get(part).copied().flatten())
        })
}