Optimize use of tinytemplate (#647)

* Optimize `GhCrateMeta::find`: Cache compiled template `pkg_url`
* Optimize `collect_bin_files`: Cache compiled template `bin_dir`
* Refactor: Improve readability of `gh_crate_meta`
* Optimize `GhCrateMeta::launch_baseline_find_tasks`: Dedup urls before checking
* Optimize `BinFile::new`: Avoid one heap alloc when creating `dest`
* Improve `warn!` msg in `GhCrateMeta::launch_baseline_find_tasks`

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>
This commit is contained in:
Jiahao XU 2023-01-26 15:33:49 +11:00 committed by GitHub
parent 719b20aadd
commit 270bf08a24
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 58 additions and 23 deletions

View file

@ -3,6 +3,7 @@ use std::{borrow::Cow, future::Future, iter, path::Path, sync::Arc};
use compact_str::{CompactString, ToCompactString};
use either::Either;
use futures_util::stream::{FuturesUnordered, StreamExt};
use itertools::Itertools;
use once_cell::sync::OnceCell;
use serde::Serialize;
use strum::IntoEnumIterator;
@ -35,23 +36,30 @@ pub struct GhCrateMeta {
type FindTaskRes = Result<Option<(Url, PkgFmt)>, BinstallError>;
impl GhCrateMeta {
/// * `tt` - must have added a template named "pkg_url".
fn launch_baseline_find_tasks<'a>(
&'a self,
pkg_fmt: PkgFmt,
tt: &'a TinyTemplate,
pkg_url: &'a str,
repo: Option<&'a str>,
) -> impl Iterator<Item = impl Future<Output = FindTaskRes> + 'static> + 'a {
// build up list of potential URLs
let urls = pkg_fmt.extensions().iter().filter_map(move |ext| {
let ctx = Context::from_data_with_repo(&self.data, &self.target_data.target, ext, repo);
match ctx.render_url(pkg_url) {
Ok(url) => Some(url),
Err(err) => {
warn!("Failed to render url for {ctx:#?}: {err:#?}");
None
let urls = pkg_fmt
.extensions()
.iter()
.filter_map(move |ext| {
let ctx =
Context::from_data_with_repo(&self.data, &self.target_data.target, ext, repo);
match ctx.render_url_with_compiled_tt(tt, pkg_url) {
Ok(url) => Some(url),
Err(err) => {
warn!("Failed to render url for {ctx:#?}: {err}");
None
}
}
}
});
})
.dedup();
// go check all potential URLs at once
urls.map(move |url| {
@ -139,12 +147,16 @@ impl super::Fetcher for GhCrateMeta {
// Iterate over pkg_urls first to avoid String::clone.
for pkg_url in pkg_urls {
let mut tt = TinyTemplate::new();
tt.add_template("pkg_url", &pkg_url)?;
// Clone iter pkg_fmts to ensure all pkg_fmts is
// iterated over for each pkg_url, which is
// basically cartesian product.
// |
for pkg_fmt in pkg_fmts.clone() {
handles.extend(this.launch_baseline_find_tasks(pkg_fmt, &pkg_url, repo));
handles.extend(this.launch_baseline_find_tasks(pkg_fmt, &tt, &pkg_url, repo));
}
}
@ -266,12 +278,22 @@ impl<'c> Context<'c> {
Self::from_data_with_repo(data, target, archive_format, data.repo.as_deref())
}
pub(self) fn render_url(&self, template: &str) -> Result<Url, BinstallError> {
debug!("Render {template:?} using context: {:?}", self);
/// * `tt` - must have added a template named "pkg_url".
pub(self) fn render_url_with_compiled_tt(
&self,
tt: &TinyTemplate,
template: &str,
) -> Result<Url, BinstallError> {
debug!("Render {template} using context: {self:?}");
Ok(Url::parse(&tt.render("pkg_url", self)?)?)
}
#[cfg(test)]
pub(self) fn render_url(&self, template: &str) -> Result<Url, BinstallError> {
let mut tt = TinyTemplate::new();
tt.add_template("path", template)?;
Ok(Url::parse(&tt.render("path", self)?)?)
tt.add_template("pkg_url", template)?;
self.render_url_with_compiled_tt(&tt, template)
}
}