rspack_core 0.102.1

rspack core
Documentation
use rspack_cacheable::cacheable;
use rspack_error::Diagnostic;
use rspack_paths::{InternedPath, InternedPathSet};
use rustc_hash::FxHashMap;

use crate::DependencyId;

#[cacheable]
#[derive(Debug, Clone)]
pub struct FactorizeInfo {
  related_dep_ids: Vec<DependencyId>,
  file_dependencies: Box<[InternedPath]>,
  context_dependencies: Box<[InternedPath]>,
  missing_dependencies: Box<[InternedPath]>,
  diagnostics: Vec<Diagnostic>,
}

impl FactorizeInfo {
  pub fn new(
    diagnostics: Vec<Diagnostic>,
    related_dep_ids: Vec<DependencyId>,
    file_dependencies: InternedPathSet,
    context_dependencies: InternedPathSet,
    missing_dependencies: InternedPathSet,
  ) -> Self {
    assert!(
      !related_dep_ids.is_empty(),
      "factorization should contain at least one dependency"
    );
    Self {
      related_dep_ids,
      file_dependencies: file_dependencies.into_iter().collect(),
      context_dependencies: context_dependencies.into_iter().collect(),
      missing_dependencies: missing_dependencies.into_iter().collect(),
      diagnostics,
    }
  }

  pub fn owner_dep_id(&self) -> DependencyId {
    self.related_dep_ids[0]
  }

  pub fn is_success(&self) -> bool {
    self.diagnostics.is_empty()
  }

  pub fn related_dep_ids(&self) -> &[DependencyId] {
    &self.related_dep_ids
  }

  pub fn file_dependencies(&self) -> &[InternedPath] {
    &self.file_dependencies
  }

  pub fn context_dependencies(&self) -> &[InternedPath] {
    &self.context_dependencies
  }

  pub fn missing_dependencies(&self) -> &[InternedPath] {
    &self.missing_dependencies
  }

  pub fn diagnostics(&self) -> &[Diagnostic] {
    &self.diagnostics
  }
}

#[derive(Debug, Default)]
pub(crate) struct FactorizationArtifact {
  infos: FxHashMap<DependencyId, FactorizeInfo>,
  dependency_owners: FxHashMap<DependencyId, DependencyId>,
}

impl FactorizationArtifact {
  pub(crate) fn insert(&mut self, info: FactorizeInfo) {
    let owner_dep_id = info.owner_dep_id();

    if let Some(previous) = self.infos.remove(&owner_dep_id) {
      for dep_id in previous.related_dep_ids() {
        self.dependency_owners.remove(dep_id);
      }
    }

    for dep_id in info.related_dep_ids() {
      let previous_owner = self.dependency_owners.insert(*dep_id, owner_dep_id);
      debug_assert!(
        previous_owner.is_none() || previous_owner == Some(owner_dep_id),
        "dependency should only belong to one factorization"
      );
    }
    self.infos.insert(owner_dep_id, info);
  }

  pub(crate) fn get(&self, dep_id: &DependencyId) -> Option<&FactorizeInfo> {
    let owner_dep_id = self.dependency_owners.get(dep_id)?;
    self.infos.get(owner_dep_id)
  }

  pub(crate) fn get_by_owner(&self, dep_id: &DependencyId) -> Option<&FactorizeInfo> {
    self.infos.get(dep_id)
  }

  pub(crate) fn revoke(&mut self, dep_id: &DependencyId) -> Option<(DependencyId, FactorizeInfo)> {
    let owner_dep_id = *self.dependency_owners.get(dep_id)?;
    let info = self
      .infos
      .remove(&owner_dep_id)
      .expect("factorization owner should have info");
    for related_dep_id in info.related_dep_ids() {
      self.dependency_owners.remove(related_dep_id);
    }
    Some((owner_dep_id, info))
  }

  pub(crate) fn iter(&self) -> impl Iterator<Item = (DependencyId, &FactorizeInfo)> {
    self.infos.iter().map(|(dep_id, info)| (*dep_id, info))
  }
}