fob_graph/memory/
mutations.rs

1//! Mutation methods for ModuleGraph.
2
3use std::sync::Arc;
4
5use super::super::Module;
6use super::super::external_dep::ExternalDependency;
7use super::graph::ModuleGraph;
8use crate::Result;
9
10impl ModuleGraph {
11    /// Add a module into the graph.
12    pub fn add_module(&self, module: Module) -> Result<()> {
13        // Prepare external dependency data before acquiring the lock
14        let mut external_deps_to_add = Vec::new();
15        for import in module.imports.iter() {
16            if import.resolved_to.is_none() && !import.source.is_empty() {
17                external_deps_to_add.push((import.source.clone(), module.id.clone()));
18            }
19        }
20
21        // Now acquire the write lock and perform all updates
22        let mut inner = self.inner.write();
23
24        // Track if it's an entry point
25        if module.is_entry {
26            inner.entry_points.insert(module.id.clone());
27        }
28
29        // Add external dependencies
30        for (source, importer_id) in external_deps_to_add {
31            let dep = inner
32                .external_deps
33                .entry(source.clone())
34                .or_insert_with(|| ExternalDependency::new(source));
35            dep.push_importer(importer_id);
36        }
37
38        // Store the module wrapped in Arc for cheap cloning
39        inner.modules.insert(module.id.clone(), Arc::new(module));
40
41        Ok(())
42    }
43
44    /// Add a dependency edge, creating forward and reverse mappings.
45    pub fn add_dependency(
46        &self,
47        from: super::super::ModuleId,
48        to: super::super::ModuleId,
49    ) -> Result<()> {
50        let mut inner = self.inner.write();
51
52        // Add forward edge (HashSet prevents duplicates)
53        inner
54            .dependencies
55            .entry(from.clone())
56            .or_default()
57            .insert(to.clone());
58
59        // Add reverse edge (HashSet prevents duplicates)
60        inner.dependents.entry(to).or_default().insert(from);
61
62        Ok(())
63    }
64
65    /// Add multiple dependencies from a single module.
66    pub fn add_dependencies<I>(&self, from: super::super::ModuleId, targets: I) -> Result<()>
67    where
68        I: IntoIterator<Item = super::super::ModuleId>,
69    {
70        for target in targets {
71            self.add_dependency(from.clone(), target)?;
72        }
73        Ok(())
74    }
75
76    /// Mark a module as an entry point.
77    pub fn add_entry_point(&self, id: super::super::ModuleId) -> Result<()> {
78        let mut inner = self.inner.write();
79        inner.entry_points.insert(id.clone());
80
81        // Update the module itself if it exists (requires cloning from Arc to modify)
82        if let Some(module_arc) = inner.modules.get(&id) {
83            let mut module = (**module_arc).clone();
84            module.is_entry = true;
85            inner.modules.insert(id, Arc::new(module));
86        }
87
88        Ok(())
89    }
90
91    /// Add an external dependency record.
92    pub fn add_external_dependency(&self, dep: ExternalDependency) -> Result<()> {
93        let mut inner = self.inner.write();
94        inner.external_deps.insert(dep.specifier.clone(), dep);
95        Ok(())
96    }
97}