use std::sync::Arc;
use qubit_spi::{
ProviderRegistry,
ProviderRegistryError,
ServiceProvider,
};
use crate::{
FileResource,
FileSystem,
FileSystemConfig,
FileSystemProvider,
FileSystemSpec,
FsError,
FsErrorKind,
FsOperation,
FsResult,
FsUri,
};
#[derive(Debug, Default)]
pub struct FileSystemRegistry {
providers: ProviderRegistry<FileSystemSpec>,
}
impl FileSystemRegistry {
#[inline]
#[must_use]
pub fn new() -> Self {
Self::default()
}
pub fn register<P>(&mut self, provider: P) -> FsResult<()>
where
P: ServiceProvider<FileSystemSpec> + 'static,
{
self.providers.register(provider).map_err(map_provider_error)
}
pub fn register_shared(&mut self, provider: Arc<FileSystemProvider>) -> FsResult<()> {
self.providers.register_shared(provider).map_err(map_provider_error)
}
pub fn fs(&self, uri: &FsUri) -> FsResult<Arc<dyn FileSystem>> {
let selector = uri.scheme.clone();
let config = FileSystemConfig::new(uri.clone());
self.providers
.create_arc(&selector, &config)
.map_err(map_provider_error)
}
pub fn resource(&self, uri: &FsUri) -> FsResult<FileResource> {
let path = uri.path.clone();
let fs = self.fs(uri)?;
Ok(FileResource::new(fs, path))
}
#[inline]
#[must_use]
pub fn provider_names(&self) -> Vec<&str> {
self.providers.provider_names()
}
}
fn map_provider_error(error: ProviderRegistryError) -> FsError {
let kind = match &error {
ProviderRegistryError::EmptyProviderName
| ProviderRegistryError::InvalidProviderName { .. }
| ProviderRegistryError::DuplicateProviderName { .. }
| ProviderRegistryError::DuplicateProviderCandidate { .. } => FsErrorKind::InvalidPath,
ProviderRegistryError::UnknownProvider { .. }
| ProviderRegistryError::ProviderUnavailable { .. }
| ProviderRegistryError::NoAvailableProvider { .. }
| ProviderRegistryError::EmptyRegistry => FsErrorKind::ProviderUnavailable,
ProviderRegistryError::ProviderCreate { .. } => FsErrorKind::Other,
};
let message = error.to_string();
FsError::with_source(kind, FsOperation::Provider, &message, error)
}