mirror of
https://github.com/cargo-bins/cargo-binstall.git
synced 2025-04-22 21:48:42 +00:00
Impl new type binstalk_downloader::cacher::HTTPCacher
Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>
This commit is contained in:
parent
3b8b4b940f
commit
926d44b4a5
2 changed files with 106 additions and 0 deletions
104
crates/binstalk-downloader/src/cacher.rs
Normal file
104
crates/binstalk-downloader/src/cacher.rs
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
use std::{
|
||||||
|
any::{Any, TypeId},
|
||||||
|
collections::{BTreeMap, HashMap},
|
||||||
|
fmt::Debug,
|
||||||
|
future::Future,
|
||||||
|
sync::{Arc, RwLock},
|
||||||
|
};
|
||||||
|
|
||||||
|
use tokio::sync::OnceCell;
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
|
type ErasedCachedEntry = Arc<dyn Any + Send + Sync>;
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
struct TypesMap {
|
||||||
|
/// Store the first element inline to avoid heap allocation.
|
||||||
|
first: Option<(TypeId, ErasedCachedEntry)>,
|
||||||
|
map: BTreeMap<TypeId, ErasedCachedEntry>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TypesMap {
|
||||||
|
fn get(&self, type_id: TypeId) -> Option<ErasedCachedEntry> {
|
||||||
|
match &self.first {
|
||||||
|
Some((tid, entry)) if *tid == type_id => Some(entry.clone()),
|
||||||
|
_ => self.map.get(&type_id).cloned(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn insert(&mut self, type_id: TypeId, f: fn() -> ErasedCachedEntry) -> ErasedCachedEntry {
|
||||||
|
if self.first.is_none() {
|
||||||
|
debug_assert!(self.map.is_empty());
|
||||||
|
|
||||||
|
let entry = f();
|
||||||
|
self.first = Some((type_id, entry.clone()));
|
||||||
|
entry
|
||||||
|
} else {
|
||||||
|
self.map.entry(type_id).or_insert_with(f).clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
struct Map(HashMap<Url, TypesMap>);
|
||||||
|
|
||||||
|
impl Map {
|
||||||
|
fn get(&self, url: &Url, type_id: TypeId) -> Option<ErasedCachedEntry> {
|
||||||
|
self.0.get(url).and_then(|types_map| types_map.get(type_id))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn insert(
|
||||||
|
&mut self,
|
||||||
|
url: Url,
|
||||||
|
type_id: TypeId,
|
||||||
|
f: fn() -> ErasedCachedEntry,
|
||||||
|
) -> ErasedCachedEntry {
|
||||||
|
self.0.entry(url).or_default().insert(type_id, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Provides a multi-value hashmap to store results of (processed) response of
|
||||||
|
/// http requests for each url.
|
||||||
|
///
|
||||||
|
/// The cached value can be arbitrary type and there can be multiple cached
|
||||||
|
/// values.
|
||||||
|
#[derive(Clone, Debug, Default)]
|
||||||
|
pub struct HTTPCacher(Arc<RwLock<Map>>);
|
||||||
|
|
||||||
|
impl HTTPCacher {
|
||||||
|
fn get_entry_inner(
|
||||||
|
&self,
|
||||||
|
url: &Url,
|
||||||
|
type_id: TypeId,
|
||||||
|
f: fn() -> ErasedCachedEntry,
|
||||||
|
) -> ErasedCachedEntry {
|
||||||
|
if let Some(entry) = self.0.read().unwrap().get(url, type_id) {
|
||||||
|
entry
|
||||||
|
} else {
|
||||||
|
// Clone the url first to reduce critical section
|
||||||
|
let url = url.clone();
|
||||||
|
self.0.write().unwrap().insert(url, type_id, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_entry<T: Send + Sync + 'static>(&self, url: &Url) -> HTTPCachedEntry<T> {
|
||||||
|
HTTPCachedEntry(
|
||||||
|
self.get_entry_inner(url, TypeId::of::<T>(), || Arc::<OnceCell<T>>::default())
|
||||||
|
.downcast()
|
||||||
|
.expect("BUG: The type of value mismatches the type id in the key"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct HTTPCachedEntry<T>(Arc<OnceCell<T>>);
|
||||||
|
|
||||||
|
impl<T> HTTPCachedEntry<T> {
|
||||||
|
pub async fn get_or_try_init<E, F, Fut>(&self, f: F) -> Result<&T, E>
|
||||||
|
where
|
||||||
|
F: FnOnce() -> Fut,
|
||||||
|
Fut: Future<Output = Result<T, E>>,
|
||||||
|
{
|
||||||
|
self.0.get_or_try_init(f).await
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,4 +12,6 @@ pub mod gh_api_client;
|
||||||
|
|
||||||
pub mod remote;
|
pub mod remote;
|
||||||
|
|
||||||
|
pub mod cacher;
|
||||||
|
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
Loading…
Add table
Reference in a new issue