use std::collections::HashMap;
use std::sync::Arc;
use anyhow::Result;
use async_trait::async_trait;
use itertools::Itertools;
use tokio::sync::RwLock;
use tracing::trace;
use crate::core::registry::Registry;
use crate::core::source::Source;
#[cfg(doc)]
use crate::core::Workspace;
use crate::core::{Config, ManifestDependency, Package, PackageId, SourceId, Summary};
use crate::sources::PathSource;
pub struct SourceMap<'c> {
config: &'c Config,
sources: RwLock<HashMap<SourceId, Arc<dyn Source + 'c>>>,
}
impl<'c> SourceMap<'c> {
pub fn preloaded(packages: impl Iterator<Item = Package>, config: &'c Config) -> Self {
let sources = packages
.sorted_by_key(|pkg| pkg.id.source_id)
.group_by(|pkg| pkg.id.source_id);
let sources = sources.into_iter().map(|(source_id, packages)| {
let packages = packages.collect::<Vec<_>>();
let source = PathSource::preloaded(&packages, config);
let source: Arc<dyn Source + 'c> = Arc::new(source);
(source_id, source)
});
let sources = RwLock::new(HashMap::from_iter(sources));
Self { config, sources }
}
async fn ensure_loaded(&self, source_id: SourceId) -> Result<Arc<dyn Source + 'c>> {
let loaded_source = self.sources.read().await.get(&source_id).cloned();
if let Some(source) = loaded_source {
Ok(source)
} else {
trace!("loading source: {source_id}");
let source = source_id.load(self.config)?;
self.sources.write().await.insert(source_id, source.clone());
Ok(source)
}
}
}
#[async_trait(?Send)]
impl<'c> Registry for SourceMap<'c> {
async fn query(&self, dependency: &ManifestDependency) -> Result<Vec<Summary>> {
let source = self.ensure_loaded(dependency.source_id).await?;
source.query(dependency).await
}
async fn download(&self, package_id: PackageId) -> Result<Package> {
let source = self.ensure_loaded(package_id.source_id).await?;
source.download(package_id).await
}
}