Skip to main content

scirs2_io/zarr/
types.rs

1//! Zarr v3 types: data types, compressors, array metadata, and array structs.
2
3use serde::{Deserialize, Serialize};
4
5/// Supported Zarr data types.
6#[non_exhaustive]
7#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
8pub enum ZarrDataType {
9    /// 32-bit floating point
10    Float32,
11    /// 64-bit floating point
12    Float64,
13    /// 32-bit signed integer
14    Int32,
15    /// 64-bit signed integer
16    Int64,
17    /// 8-bit unsigned integer
18    UInt8,
19    /// 16-bit unsigned integer
20    UInt16,
21    /// 32-bit unsigned integer
22    UInt32,
23}
24
25impl ZarrDataType {
26    /// Returns the number of bytes per element.
27    pub fn byte_size(&self) -> usize {
28        match self {
29            ZarrDataType::Float32 => 4,
30            ZarrDataType::Float64 => 8,
31            ZarrDataType::Int32 => 4,
32            ZarrDataType::Int64 => 8,
33            ZarrDataType::UInt8 => 1,
34            ZarrDataType::UInt16 => 2,
35            ZarrDataType::UInt32 => 4,
36        }
37    }
38
39    /// Returns the Zarr v3 data type string.
40    pub fn as_str(&self) -> &'static str {
41        match self {
42            ZarrDataType::Float32 => "float32",
43            ZarrDataType::Float64 => "float64",
44            ZarrDataType::Int32 => "int32",
45            ZarrDataType::Int64 => "int64",
46            ZarrDataType::UInt8 => "uint8",
47            ZarrDataType::UInt16 => "uint16",
48            ZarrDataType::UInt32 => "uint32",
49        }
50    }
51}
52
53/// Zarr compressor configuration.
54///
55/// Actual compression is handled via oxiarc-* crates (COOLJAPAN Policy).
56/// For `None`, raw bytes are stored.
57#[non_exhaustive]
58#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
59pub enum ZarrCompressor {
60    /// No compression — store raw bytes.
61    None,
62    /// Blosc compression (placeholder; compression via oxiarc).
63    Blosc {
64        /// Blosc codec name (e.g., "lz4", "zstd").
65        cname: String,
66        /// Compression level (1–9).
67        clevel: u8,
68    },
69    /// GZip/Deflate compression via oxiarc-deflate.
70    GZip {
71        /// Compression level (1–9).
72        level: u8,
73    },
74    /// Zstandard compression via oxiarc-zstd.
75    Zstd {
76        /// Compression level (1–22).
77        level: u8,
78    },
79}
80
81/// Zarr v3 array metadata (zarr.json).
82#[non_exhaustive]
83#[derive(Debug, Clone, Serialize, Deserialize)]
84pub struct ZarrArrayMeta {
85    /// Shape of the array.
86    pub shape: Vec<usize>,
87    /// Chunk shape (must have same length as `shape`).
88    pub chunks: Vec<usize>,
89    /// Element data type.
90    pub dtype: ZarrDataType,
91    /// Compressor configuration.
92    pub compressor: ZarrCompressor,
93    /// Fill value for missing/unwritten chunks.
94    pub fill_value: f64,
95    /// Zarr format version (must be 3).
96    pub zarr_format: u8,
97    /// Separator character used in chunk keys ('/' for v3).
98    pub dimension_separator: char,
99}
100
101impl Default for ZarrArrayMeta {
102    fn default() -> Self {
103        Self {
104            shape: vec![],
105            chunks: vec![],
106            dtype: ZarrDataType::Float64,
107            compressor: ZarrCompressor::None,
108            fill_value: 0.0,
109            zarr_format: 3,
110            dimension_separator: '/',
111        }
112    }
113}
114
115/// An in-memory Zarr array with flat f64 storage.
116pub struct ZarrArray {
117    /// Array metadata.
118    pub meta: ZarrArrayMeta,
119    /// Flat data buffer in row-major order.
120    pub(crate) data: Vec<f64>,
121}
122
123impl ZarrArray {
124    /// Create a new ZarrArray with given metadata and flat data.
125    pub fn new(meta: ZarrArrayMeta, data: Vec<f64>) -> Self {
126        Self { meta, data }
127    }
128
129    /// Total number of elements.
130    pub fn len(&self) -> usize {
131        self.data.len()
132    }
133
134    /// Returns `true` if the array contains no elements.
135    pub fn is_empty(&self) -> bool {
136        self.data.is_empty()
137    }
138
139    /// Access data as a flat slice.
140    pub fn as_slice(&self) -> &[f64] {
141        &self.data
142    }
143}