Optimize Download::and_visit_tar: Use trait object to avoid monomorphization (#644)

by removing method `TarEntriesVisitor::finish` and associated type
`TarEntriesVisitor::Target`.

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>
This commit is contained in:
Jiahao XU 2023-01-04 11:11:10 +11:00 committed by GitHub
parent 1ab979cde8
commit 959b465d81
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 30 additions and 37 deletions

View file

@ -101,11 +101,11 @@ impl Download {
/// NOTE that this API does not support gnu extension sparse file unlike /// NOTE that this API does not support gnu extension sparse file unlike
/// [`Download::and_extract`]. /// [`Download::and_extract`].
#[instrument(skip(visitor))] #[instrument(skip(visitor))]
pub async fn and_visit_tar<V: TarEntriesVisitor + Debug + Send + 'static>( pub async fn and_visit_tar(
self, self,
fmt: TarBasedFmt, fmt: TarBasedFmt,
visitor: V, visitor: &mut dyn TarEntriesVisitor,
) -> Result<V::Target, DownloadError> { ) -> Result<(), DownloadError> {
let stream = self let stream = self
.client .client
.get_stream(self.url) .get_stream(self.url)
@ -114,11 +114,11 @@ impl Download {
debug!("Downloading and extracting then in-memory processing"); debug!("Downloading and extracting then in-memory processing");
let ret = extract_tar_based_stream_and_visit(stream, fmt, visitor).await?; extract_tar_based_stream_and_visit(stream, fmt, visitor).await?;
debug!("Download, extraction and in-memory procession OK"); debug!("Download, extraction and in-memory procession OK");
Ok(ret) Ok(())
} }
/// Download a file from the provided URL and extract it to the provided path. /// Download a file from the provided URL and extract it to the provided path.

View file

@ -84,21 +84,17 @@ pub enum TarEntryType {
/// Entires can be in arbitary order. /// Entires can be in arbitary order.
#[async_trait::async_trait] #[async_trait::async_trait]
pub trait TarEntriesVisitor: Send + Sync { pub trait TarEntriesVisitor: Send + Sync {
type Target;
/// Will be called once per entry /// Will be called once per entry
async fn visit(&mut self, entry: &mut dyn TarEntry) -> Result<(), DownloadError>; async fn visit(&mut self, entry: &mut dyn TarEntry) -> Result<(), DownloadError>;
fn finish(self) -> Result<Self::Target, DownloadError>;
} }
pub(crate) async fn extract_tar_based_stream_and_visit<S, V>( pub(crate) async fn extract_tar_based_stream_and_visit<S>(
stream: S, stream: S,
fmt: TarBasedFmt, fmt: TarBasedFmt,
mut visitor: V, visitor: &mut dyn TarEntriesVisitor,
) -> Result<V::Target, DownloadError> ) -> Result<(), DownloadError>
where where
S: Stream<Item = Result<Bytes, DownloadError>> + Send + Sync, S: Stream<Item = Result<Bytes, DownloadError>> + Send + Sync,
V: TarEntriesVisitor,
{ {
debug!("Extracting from {fmt} archive to process it in memory"); debug!("Extracting from {fmt} archive to process it in memory");
@ -125,5 +121,5 @@ where
copy(&mut entry, &mut sink).await?; copy(&mut entry, &mut sink).await?;
} }
visitor.finish() Ok(())
} }

View file

@ -52,7 +52,11 @@ pub async fn fetch_crate_cratesio(
let manifest_dir_path: PathBuf = format!("{name}-{version_name}").into(); let manifest_dir_path: PathBuf = format!("{name}-{version_name}").into();
Ok(Download::new(client, Url::parse(&crate_url)?) let mut manifest_visitor = ManifestVisitor::new(manifest_dir_path);
.and_visit_tar(TarBasedFmt::Tgz, ManifestVisitor::new(manifest_dir_path))
.await?) Download::new(client, Url::parse(&crate_url)?)
.and_visit_tar(TarBasedFmt::Tgz, &mut manifest_visitor)
.await?;
manifest_visitor.load_manifest()
} }

View file

@ -1,7 +1,4 @@
use std::{ use std::path::{Path, PathBuf};
io,
path::{Path, PathBuf},
};
use cargo_toml::{Manifest, Value}; use cargo_toml::{Manifest, Value};
use normalize_path::NormalizePath; use normalize_path::NormalizePath;
@ -37,8 +34,6 @@ impl ManifestVisitor {
#[async_trait::async_trait] #[async_trait::async_trait]
impl TarEntriesVisitor for ManifestVisitor { impl TarEntriesVisitor for ManifestVisitor {
type Target = Manifest<Meta>;
async fn visit(&mut self, entry: &mut dyn TarEntry) -> Result<(), DownloadError> { async fn visit(&mut self, entry: &mut dyn TarEntry) -> Result<(), DownloadError> {
let path = entry.path()?; let path = entry.path()?;
let path = path.normalize(); let path = path.normalize();
@ -70,22 +65,20 @@ impl TarEntriesVisitor for ManifestVisitor {
Ok(()) Ok(())
} }
}
impl ManifestVisitor {
/// Load binstall metadata using the extracted information stored in memory. /// Load binstall metadata using the extracted information stored in memory.
fn finish(self) -> Result<Self::Target, DownloadError> { pub(super) fn load_manifest(self) -> Result<Manifest<Meta>, BinstallError> {
Ok(load_manifest(&self.cargo_toml_content, &self.vfs).map_err(io::Error::from)?) debug!("Loading manifest directly from extracted file");
// Load and parse manifest
let mut manifest = Manifest::from_slice_with_metadata(&self.cargo_toml_content)?;
// Checks vfs for binary output names
manifest.complete_from_abstract_filesystem::<Value, _>(&self.vfs, None)?;
// Return metadata
Ok(manifest)
} }
} }
fn load_manifest(slice: &[u8], vfs: &Vfs) -> Result<Manifest<Meta>, BinstallError> {
debug!("Loading manifest directly from extracted file");
// Load and parse manifest
let mut manifest = Manifest::from_slice_with_metadata(slice)?;
// Checks vfs for binary output names
manifest.complete_from_abstract_filesystem::<Value, _>(vfs, None)?;
// Return metadata
Ok(manifest)
}