zarrs/array/
chunk_key_encoding.rs

1//! Zarr chunk key encodings. Includes a [default](default::DefaultChunkKeyEncoding) and [v2](v2::V2ChunkKeyEncoding) implementation.
2//!
3//! See <https://zarr-specs.readthedocs.io/en/latest/v3/chunk-key-encodings/index.html>.
4//!
5#![doc = include_str!("../../doc/status/chunk_key_encodings.md")]
6
7pub mod default;
8pub mod default_suffix;
9pub mod v2;
10
11use std::sync::Arc;
12
13pub use zarrs_metadata::ChunkKeySeparator;
14
15pub use default::{DefaultChunkKeyEncoding, DefaultChunkKeyEncodingConfiguration};
16pub use default_suffix::{
17    DefaultSuffixChunkKeyEncoding, DefaultSuffixChunkKeyEncodingConfiguration,
18};
19pub use v2::{V2ChunkKeyEncoding, V2ChunkKeyEncodingConfiguration};
20use zarrs_plugin::PluginUnsupportedError;
21use zarrs_storage::{MaybeSend, MaybeSync};
22
23use crate::{
24    metadata::v3::MetadataV3,
25    plugin::{Plugin, PluginCreateError},
26    storage::StoreKey,
27};
28
29use derive_more::{Deref, From};
30
31/// A chunk key encoding.
32#[derive(Debug, Clone, From, Deref)]
33pub struct ChunkKeyEncoding(Arc<dyn ChunkKeyEncodingTraits>);
34
35/// A chunk key encoding plugin.
36#[derive(derive_more::Deref)]
37pub struct ChunkKeyEncodingPlugin(Plugin<ChunkKeyEncoding, MetadataV3>);
38inventory::collect!(ChunkKeyEncodingPlugin);
39
40impl ChunkKeyEncodingPlugin {
41    /// Create a new [`ChunkKeyEncodingPlugin`].
42    pub const fn new(
43        identifier: &'static str,
44        match_name_fn: fn(name: &str) -> bool,
45        create_fn: fn(metadata: &MetadataV3) -> Result<ChunkKeyEncoding, PluginCreateError>,
46    ) -> Self {
47        Self(Plugin::new(identifier, match_name_fn, create_fn))
48    }
49}
50
51impl ChunkKeyEncoding {
52    /// Create a chunk key encoding.
53    pub fn new<T: ChunkKeyEncodingTraits + 'static>(chunk_key_encoding: T) -> Self {
54        let chunk_key_encoding: Arc<dyn ChunkKeyEncodingTraits> = Arc::new(chunk_key_encoding);
55        chunk_key_encoding.into()
56    }
57
58    /// Create a chunk key encoding from metadata.
59    ///
60    /// # Errors
61    ///
62    /// Returns [`PluginCreateError`] if the metadata is invalid or not associated with a registered chunk key encoding plugin.
63    pub fn from_metadata(metadata: &MetadataV3) -> Result<Self, PluginCreateError> {
64        for plugin in inventory::iter::<ChunkKeyEncodingPlugin> {
65            if plugin.match_name(metadata.name()) {
66                return plugin.create(metadata);
67            }
68        }
69        #[cfg(miri)]
70        {
71            // Inventory does not work in miri, so manually handle all known chunk key encodings
72            match metadata.name() {
73                chunk_key_encoding::DEFAULT => {
74                    return default::create_chunk_key_encoding_default(metadata);
75                }
76                chunk_key_encoding::V2 => {
77                    return v2::create_chunk_key_encoding_v2(metadata);
78                }
79                _ => {}
80            }
81        }
82        Err(PluginUnsupportedError::new(
83            metadata.name().to_string(),
84            "chunk key encoding".to_string(),
85        )
86        .into())
87    }
88}
89
90impl<T> From<T> for ChunkKeyEncoding
91where
92    T: ChunkKeyEncodingTraits + 'static,
93{
94    fn from(chunk_key_encoding: T) -> Self {
95        Self::new(chunk_key_encoding)
96    }
97}
98
99/// Chunk key encoding traits.
100pub trait ChunkKeyEncodingTraits: core::fmt::Debug + MaybeSend + MaybeSync {
101    /// Create the metadata of this chunk key encoding.
102    fn create_metadata(&self) -> MetadataV3;
103
104    /// Encode chunk grid indices (grid cell coordinates) into a store key.
105    fn encode(&self, chunk_grid_indices: &[u64]) -> StoreKey;
106}