use derive_more::Display;
use serde::{Deserialize, Serialize};
use super::AdditionalFieldsV3;
use crate::array::IntoDimensionName;
use crate::v3::MetadataV3;
use crate::{ArrayShape, ChunkKeySeparator, DimensionName};
mod fill_value;
mod nan_representations;
pub use fill_value::FillValueMetadataV3;
pub use nan_representations::{ZARR_NAN_BF16, ZARR_NAN_F16, ZARR_NAN_F32, ZARR_NAN_F64};
#[non_exhaustive]
#[allow(clippy::unsafe_derive_deserialize)]
#[derive(Serialize, Deserialize, Clone, PartialEq, Debug, Display)]
#[display("{}", serde_json::to_string(self).unwrap_or_default())]
pub struct ArrayMetadataV3 {
pub zarr_format: monostate::MustBe!(3u64),
pub node_type: monostate::MustBe!("array"),
pub shape: ArrayShape,
pub data_type: MetadataV3,
pub chunk_grid: MetadataV3,
pub chunk_key_encoding: MetadataV3,
pub fill_value: FillValueMetadataV3,
pub codecs: Vec<MetadataV3>,
#[serde(default, skip_serializing_if = "serde_json::Map::is_empty")]
pub attributes: serde_json::Map<String, serde_json::Value>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub storage_transformers: Vec<MetadataV3>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub dimension_names: Option<Vec<DimensionName>>,
#[serde(flatten)]
pub additional_fields: AdditionalFieldsV3,
}
impl ArrayMetadataV3 {
#[must_use]
pub fn new(
shape: ArrayShape,
chunk_grid: MetadataV3,
data_type: MetadataV3,
fill_value: FillValueMetadataV3,
codecs: Vec<MetadataV3>,
) -> Self {
#[derive(Serialize)]
struct DefaultChunkKeyEncodingConfiguration {
pub separator: ChunkKeySeparator,
}
let chunk_key_encoding = unsafe {
MetadataV3::new_with_serializable_configuration(
"default".to_string(),
&DefaultChunkKeyEncodingConfiguration {
separator: crate::ChunkKeySeparator::Slash,
},
)
.unwrap_unchecked()
};
Self {
zarr_format: monostate::MustBe!(3u64),
node_type: monostate::MustBe!("array"),
shape,
data_type,
chunk_grid,
chunk_key_encoding,
fill_value,
codecs,
attributes: serde_json::Map::default(),
storage_transformers: Vec::default(),
dimension_names: None,
additional_fields: AdditionalFieldsV3::default(),
}
}
#[allow(clippy::missing_panics_doc)]
#[must_use]
pub fn to_string_pretty(&self) -> String {
serde_json::to_string_pretty(self).expect("array metadata is valid JSON")
}
#[must_use]
pub fn with_attributes(
mut self,
attributes: serde_json::Map<String, serde_json::Value>,
) -> Self {
self.attributes = attributes;
self
}
#[must_use]
pub fn with_additional_fields(mut self, additional_fields: AdditionalFieldsV3) -> Self {
self.additional_fields = additional_fields;
self
}
#[must_use]
pub fn with_chunk_key_encoding(mut self, chunk_key_encoding: MetadataV3) -> Self {
self.chunk_key_encoding = chunk_key_encoding;
self
}
#[must_use]
pub fn with_dimension_names<I, D>(mut self, dimension_names: Option<I>) -> Self
where
I: IntoIterator<Item = D>,
D: IntoDimensionName,
{
if let Some(dimension_names) = dimension_names {
self.dimension_names = Some(
dimension_names
.into_iter()
.map(IntoDimensionName::into_dimension_name)
.collect(),
);
} else {
self.dimension_names = None;
}
self
}
#[must_use]
pub fn with_storage_transformers(mut self, storage_transformers: Vec<MetadataV3>) -> Self {
self.storage_transformers = storage_transformers;
self
}
}