Skip to content

Commit c0a368e

Browse files
committed
Optimize memory usage
1 parent e2ce753 commit c0a368e

File tree

4 files changed

+69
-82
lines changed

4 files changed

+69
-82
lines changed

src/import_discovery.rs

+24-26
Original file line numberDiff line numberDiff line change
@@ -4,31 +4,33 @@ use rustpython_parser::{
44
self,
55
ast::{Mod, Stmt},
66
};
7+
use std::collections::HashMap;
78
use std::collections::HashSet;
89
use std::fs;
9-
use std::{collections::HashMap, sync::Arc};
1010

1111
use crate::ast_visit;
1212
use crate::indexing;
1313
use crate::package_discovery;
1414

15-
pub type Imports = HashMap<String, HashSet<String>>;
15+
pub type Imports<'a> = HashMap<&'a str, HashSet<&'a str>>;
1616

17-
pub fn discover_imports(modules_by_pypath: &indexing::ModulesByPypath) -> Result<Imports> {
17+
pub fn discover_imports<'a>(
18+
modules_by_pypath: &'a indexing::ModulesByPypath,
19+
) -> Result<Imports<'a>> {
1820
modules_by_pypath
1921
.values()
2022
.par_bridge()
2123
.map(|module| {
22-
let imports = get_imports_for_module(Arc::clone(module), modules_by_pypath)?;
23-
Ok((module.pypath.clone(), imports))
24+
let imports = get_imports_for_module(module, modules_by_pypath)?;
25+
Ok((module.pypath.as_str(), imports))
2426
})
2527
.collect::<Result<Imports>>()
2628
}
2729

28-
fn get_imports_for_module(
29-
module: Arc<package_discovery::Module>,
30-
modules_by_pypath: &indexing::ModulesByPypath,
31-
) -> Result<HashSet<String>> {
30+
fn get_imports_for_module<'a>(
31+
module: &'a package_discovery::Module,
32+
modules_by_pypath: &'a indexing::ModulesByPypath,
33+
) -> Result<HashSet<&'a str>> {
3234
let code = fs::read_to_string(&module.path)?;
3335
let ast = rustpython_parser::parse(
3436
&code,
@@ -44,7 +46,7 @@ fn get_imports_for_module(
4446
};
4547

4648
let mut visitor = ImportVisitor {
47-
module: Arc::clone(&module),
49+
module,
4850
modules_by_pypath,
4951
imports: HashSet::new(),
5052
};
@@ -54,9 +56,9 @@ fn get_imports_for_module(
5456
}
5557

5658
struct ImportVisitor<'a> {
57-
module: Arc<package_discovery::Module>,
58-
modules_by_pypath: &'a indexing::ModulesByPypath,
59-
imports: HashSet<String>,
59+
module: &'a package_discovery::Module,
60+
modules_by_pypath: &'a indexing::ModulesByPypath<'a>,
61+
imports: HashSet<&'a str>,
6062
}
6163

