From 31d9716d28582eaa4c3a19d35504cf485406c625 Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Thu, 21 Jul 2022 19:50:23 +1000 Subject: [PATCH 01/11] Refactor: Extract `CratesToml::append{_to_path}` Signed-off-by: Jiahao XU --- src/binstall/install.rs | 8 ++------ src/metafiles/v1.rs | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/binstall/install.rs b/src/binstall/install.rs index 6c1830ea..9df6013a 100644 --- a/src/binstall/install.rs +++ b/src/binstall/install.rs @@ -109,12 +109,8 @@ async fn install_from_package( let bins: BTreeSet = bin_files.into_iter().map(|bin| bin.base_name).collect(); - { - debug!("Writing .crates.toml"); - let mut c1 = metafiles::v1::CratesToml::load().unwrap_or_default(); - c1.insert(cvs.clone(), bins.clone()); - c1.write()?; - } + debug!("Writing .crates.toml"); + metafiles::v1::CratesToml::append(cvs.clone(), bins.clone())?; { debug!("Writing .crates2.json"); diff --git a/src/metafiles/v1.rs b/src/metafiles/v1.rs index 1180814a..12e34641 100644 --- a/src/metafiles/v1.rs +++ b/src/metafiles/v1.rs @@ -42,6 +42,25 @@ impl CratesToml { fs::write(path, &toml::to_vec(&self)?)?; Ok(()) } + + pub fn append_to_path( + path: impl AsRef, + cvs: CrateVersionSource, + bins: BTreeSet, + ) -> Result<(), CratesTomlParseError> { + let mut c1 = Self::load_from_path(path.as_ref()).unwrap_or_default(); + c1.insert(cvs, bins); + c1.write_to_path(path.as_ref())?; + + Ok(()) + } + + pub fn append( + cvs: CrateVersionSource, + bins: BTreeSet, + ) -> Result<(), CratesTomlParseError> { + Self::append_to_path(Self::default_path()?, cvs, bins) + } } impl FromStr for CratesToml { From 0157a594e6f117316e777e84aee9d2dc7973c751 Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Thu, 21 Jul 2022 19:54:45 +1000 Subject: [PATCH 02/11] Fix err handling in `CratesToml::append_to_path` Make it more robust to `io::Error`: Only create a `Self::default()` if fails to open the file. Signed-off-by: Jiahao XU --- src/metafiles/v1.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/metafiles/v1.rs b/src/metafiles/v1.rs index 12e34641..e0dbcb1e 100644 --- a/src/metafiles/v1.rs +++ b/src/metafiles/v1.rs @@ -1,6 +1,6 @@ use std::{ collections::{BTreeMap, BTreeSet}, - fs, + fs, io, path::{Path, PathBuf}, str::FromStr, }; @@ -48,7 +48,13 @@ impl CratesToml { cvs: CrateVersionSource, bins: BTreeSet, ) -> Result<(), CratesTomlParseError> { - let mut c1 = Self::load_from_path(path.as_ref()).unwrap_or_default(); + let mut c1 = match Self::load_from_path(path.as_ref()) { + Ok(c1) => c1, + Err(CratesTomlParseError::Io(io_err)) if io_err.kind() == io::ErrorKind::NotFound => { + Self::default() + } + Err(err) => return Err(err), + }; c1.insert(cvs, bins); c1.write_to_path(path.as_ref())?; @@ -73,7 +79,7 @@ impl FromStr for CratesToml { #[derive(Debug, Diagnostic, Error)] pub enum CratesTomlParseError { #[error(transparent)] - Io(#[from] std::io::Error), + Io(#[from] io::Error), #[error(transparent)] TomlParse(#[from] toml::de::Error), From 1e725a9ffeaf4bfbba79a19b251f435570b132f8 Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Thu, 21 Jul 2022 19:58:23 +1000 Subject: [PATCH 03/11] Refactor: Extract `Crates2Json::append{_to_path}` Signed-off-by: Jiahao XU --- src/binstall/install.rs | 28 ++++++++++++---------------- src/metafiles/v2.rs | 16 ++++++++++++++++ 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/src/binstall/install.rs b/src/binstall/install.rs index 9df6013a..677423c9 100644 --- a/src/binstall/install.rs +++ b/src/binstall/install.rs @@ -112,22 +112,18 @@ async fn install_from_package( debug!("Writing .crates.toml"); metafiles::v1::CratesToml::append(cvs.clone(), bins.clone())?; - { - debug!("Writing .crates2.json"); - let mut c2 = metafiles::v2::Crates2Json::load().unwrap_or_default(); - c2.insert( - cvs, - metafiles::v2::CrateInfo { - version_req: Some(version), - bins, - profile: "release".into(), - target: fetcher.target().to_string(), - rustc: format!("{} {}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")), - ..Default::default() - }, - ); - c2.write()?; - } + debug!("Writing .crates2.json"); + metafiles::v2::Crates2Json::append( + cvs, + metafiles::v2::CrateInfo { + version_req: Some(version), + bins, + profile: "release".into(), + target: fetcher.target().to_string(), + rustc: format!("{} {}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")), + ..Default::default() + }, + )?; Ok(()) }) diff --git a/src/metafiles/v2.rs b/src/metafiles/v2.rs index 70c4e46e..1501e238 100644 --- a/src/metafiles/v2.rs +++ b/src/metafiles/v2.rs @@ -63,6 +63,22 @@ impl Crates2Json { fs::write(path, &serde_json::to_vec(&self)?)?; Ok(()) } + + pub fn append_to_path( + path: impl AsRef, + cvs: CrateVersionSource, + info: CrateInfo, + ) -> Result<(), Crates2JsonParseError> { + let mut c2 = Self::load_from_path(path.as_ref()).unwrap_or_default(); + c2.insert(cvs, info); + c2.write_to_path(path.as_ref())?; + + Ok(()) + } + + pub fn append(cvs: CrateVersionSource, info: CrateInfo) -> Result<(), Crates2JsonParseError> { + Self::append_to_path(Self::default_path()?, cvs, info) + } } #[derive(Debug, Diagnostic, Error)] From fb3e35624b30d9380bd24b339495efccee00688c Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Thu, 21 Jul 2022 19:59:36 +1000 Subject: [PATCH 04/11] Fix err handling in `Crates2Json::append_to_path` Only uses `Self::default()` if the file is not found. Signed-off-by: Jiahao XU --- src/metafiles/v2.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/metafiles/v2.rs b/src/metafiles/v2.rs index 1501e238..3be0ead6 100644 --- a/src/metafiles/v2.rs +++ b/src/metafiles/v2.rs @@ -1,6 +1,6 @@ use std::{ collections::{BTreeMap, BTreeSet}, - fs, + fs, io, path::{Path, PathBuf}, }; @@ -69,7 +69,13 @@ impl Crates2Json { cvs: CrateVersionSource, info: CrateInfo, ) -> Result<(), Crates2JsonParseError> { - let mut c2 = Self::load_from_path(path.as_ref()).unwrap_or_default(); + let mut c2 = match Self::load_from_path(path.as_ref()) { + Ok(c2) => c2, + Err(Crates2JsonParseError::Io(io_err)) if io_err.kind() == io::ErrorKind::NotFound => { + Self::default() + } + Err(err) => return Err(err), + }; c2.insert(cvs, info); c2.write_to_path(path.as_ref())?; @@ -84,7 +90,7 @@ impl Crates2Json { #[derive(Debug, Diagnostic, Error)] pub enum Crates2JsonParseError { #[error(transparent)] - Io(#[from] std::io::Error), + Io(#[from] io::Error), #[error(transparent)] Json(#[from] serde_json::Error), From d7ae1f242b2394e91961c448443c92edcc30c0d3 Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Thu, 21 Jul 2022 22:14:20 +1000 Subject: [PATCH 05/11] Optimize `Crates2Json::load_from_path`: Use `from_reader` which avoids reading the entire file into string at once. Signed-off-by: Jiahao XU --- src/metafiles/v2.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/metafiles/v2.rs b/src/metafiles/v2.rs index 3be0ead6..f4ea5573 100644 --- a/src/metafiles/v2.rs +++ b/src/metafiles/v2.rs @@ -47,8 +47,8 @@ impl Crates2Json { } pub fn load_from_path(path: impl AsRef) -> Result { - let file = fs::read_to_string(path)?; - Ok(serde_json::from_str(&file)?) + let file = fs::File::open(path.as_ref())?; + Ok(serde_json::from_reader(file)?) } pub fn insert(&mut self, cvs: CrateVersionSource, info: CrateInfo) { From c2ce265afacc416af86918377298d76b53cde79b Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Thu, 21 Jul 2022 22:18:08 +1000 Subject: [PATCH 06/11] Optimize `Crates2Json::write_to_path`: Use `to_writer` which avoids allocating a `Vec` just to hold serialized data. Signed-off-by: Jiahao XU --- src/metafiles/v2.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/metafiles/v2.rs b/src/metafiles/v2.rs index f4ea5573..c7d0f337 100644 --- a/src/metafiles/v2.rs +++ b/src/metafiles/v2.rs @@ -60,7 +60,8 @@ impl Crates2Json { } pub fn write_to_path(&self, path: impl AsRef) -> Result<(), Crates2JsonParseError> { - fs::write(path, &serde_json::to_vec(&self)?)?; + let file = fs::File::create(path.as_ref())?; + serde_json::to_writer(file, &self)?; Ok(()) } From 9d9a31bef3fc888e7a0745e6e685d5f2232aab12 Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Fri, 22 Jul 2022 01:23:58 +1000 Subject: [PATCH 07/11] Optimize `Deserialize` impl for `CrateVersionSource` Use `<&str>::deserialize` instead of `String::deserialize` to avoid intermediate `String`. Signed-off-by: Jiahao XU --- src/metafiles/cvs.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/metafiles/cvs.rs b/src/metafiles/cvs.rs index 2b8f2214..d63d35cf 100644 --- a/src/metafiles/cvs.rs +++ b/src/metafiles/cvs.rs @@ -116,6 +116,7 @@ impl<'de> Deserialize<'de> for CrateVersionSource { where D: Deserializer<'de>, { - Self::from_str(&String::deserialize(deserializer)?).map_err(serde::de::Error::custom) + let s = <&str>::deserialize(deserializer)?; + Self::from_str(s).map_err(serde::de::Error::custom) } } From 96aaca1cc67ad5bda2701171620bdbf9a778dbf0 Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Fri, 22 Jul 2022 01:36:22 +1000 Subject: [PATCH 08/11] Optimize `CratesToml`: Use `String` as key to avoid cost of deserializing (`CrateVersionSource::from_str`). Signed-off-by: Jiahao XU --- src/metafiles/v1.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/metafiles/v1.rs b/src/metafiles/v1.rs index e0dbcb1e..414155a9 100644 --- a/src/metafiles/v1.rs +++ b/src/metafiles/v1.rs @@ -13,7 +13,7 @@ use super::CrateVersionSource; #[derive(Clone, Debug, Default, Deserialize, Serialize)] pub struct CratesToml { - v1: BTreeMap>, + v1: BTreeMap>, } impl CratesToml { @@ -31,7 +31,7 @@ impl CratesToml { } pub fn insert(&mut self, cvs: CrateVersionSource, bins: BTreeSet) { - self.v1.insert(cvs, bins); + self.v1.insert(cvs.to_string(), bins); } pub fn write(&self) -> Result<(), CratesTomlParseError> { From de9404feda611d4f093fbbcc398bd56e54add8ea Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Fri, 22 Jul 2022 01:37:27 +1000 Subject: [PATCH 09/11] Optimize `Crates2Json`: Use `String` as key to avoid cost of deserializing (`CrateVersionSource::from_str`). Signed-off-by: Jiahao XU --- src/metafiles/v2.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/metafiles/v2.rs b/src/metafiles/v2.rs index c7d0f337..0db24f14 100644 --- a/src/metafiles/v2.rs +++ b/src/metafiles/v2.rs @@ -12,7 +12,7 @@ use super::CrateVersionSource; #[derive(Clone, Debug, Default, Deserialize, Serialize)] pub struct Crates2Json { - pub installs: BTreeMap, + pub installs: BTreeMap, } #[derive(Clone, Debug, Default, Deserialize, Serialize)] @@ -52,7 +52,7 @@ impl Crates2Json { } pub fn insert(&mut self, cvs: CrateVersionSource, info: CrateInfo) { - self.installs.insert(cvs, info); + self.installs.insert(cvs.to_string(), info); } pub fn write(&self) -> Result<(), Crates2JsonParseError> { From a3fcc298abfd13dcbf58cbf075d7bdac0b2b1d9d Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Fri, 22 Jul 2022 01:38:44 +1000 Subject: [PATCH 10/11] Avoid `CrateVersionSource::clone` for insertion in `metafiles` Signed-off-by: Jiahao XU --- src/binstall/install.rs | 4 ++-- src/metafiles/v1.rs | 6 +++--- src/metafiles/v2.rs | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/binstall/install.rs b/src/binstall/install.rs index 677423c9..2efeef4b 100644 --- a/src/binstall/install.rs +++ b/src/binstall/install.rs @@ -110,11 +110,11 @@ async fn install_from_package( let bins: BTreeSet = bin_files.into_iter().map(|bin| bin.base_name).collect(); debug!("Writing .crates.toml"); - metafiles::v1::CratesToml::append(cvs.clone(), bins.clone())?; + metafiles::v1::CratesToml::append(&cvs, bins.clone())?; debug!("Writing .crates2.json"); metafiles::v2::Crates2Json::append( - cvs, + &cvs, metafiles::v2::CrateInfo { version_req: Some(version), bins, diff --git a/src/metafiles/v1.rs b/src/metafiles/v1.rs index 414155a9..7e0d9a2f 100644 --- a/src/metafiles/v1.rs +++ b/src/metafiles/v1.rs @@ -30,7 +30,7 @@ impl CratesToml { Self::from_str(&file) } - pub fn insert(&mut self, cvs: CrateVersionSource, bins: BTreeSet) { + pub fn insert(&mut self, cvs: &CrateVersionSource, bins: BTreeSet) { self.v1.insert(cvs.to_string(), bins); } @@ -45,7 +45,7 @@ impl CratesToml { pub fn append_to_path( path: impl AsRef, - cvs: CrateVersionSource, + cvs: &CrateVersionSource, bins: BTreeSet, ) -> Result<(), CratesTomlParseError> { let mut c1 = match Self::load_from_path(path.as_ref()) { @@ -62,7 +62,7 @@ impl CratesToml { } pub fn append( - cvs: CrateVersionSource, + cvs: &CrateVersionSource, bins: BTreeSet, ) -> Result<(), CratesTomlParseError> { Self::append_to_path(Self::default_path()?, cvs, bins) diff --git a/src/metafiles/v2.rs b/src/metafiles/v2.rs index 0db24f14..9f77af2d 100644 --- a/src/metafiles/v2.rs +++ b/src/metafiles/v2.rs @@ -51,7 +51,7 @@ impl Crates2Json { Ok(serde_json::from_reader(file)?) } - pub fn insert(&mut self, cvs: CrateVersionSource, info: CrateInfo) { + pub fn insert(&mut self, cvs: &CrateVersionSource, info: CrateInfo) { self.installs.insert(cvs.to_string(), info); } @@ -67,7 +67,7 @@ impl Crates2Json { pub fn append_to_path( path: impl AsRef, - cvs: CrateVersionSource, + cvs: &CrateVersionSource, info: CrateInfo, ) -> Result<(), Crates2JsonParseError> { let mut c2 = match Self::load_from_path(path.as_ref()) { @@ -83,7 +83,7 @@ impl Crates2Json { Ok(()) } - pub fn append(cvs: CrateVersionSource, info: CrateInfo) -> Result<(), Crates2JsonParseError> { + pub fn append(cvs: &CrateVersionSource, info: CrateInfo) -> Result<(), Crates2JsonParseError> { Self::append_to_path(Self::default_path()?, cvs, info) } } From 32b98f0c5a417b280f184dd3c5859495aa2ee9f0 Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Fri, 22 Jul 2022 01:43:40 +1000 Subject: [PATCH 11/11] Fix `Deserialize` for `CrateVersionSource` Use `Cow::<'_, str>::deserialize` to ensure that it would still work even if it contains escaped characters. Signed-off-by: Jiahao XU --- src/metafiles/cvs.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/metafiles/cvs.rs b/src/metafiles/cvs.rs index d63d35cf..b56ab5fc 100644 --- a/src/metafiles/cvs.rs +++ b/src/metafiles/cvs.rs @@ -1,4 +1,4 @@ -use std::{fmt, str::FromStr}; +use std::{borrow::Cow, fmt, str::FromStr}; use miette::Diagnostic; use once_cell::sync::Lazy; @@ -116,7 +116,7 @@ impl<'de> Deserialize<'de> for CrateVersionSource { where D: Deserializer<'de>, { - let s = <&str>::deserialize(deserializer)?; - Self::from_str(s).map_err(serde::de::Error::custom) + let s = Cow::<'_, str>::deserialize(deserializer)?; + Self::from_str(&s).map_err(serde::de::Error::custom) } }