#![doc = include_str!("../../doc/status/storage_transformers.md")]
mod storage_transformer_chain;
use std::sync::{Arc, LazyLock};
pub use storage_transformer_chain::StorageTransformerChain;
use zarrs_plugin::{
ExtensionAliases, Plugin2, PluginUnsupportedError, RuntimePlugin2, RuntimeRegistry,
ZarrVersion3,
};
use crate::node::NodePath;
use zarrs_metadata::Configuration;
use zarrs_metadata::v3::MetadataV3;
use zarrs_plugin::{ExtensionName, PluginCreateError};
#[cfg(feature = "async")]
use zarrs_storage::{
AsyncListableStorage, AsyncReadableStorage, AsyncReadableWritableStorage, AsyncWritableStorage,
};
use zarrs_storage::{
ListableStorage, MaybeSend, MaybeSync, ReadableStorage, ReadableWritableStorage, StorageError,
WritableStorage,
};
pub type StorageTransformer = Arc<dyn StorageTransformerTraits>;
#[derive(derive_more::Deref)]
pub struct StorageTransformerPlugin(Plugin2<StorageTransformer, MetadataV3, NodePath>);
inventory::collect!(StorageTransformerPlugin);
impl StorageTransformerPlugin {
pub const fn new<T: ExtensionAliases<ZarrVersion3> + StorageTransformerTraits>() -> Self {
Self(Plugin2::new(T::matches_name, T::create))
}
}
pub type StorageTransformerRuntimePlugin = RuntimePlugin2<StorageTransformer, MetadataV3, NodePath>;
pub static STORAGE_TRANSFORMER_RUNTIME_REGISTRY: LazyLock<
RuntimeRegistry<StorageTransformerRuntimePlugin>,
> = LazyLock::new(RuntimeRegistry::new);
pub type StorageTransformerRuntimeRegistryHandle = Arc<StorageTransformerRuntimePlugin>;
pub fn register_storage_transformer(
plugin: StorageTransformerRuntimePlugin,
) -> StorageTransformerRuntimeRegistryHandle {
STORAGE_TRANSFORMER_RUNTIME_REGISTRY.register(plugin)
}
pub fn unregister_storage_transformer(handle: &StorageTransformerRuntimeRegistryHandle) -> bool {
STORAGE_TRANSFORMER_RUNTIME_REGISTRY.unregister(handle)
}
pub fn try_create_storage_transformer(
metadata: &MetadataV3,
path: &NodePath,
) -> Result<StorageTransformer, PluginCreateError> {
let name = metadata.name();
{
let result = STORAGE_TRANSFORMER_RUNTIME_REGISTRY.with_plugins(|plugins| {
for plugin in plugins {
if plugin.match_name(name) {
return Some(plugin.create(metadata, path));
}
}
None
});
if let Some(result) = result {
return result;
}
}
for plugin in inventory::iter::<StorageTransformerPlugin> {
if plugin.match_name(name) {
return plugin.create(metadata, path);
}
}
Err(PluginUnsupportedError::new(
metadata.name().to_string(),
"storage transformer".to_string(),
)
.into())
}
#[cfg_attr(
all(feature = "async", not(target_arch = "wasm32")),
async_trait::async_trait
)]
#[cfg_attr(all(feature = "async", target_arch = "wasm32"), async_trait::async_trait(?Send))]
pub trait StorageTransformerTraits:
ExtensionName + core::fmt::Debug + MaybeSend + MaybeSync
{
fn create(
metadata: &MetadataV3,
path: &NodePath,
) -> Result<StorageTransformer, PluginCreateError>
where
Self: Sized;
fn configuration(&self) -> Configuration;
fn create_readable_transformer(
self: Arc<Self>,
storage: ReadableStorage,
) -> Result<ReadableStorage, StorageError>;
fn create_writable_transformer(
self: Arc<Self>,
storage: WritableStorage,
) -> Result<WritableStorage, StorageError>;
fn create_readable_writable_transformer(
self: Arc<Self>,
storage: ReadableWritableStorage,
) -> Result<ReadableWritableStorage, StorageError>;
fn create_listable_transformer(
self: Arc<Self>,
storage: ListableStorage,
) -> Result<ListableStorage, StorageError>;
#[cfg(feature = "async")]
async fn create_async_readable_transformer(
self: Arc<Self>,
storage: AsyncReadableStorage,
) -> Result<AsyncReadableStorage, StorageError>;
#[cfg(feature = "async")]
async fn create_async_writable_transformer(
self: Arc<Self>,
storage: AsyncWritableStorage,
) -> Result<AsyncWritableStorage, StorageError>;
#[cfg(feature = "async")]
async fn create_async_readable_writable_transformer(
self: Arc<Self>,
storage: AsyncReadableWritableStorage,
) -> Result<AsyncReadableWritableStorage, StorageError>;
#[cfg(feature = "async")]
async fn create_async_listable_transformer(
self: Arc<Self>,
storage: AsyncListableStorage,
) -> Result<AsyncListableStorage, StorageError>;
}