6264
impl<'a> ast_visit::StatementVisitor for ImportVisitor<'a> {
@@ -65,9 +67,9 @@ impl<'a> ast_visit::StatementVisitor for ImportVisitor<'a> {
6567
Stmt::Import(stmt) => {
6668
for name in stmt.names.iter() {
6769
for pypath in [name.name.to_string(), format!("{}.__init__", name.name)] {
68-
match self.modules_by_pypath.get(&pypath) {
70+
match self.modules_by_pypath.get(pypath.as_str()) {
6971
Some(imported_module) => {
70-
self.imports.insert(imported_module.pypath.clone());
72+
self.imports.insert(imported_module.pypath.as_str());
7173
}
7274
None => continue,
7375
}
@@ -116,9 +118,9 @@ impl<'a> ast_visit::StatementVisitor for ImportVisitor<'a> {
116118
format!("{}.{}.__init__", &pypath_prefix, name.name),
117119
format!("{}.__init__", &pypath_prefix),
118120
] {
119-
match self.modules_by_pypath.get(&pypath) {
121+
match self.modules_by_pypath.get(pypath.as_str()) {
120122
Some(imported_module) => {
121-
self.imports.insert(imported_module.pypath.clone());
123+
self.imports.insert(imported_module.pypath.as_str());
122124
break;
123125
}
124126
None => continue,
@@ -143,10 +145,10 @@ mod tests {
143145
fn test_get_imports_for_module() {
144146
let root_package_path = Path::new("./example");
145147
let root_package = package_discovery::discover_package(root_package_path).unwrap();
146-
let modules_by_pypath = indexing::get_modules_by_pypath(Arc::clone(&root_package)).unwrap();
148+
let modules_by_pypath = indexing::get_modules_by_pypath(&root_package).unwrap();
147149

148150
let module = modules_by_pypath.get("example.__init__").unwrap();
149-
let imports = get_imports_for_module(Arc::clone(module), &modules_by_pypath).unwrap();
151+
let imports = get_imports_for_module(module, &modules_by_pypath).unwrap();
150152
assert_eq!(
151153
imports,
152154
[
@@ -167,12 +169,11 @@ mod tests {
167169
"example.child5.__init__",
168170
]
169171
.into_iter()
170-
.map(|i| i.to_string())
171172
.collect::<HashSet<_>>()
172173
);
173174

174175
let module = modules_by_pypath.get("example.child.__init__").unwrap();
175-
let imports = get_imports_for_module(Arc::clone(module), &modules_by_pypath).unwrap();
176+
let imports = get_imports_for_module(module, &modules_by_pypath).unwrap();
176177
assert_eq!(
177178
imports,
178179
[
@@ -193,12 +194,11 @@ mod tests {
193194
"example.child5.__init__",
194195
]
195196
.into_iter()
196-
.map(|i| i.to_string())
197197
.collect::<HashSet<_>>()
198198
);
199199

200200
let module = modules_by_pypath.get("example.z").unwrap();
201-
let imports = get_imports_for_module(Arc::clone(module), &modules_by_pypath).unwrap();
201+
let imports = get_imports_for_module(module, &modules_by_pypath).unwrap();
202202
assert_eq!(
203203
imports,
204204
[
@@ -219,12 +219,11 @@ mod tests {
219219
"example.child5.__init__",
220220
]
221221
.into_iter()
222-
.map(|i| i.to_string())
223222
.collect::<HashSet<_>>()
224223
);
225224

226225
let module = modules_by_pypath.get("example.child.c_z").unwrap();
227-
let imports = get_imports_for_module(Arc::clone(module), &modules_by_pypath).unwrap();
226+
let imports = get_imports_for_module(module, &modules_by_pypath).unwrap();
228227
assert_eq!(
229228
imports,
230229
[
@@ -245,7 +244,6 @@ mod tests {
245244
"example.child5.__init__",
246245
]
247246
.into_iter()
248-
.map(|i| i.to_string())
249247
.collect::<HashSet<_>>()
250248
);
251249
}

src/indexing.rs

+32-41
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,34 @@
11
use anyhow::Result;
2-
use std::{collections::HashMap, sync::Arc};
2+
use std::collections::HashMap;
33

44
use crate::package_discovery;
55

6-
pub type PackagesByPypath = HashMap<String, Arc<package_discovery::Package>>;
7-
pub type ModulesByPypath = HashMap<String, Arc<package_discovery::Module>>;
6+
pub type PackagesByPypath<'a> = HashMap<&'a str, &'a package_discovery::Package>;
7+
pub type ModulesByPypath<'a> = HashMap<&'a str, &'a package_discovery::Module>;
88

99
pub fn get_packages_by_pypath(
10-
root_package: Arc<package_discovery::Package>,
10+
root_package: &package_discovery::Package,
1111
) -> Result<PackagesByPypath> {
1212
let mut m = HashMap::new();
1313
let mut q = vec![root_package];
1414
while let Some(package) = q.pop() {
15-
m.insert(package.pypath.clone(), Arc::clone(&package));
15+
m.insert(package.pypath.as_str(), package);
1616
for child in package.children.iter() {
17-
q.push(Arc::clone(&child));
17+
q.push(child);
1818
}
1919
}
2020
Ok(m)
2121
}
2222

23-
pub fn get_modules_by_pypath(
24-
root_package: Arc<package_discovery::Package>,
25-
) -> Result<ModulesByPypath> {
23+
pub fn get_modules_by_pypath(root_package: &package_discovery::Package) -> Result<ModulesByPypath> {
2624
let mut m = HashMap::new();
2725
let mut q = vec![root_package];
2826
while let Some(package) = q.pop() {
2927
for module in package.modules.iter() {
30-
m.insert(module.pypath.clone(), Arc::clone(module));
28+
m.insert(module.pypath.as_str(), module);
3129
}
3230
for child in package.children.iter() {
33-
q.push(Arc::clone(&child));
31+
q.push(child);
3432
}
3533
}
3634
Ok(m)
@@ -48,36 +46,29 @@ mod tests {
4846
let root_package_path = Path::new("./example");
4947
let root_package = package_discovery::discover_package(root_package_path).unwrap();
5048

51-
let mut packages_by_pypath = get_packages_by_pypath(Arc::clone(&root_package)).unwrap();
49+
let packages_by_pypath = get_packages_by_pypath(&root_package).unwrap();
5250

5351
assert_eq!(packages_by_pypath.len(), 6);
52+
assert_eq!(packages_by_pypath.get("example").unwrap(), &&root_package);
5453
assert_eq!(
55-
packages_by_pypath.remove("example").unwrap(),
56-
Arc::clone(&root_package)
54+
packages_by_pypath.get("example.child").unwrap(),
55+
root_package
56+
.children
57+
.iter()
58+
.filter(|child| child.pypath == "example.child")
59+
.collect::<Vec<_>>()
60+
.first()
61+
.unwrap()
5762
);
5863
assert_eq!(
59-
packages_by_pypath.remove("example.child").unwrap(),
60-
Arc::clone(
61-
&root_package
62-
.children
63-
.iter()
64-
.filter(|child| child.pypath == "example.child")
65-
.collect::<Vec<_>>()
66-
.first()
67-
.unwrap()
68-
)
69-
);
70-
assert_eq!(
71-
packages_by_pypath.remove("example.child2").unwrap(),
72-
Arc::clone(
73-
&root_package
74-
.children
75-
.iter()
76-
.filter(|child| child.pypath == "example.child2")
77-
.collect::<Vec<_>>()
78-
.first()
79-
.unwrap()
80-
)
64+
packages_by_pypath.get("example.child2").unwrap(),
65+
root_package
66+
.children
67+
.iter()
68+
.filter(|child| child.pypath == "example.child2")
69+
.collect::<Vec<_>>()
70+
.first()
71+
.unwrap()
8172
);
8273
}
8374

@@ -86,13 +77,13 @@ mod tests {
8677
let root_package_path = Path::new("./example");
8778
let root_package = package_discovery::discover_package(root_package_path).unwrap();
8879

89-
let mut modules_by_pypath = get_modules_by_pypath(Arc::clone(&root_package)).unwrap();
80+
let modules_by_pypath = get_modules_by_pypath(&root_package).unwrap();
9081

9182
assert_eq!(modules_by_pypath.len(), 18);
9283
for module in root_package.modules.iter() {
9384
assert_eq!(
94-
modules_by_pypath.remove(&module.pypath).unwrap(),
95-
Arc::clone(module)
85+
modules_by_pypath.get(module.pypath.as_str()).unwrap(),
86+
&module
9687
)
9788
}
9889
for child_module in root_package
@@ -106,8 +97,8 @@ mod tests {
10697
.iter()
10798
{
10899
assert_eq!(
109-
modules_by_pypath.remove(&child_module.pypath).unwrap(),
110-
Arc::clone(child_module)
100+
modules_by_pypath.get(child_module.pypath.as_str()).unwrap(),
101+
&child_module
111102
)
112103
}
113104
}

src/main.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use anyhow::Result;
2-
use std::sync::Arc;
32
use std::{env, path::Path};
43

54
use pyimports::import_discovery;
@@ -11,8 +10,8 @@ pub fn main() -> Result<()> {
1110
let root_package_path = Path::new(&args[1]);
1211

1312
let package = package_discovery::discover_package(root_package_path)?;
14-
let packages_by_pypath = indexing::get_packages_by_pypath(Arc::clone(&package))?;
15-
let modules_by_pypath = indexing::get_modules_by_pypath(Arc::clone(&package))?;
13+
let packages_by_pypath = indexing::get_packages_by_pypath(&package)?;
14+
let modules_by_pypath = indexing::get_modules_by_pypath(&package)?;
1615
let imports = import_discovery::discover_imports(&modules_by_pypath)?;
1716

1817
// dbg!(&package);

src/package_discovery.rs

+11-12
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use anyhow::Result;
22
use rayon::prelude::*;
33
use std::path::PathBuf;
4-
use std::sync::Arc;
54
use std::{fs, io, path::Path};
65
use thiserror::Error;
76

@@ -24,8 +23,8 @@ pub enum PackageDiscoveryError {
2423
pub struct Package {
2524
pub pypath: String,
2625
pub path: PathBuf,
27-
pub children: Vec<Arc<Package>>,
28-
pub modules: Vec<Arc<Module>>,
26+
pub children: Vec<Package>,
27+
pub modules: Vec<Module>,
2928
}
3029

3130
impl Package {
@@ -38,11 +37,11 @@ impl Package {
3837
}
3938
}
4039

41-
pub fn add_child(&mut self, child: Arc<Package>) {
40+
pub fn add_child(&mut self, child: Package) {
4241
self.children.push(child);
4342
}
4443

45-
pub fn add_module(&mut self, module: Arc<Module>) {
44+
pub fn add_module(&mut self, module: Module) {
4645
self.modules.push(module);
4746
}
4847
}
@@ -59,11 +58,11 @@ impl Module {
5958
}
6059
}
6160

62-
pub fn discover_package(package_path: &Path) -> Result<Arc<Package>> {
61+
pub fn discover_package(package_path: &Path) -> Result<Package> {
6362
_discover_package(package_path, package_path)
6463
}
6564

66-
fn _discover_package(root_package_path: &Path, package_path: &Path) -> Result<Arc<Package>> {
65+
fn _discover_package(root_package_path: &Path, package_path: &Path) -> Result<Package> {
6766
let (is_package, files, dirs) = fs::read_dir(package_path)
6867
.map_err(PackageDiscoveryError::CannotReadDir)?
6968
.par_bridge()
@@ -101,18 +100,18 @@ fn _discover_package(root_package_path: &Path, package_path: &Path) -> Result<Ar
101100
}
102101

103102
let pypath = get_pypath(root_package_path, package_path, false)?;
104-
let mut package = Package::new(pypath, package_path.to_owned());
103+
let mut package = Package::new(pypath, package_path.to_path_buf());
105104

106105
for module in files
107106
.par_iter()
108107
.filter(|file| file.path().extension().unwrap_or_default() == "py")
109108
.map(|file| {
110109
let pypath = get_pypath(root_package_path, &file.path(), true)?;
111-
Ok(Module::new(pypath, file.path().to_owned()))
110+
Ok(Module::new(pypath, file.path().to_path_buf()))
112111
})
113112
.collect::<Result<Vec<_>>>()?
114113
{
115-
package.add_module(Arc::new(module));
114+
package.add_module(module);
116115
}
117116

118117
for child in dirs
@@ -123,7 +122,7 @@ fn _discover_package(root_package_path: &Path, package_path: &Path) -> Result<Ar
123122
{
124123
match child {
125124
Ok(child) => {
126-
package.add_child(Arc::clone(&child));
125+
package.add_child(child);
127126
}
128127
Err(e) => match e.root_cause().downcast_ref::<PackageDiscoveryError>() {
129128
Some(PackageDiscoveryError::NotAPythonPackage) => continue,
@@ -132,7 +131,7 @@ fn _discover_package(root_package_path: &Path, package_path: &Path) -> Result<Ar
132131
}
133132
}
134133

135-
Ok(Arc::new(package))
134+
Ok(package)
136135
}
137136

138137
fn get_pypath(root_package_path: &Path, path: &Path, is_file: bool) -> Result<String> {

0 commit comments

Comments
 (0)