mod array;
mod codecs;
pub mod group;
mod metadata;
mod store;
pub mod types;
pub use array::ZarrArray;
pub use codecs::{
BytesCodec, Codec, CodecPipeline, Endian, ShuffleCodec, TransposeCodec, ZstdCodec,
};
pub use metadata::{
ArrayMetadataV2, ArrayMetadataV3, ChunkGrid, CodecMetadata, ConsolidatedMetadata,
GroupMetadataV2, GroupMetadataV3,
};
pub use store::DirectoryStore;
use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ZarrVersion {
V2,
V3,
}
impl fmt::Display for ZarrVersion {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ZarrVersion::V2 => write!(f, "2"),
ZarrVersion::V3 => write!(f, "3"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub enum DataType {
Bool,
Int8,
Int16,
Int32,
Int64,
UInt8,
UInt16,
UInt32,
UInt64,
Float32,
Float64,
}
impl DataType {
pub fn byte_size(&self) -> usize {
match self {
DataType::Bool | DataType::Int8 | DataType::UInt8 => 1,
DataType::Int16 | DataType::UInt16 => 2,
DataType::Int32 | DataType::UInt32 | DataType::Float32 => 4,
DataType::Int64 | DataType::UInt64 | DataType::Float64 => 8,
}
}
pub fn to_v2_dtype(&self) -> &'static str {
match self {
DataType::Bool => "|b1",
DataType::Int8 => "|i1",
DataType::Int16 => "<i2",
DataType::Int32 => "<i4",
DataType::Int64 => "<i8",
DataType::UInt8 => "|u1",
DataType::UInt16 => "<u2",
DataType::UInt32 => "<u4",
DataType::UInt64 => "<u8",
DataType::Float32 => "<f4",
DataType::Float64 => "<f8",
}
}
pub fn from_v2_dtype(s: &str) -> crate::error::Result<Self> {
match s {
"|b1" => Ok(DataType::Bool),
"|i1" => Ok(DataType::Int8),
"<i2" | ">i2" => Ok(DataType::Int16),
"<i4" | ">i4" => Ok(DataType::Int32),
"<i8" | ">i8" => Ok(DataType::Int64),
"|u1" => Ok(DataType::UInt8),
"<u2" | ">u2" => Ok(DataType::UInt16),
"<u4" | ">u4" => Ok(DataType::UInt32),
"<u8" | ">u8" => Ok(DataType::UInt64),
"<f4" | ">f4" => Ok(DataType::Float32),
"<f8" | ">f8" => Ok(DataType::Float64),
_ => Err(crate::error::IoError::FormatError(format!(
"Unknown Zarr v2 dtype: {s}"
))),
}
}
pub fn to_v3_name(&self) -> &'static str {
match self {
DataType::Bool => "bool",
DataType::Int8 => "int8",
DataType::Int16 => "int16",
DataType::Int32 => "int32",
DataType::Int64 => "int64",
DataType::UInt8 => "uint8",
DataType::UInt16 => "uint16",
DataType::UInt32 => "uint32",
DataType::UInt64 => "uint64",
DataType::Float32 => "float32",
DataType::Float64 => "float64",
}
}
pub fn from_v3_name(s: &str) -> crate::error::Result<Self> {
match s {
"bool" => Ok(DataType::Bool),
"int8" => Ok(DataType::Int8),
"int16" => Ok(DataType::Int16),
"int32" => Ok(DataType::Int32),
"int64" => Ok(DataType::Int64),
"uint8" => Ok(DataType::UInt8),
"uint16" => Ok(DataType::UInt16),
"uint32" => Ok(DataType::UInt32),
"uint64" => Ok(DataType::UInt64),
"float32" => Ok(DataType::Float32),
"float64" => Ok(DataType::Float64),
_ => Err(crate::error::IoError::FormatError(format!(
"Unknown Zarr v3 data type: {s}"
))),
}
}
}
impl fmt::Display for DataType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.to_v3_name())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_data_type_byte_size() {
assert_eq!(DataType::Bool.byte_size(), 1);
assert_eq!(DataType::Int32.byte_size(), 4);
assert_eq!(DataType::Float64.byte_size(), 8);
assert_eq!(DataType::UInt16.byte_size(), 2);
}
#[test]
fn test_data_type_v2_roundtrip() {
let types = [
DataType::Bool,
DataType::Int8,
DataType::Int16,
DataType::Int32,
DataType::Int64,
DataType::UInt8,
DataType::UInt16,
DataType::UInt32,
DataType::UInt64,
DataType::Float32,
DataType::Float64,
];
for dt in &types {
let s = dt.to_v2_dtype();
let parsed = DataType::from_v2_dtype(s).expect("roundtrip should succeed");
assert_eq!(*dt, parsed);
}
}
#[test]
fn test_data_type_v3_roundtrip() {
let types = [
DataType::Bool,
DataType::Float32,
DataType::Float64,
DataType::Int64,
DataType::UInt8,
];
for dt in &types {
let s = dt.to_v3_name();
let parsed = DataType::from_v3_name(s).expect("roundtrip should succeed");
assert_eq!(*dt, parsed);
}
}
#[test]
fn test_data_type_v2_big_endian() {
assert_eq!(
DataType::from_v2_dtype(">f8").expect("should parse"),
DataType::Float64
);
assert_eq!(
DataType::from_v2_dtype(">i4").expect("should parse"),
DataType::Int32
);
}
#[test]
fn test_zarr_version_display() {
assert_eq!(ZarrVersion::V2.to_string(), "2");
assert_eq!(ZarrVersion::V3.to_string(), "3");
}
}