mod local;
mod overlay;
mod remote;
mod spec;
use std::fmt;
use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
pub use local::LocalRegistry;
pub use overlay::OverlayRegistry;
pub use remote::RemoteRegistry;
pub use spec::{build_registry, BuiltRegistry, RegistryBuildOptions, RegistrySpec};
use crate::types::{IndexEntry, PublishMetadata};
#[derive(Debug)]
pub enum RegistryError {
NotFound,
Storage(std::io::Error),
Serialization(serde_json::Error),
ValidationFailed(Vec<String>),
Network(String),
NotSupported,
}
impl fmt::Display for RegistryError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
RegistryError::NotFound => write!(f, "not found"),
RegistryError::Storage(e) => write!(f, "storage error: {}", e),
RegistryError::Serialization(e) => write!(f, "serialization error: {}", e),
RegistryError::ValidationFailed(errors) => {
write!(f, "validation failed: {}", errors.join("; "))
}
RegistryError::Network(msg) => write!(f, "network error: {}", msg),
RegistryError::NotSupported => write!(f, "operation not supported"),
}
}
}
impl std::error::Error for RegistryError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
RegistryError::Storage(e) => Some(e),
RegistryError::Serialization(e) => Some(e),
_ => None,
}
}
}
impl From<std::io::Error> for RegistryError {
fn from(e: std::io::Error) -> Self {
RegistryError::Storage(e)
}
}
impl From<serde_json::Error> for RegistryError {
fn from(e: serde_json::Error) -> Self {
RegistryError::Serialization(e)
}
}
pub trait Registry: Send + Sync {
fn lookup(
&self,
crate_name: &str,
) -> impl std::future::Future<Output = Result<Vec<IndexEntry>, RegistryError>> + Send;
fn download(
&self,
crate_name: &str,
version: &str,
) -> impl std::future::Future<Output = Result<Vec<u8>, RegistryError>> + Send;
fn publish(
&self,
metadata: PublishMetadata,
crate_data: &[u8],
auth_token: Option<&str>,
) -> impl std::future::Future<Output = Result<String, RegistryError>> + Send;
}
pub trait DynRegistry: Send + Sync {
fn lookup<'a>(
&'a self,
crate_name: &'a str,
) -> Pin<Box<dyn Future<Output = Result<Vec<IndexEntry>, RegistryError>> + Send + 'a>>;
fn download<'a>(
&'a self,
crate_name: &'a str,
version: &'a str,
) -> Pin<Box<dyn Future<Output = Result<Vec<u8>, RegistryError>> + Send + 'a>>;
fn publish<'a>(
&'a self,
metadata: PublishMetadata,
crate_data: &'a [u8],
auth_token: Option<&'a str>,
) -> Pin<Box<dyn Future<Output = Result<String, RegistryError>> + Send + 'a>>;
}
impl<T: Registry> DynRegistry for T {
fn lookup<'a>(
&'a self,
crate_name: &'a str,
) -> Pin<Box<dyn Future<Output = Result<Vec<IndexEntry>, RegistryError>> + Send + 'a>> {
Box::pin(Registry::lookup(self, crate_name))
}
fn download<'a>(
&'a self,
crate_name: &'a str,
version: &'a str,
) -> Pin<Box<dyn Future<Output = Result<Vec<u8>, RegistryError>> + Send + 'a>> {
Box::pin(Registry::download(self, crate_name, version))
}
fn publish<'a>(
&'a self,
metadata: PublishMetadata,
crate_data: &'a [u8],
auth_token: Option<&'a str>,
) -> Pin<Box<dyn Future<Output = Result<String, RegistryError>> + Send + 'a>> {
Box::pin(Registry::publish(self, metadata, crate_data, auth_token))
}
}
#[derive(Clone)]
pub struct AnyRegistry(Arc<dyn DynRegistry>);
impl AnyRegistry {
pub fn new<R: Registry + 'static>(registry: R) -> Self {
Self(Arc::new(registry))
}
pub fn from_arc(registry: Arc<dyn DynRegistry>) -> Self {
Self(registry)
}
}
impl Registry for AnyRegistry {
async fn lookup(&self, crate_name: &str) -> Result<Vec<IndexEntry>, RegistryError> {
self.0.lookup(crate_name).await
}
async fn download(&self, crate_name: &str, version: &str) -> Result<Vec<u8>, RegistryError> {
self.0.download(crate_name, version).await
}
async fn publish(
&self,
metadata: PublishMetadata,
crate_data: &[u8],
auth_token: Option<&str>,
) -> Result<String, RegistryError> {
self.0.publish(metadata, crate_data, auth_token).await
}
}