Skip to content

Commit 9386369

Browse files
committed
perf(core): read files in parallel
1 parent 3001bed commit 9386369

4 files changed

Lines changed: 64 additions & 26 deletions

File tree

Cargo.toml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,12 @@ serde = { version = "1.0.228", features = ["derive"] }
3636
serde_json = { version = "1.0.145", features = ["preserve_order"] }
3737
serde_yaml = "0.9"
3838
thiserror = "2.0.17"
39-
tokio = { version = "1", features = ["macros", "rt-multi-thread", "sync"] }
39+
tokio = { version = "1", features = [
40+
"macros",
41+
"rt-multi-thread",
42+
"sync",
43+
"fs",
44+
] }
4045

4146
[features]
4247
default = []

src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ async fn main() {
5959
debug!("{:#?}", config.cli);
6060
debug!("{:#?}", config.rcfile);
6161

62-
let packages = Packages::from_config(&config);
62+
let packages = Packages::from_config(&config).await;
6363

6464
match packages.all.len() {
6565
0 => {

src/package_json.rs

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,12 @@ use {
33
log::error,
44
serde::Serialize,
55
serde_json::{ser::PrettyFormatter, Serializer, Value},
6-
std::{cell::RefCell, fs, path::PathBuf, rc::Rc},
6+
std::{
7+
cell::RefCell,
8+
fs,
9+
path::{Path, PathBuf},
10+
rc::Rc,
11+
},
712
};
813

914
#[derive(Debug)]
@@ -50,31 +55,34 @@ pub enum FormatMismatchVariant {
5055
}
5156

5257
impl PackageJson {
53-
/// Read a package.json file from the given location
58+
/// Parse a package.json from already-read JSON content
59+
pub fn from_json(file_path: &Path, json: String) -> Option<Self> {
60+
serde_json::from_str(&json)
61+
.inspect_err(|_| {
62+
error!("Invalid JSON: {}", &file_path.to_str().unwrap());
63+
})
64+
.map(|contents: Value| Self {
65+
name: contents
66+
.pointer("/name")
67+
.and_then(|name| name.as_str())
68+
.unwrap_or("NAME_IS_MISSING")
69+
.to_string(),
70+
file_path: file_path.to_path_buf(),
71+
formatting_mismatches: RefCell::new(vec![]),
72+
json: RefCell::new(contents.to_string()),
73+
contents: RefCell::new(contents),
74+
})
75+
.ok()
76+
}
77+
78+
/// Read a package.json file from the given location (sync)
5479
pub fn from_file(file_path: &PathBuf) -> Option<Self> {
5580
fs::read_to_string(file_path)
5681
.inspect_err(|_| {
5782
error!("package.json not readable at {}", &file_path.to_str().unwrap());
5883
})
5984
.ok()
60-
.and_then(|json| {
61-
serde_json::from_str(&json)
62-
.inspect_err(|_| {
63-
error!("Invalid JSON: {}", &file_path.to_str().unwrap());
64-
})
65-
.map(|contents: Value| Self {
66-
name: contents
67-
.pointer("/name")
68-
.and_then(|name| name.as_str())
69-
.unwrap_or("NAME_IS_MISSING")
70-
.to_string(),
71-
file_path: file_path.clone(),
72-
formatting_mismatches: RefCell::new(vec![]),
73-
json: RefCell::new(contents.to_string()),
74-
contents: RefCell::new(contents),
75-
})
76-
.ok()
77-
})
85+
.and_then(|json| Self::from_json(file_path, json))
7886
}
7987

8088
/// Does a property exist at this path of the parsed package.json?

src/packages.rs

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use {
1919
path::{Path, PathBuf},
2020
rc::Rc,
2121
},
22+
tokio::fs as tokio_fs,
2223
};
2324

2425
#[derive(Debug)]
@@ -33,14 +34,38 @@ impl Packages {
3334
}
3435

3536
/// Get every package.json file matched by the user's source patterns
36-
pub fn from_config(config: &Config) -> Self {
37+
pub async fn from_config(config: &Config) -> Self {
3738
let file_paths = get_file_paths(config);
39+
40+
// Read all file contents in parallel using tokio
41+
let tasks: Vec<_> = file_paths
42+
.into_iter()
43+
.map(|file_path| {
44+
tokio::spawn(async move {
45+
tokio_fs::read_to_string(&file_path)
46+
.await
47+
.ok()
48+
.map(|contents| (file_path, contents))
49+
})
50+
})
51+
.collect();
52+
53+
// Wait for all tasks to complete and collect results
54+
let mut file_contents = Vec::new();
55+
for task in tasks {
56+
if let Ok(Some((path, content))) = task.await {
57+
file_contents.push((path, content));
58+
}
59+
}
60+
61+
// Parse JSON synchronously (to avoid Send issues with Rc)
3862
let mut packages = Self::new();
39-
file_paths.iter().for_each(|file_path| {
40-
if let Some(package_json) = PackageJson::from_file(file_path) {
63+
for (file_path, json) in file_contents {
64+
if let Some(package_json) = PackageJson::from_json(&file_path, json) {
4165
packages.add_package(package_json);
4266
}
43-
});
67+
}
68+
4469
packages
4570
}
4671

0 commit comments

Comments
 (0)