@@ -20,14 +20,15 @@ use unsafe_cell_slice::UnsafeCellSlice;
2020use utils:: is_whole_chunk;
2121use zarrs:: array:: codec:: {
2222 ArrayPartialDecoderTraits , ArrayToBytesCodecTraits , CodecOptions , CodecOptionsBuilder ,
23+ StoragePartialDecoder ,
2324} ;
2425use zarrs:: array:: {
25- copy_fill_value_into, update_array_bytes, ArrayBytes , ArrayBytesFixedDisjointView , ArraySize ,
26- CodecChain , FillValue ,
26+ copy_fill_value_into, update_array_bytes, Array , ArrayBytes , ArrayBytesFixedDisjointView ,
27+ ArrayMetadata , ArraySize , CodecChain , FillValue ,
2728} ;
2829use zarrs:: array_subset:: ArraySubset ;
29- use zarrs:: metadata :: v3 :: MetadataV3 ;
30- use zarrs:: storage:: StoreKey ;
30+ use zarrs:: storage :: store :: MemoryStore ;
31+ use zarrs:: storage:: { ReadableWritableListableStorage , StorageHandle , StoreKey } ;
3132
3233mod chunk_item;
3334mod concurrency;
@@ -41,14 +42,14 @@ mod utils;
4142use crate :: chunk_item:: ChunksItem ;
4243use crate :: concurrency:: ChunkConcurrentLimitAndCodecOptions ;
4344use crate :: metadata_v2:: codec_metadata_v2_to_v3;
44- use crate :: store:: StoreManager ;
45+ use crate :: store:: StoreConfig ;
4546use crate :: utils:: { PyErrExt as _, PyUntypedArrayExt as _} ;
4647
4748// TODO: Use a OnceLock for store with get_or_try_init when stabilised?
4849#[ gen_stub_pyclass]
4950#[ pyclass]
5051pub struct CodecPipelineImpl {
51- pub ( crate ) stores : StoreManager ,
52+ pub ( crate ) store : ReadableWritableListableStorage ,
5253 pub ( crate ) codec_chain : Arc < CodecChain > ,
5354 pub ( crate ) codec_options : CodecOptions ,
5455 pub ( crate ) chunk_concurrent_minimum : usize ,
@@ -63,7 +64,7 @@ impl CodecPipelineImpl {
6364 codec_chain : & CodecChain ,
6465 codec_options : & CodecOptions ,
6566 ) -> PyResult < ArrayBytes < ' a > > {
66- let value_encoded = self . stores . get ( item) ?;
67+ let value_encoded = self . store . get ( item. key ( ) ) . map_py_err :: < PyRuntimeError > ( ) ?;
6768 let value_decoded = if let Some ( value_encoded) = value_encoded {
6869 let value_encoded: Vec < u8 > = value_encoded. into ( ) ; // zero-copy in this case
6970 codec_chain
@@ -94,15 +95,17 @@ impl CodecPipelineImpl {
9495 . map_py_err :: < PyValueError > ( ) ?;
9596
9697 if value_decoded. is_fill_value ( item. representation ( ) . fill_value ( ) ) {
97- self . stores . erase ( item)
98+ self . store . erase ( item. key ( ) ) . map_py_err :: < PyRuntimeError > ( )
9899 } else {
99100 let value_encoded = codec_chain
100101 . encode ( value_decoded, item. representation ( ) , codec_options)
101102 . map ( Cow :: into_owned)
102103 . map_py_err :: < PyRuntimeError > ( ) ?;
103104
104105 // Store the encoded chunk
105- self . stores . set ( item, value_encoded. into ( ) )
106+ self . store
107+ . set ( item. key ( ) , value_encoded. into ( ) )
108+ . map_py_err :: < PyRuntimeError > ( )
106109 }
107110 }
108111
@@ -204,7 +207,8 @@ impl CodecPipelineImpl {
204207#[ pymethods]
205208impl CodecPipelineImpl {
206209 #[ pyo3( signature = (
207- metadata,
210+ array_metadata,
211+ store_config,
208212 * ,
209213 validate_checksums=None ,
210214 chunk_concurrent_minimum=None ,
@@ -213,16 +217,21 @@ impl CodecPipelineImpl {
213217 ) ) ]
214218 #[ new]
215219 fn new (
216- metadata : & str ,
220+ array_metadata : & str ,
221+ store_config : StoreConfig ,
217222 validate_checksums : Option < bool > ,
218223 chunk_concurrent_minimum : Option < usize > ,
219224 chunk_concurrent_maximum : Option < usize > ,
220225 num_threads : Option < usize > ,
221226 ) -> PyResult < Self > {
222- let metadata: Vec < MetadataV3 > =
223- serde_json:: from_str ( metadata) . map_py_err :: < PyTypeError > ( ) ?;
224- let codec_chain =
225- Arc :: new ( CodecChain :: from_metadata ( & metadata) . map_py_err :: < PyTypeError > ( ) ?) ;
227+ let metadata: ArrayMetadata =
228+ serde_json:: from_str ( array_metadata) . map_py_err :: < PyTypeError > ( ) ?;
229+
230+ // TODO: Add a direct metadata -> codec chain method to zarrs
231+ let store = Arc :: new ( MemoryStore :: new ( ) ) ;
232+ let array = Array :: new_with_metadata ( store, "/" , metadata) . map_py_err :: < PyTypeError > ( ) ?;
233+ let codec_chain = Arc :: new ( array. codecs ( ) . clone ( ) ) ;
234+
226235 let mut codec_options = CodecOptionsBuilder :: new ( ) ;
227236 if let Some ( validate_checksums) = validate_checksums {
228237 codec_options = codec_options. validate_checksums ( validate_checksums) ;
@@ -235,8 +244,11 @@ impl CodecPipelineImpl {
235244 chunk_concurrent_maximum. unwrap_or ( rayon:: current_num_threads ( ) ) ;
236245 let num_threads = num_threads. unwrap_or ( rayon:: current_num_threads ( ) ) ;
237246
247+ let store: ReadableWritableListableStorage =
248+ ( & store_config) . try_into ( ) . map_py_err :: < PyTypeError > ( ) ?;
249+
238250 Ok ( Self {
239- stores : StoreManager :: default ( ) ,
251+ store ,
240252 codec_chain,
241253 codec_options,
242254 chunk_concurrent_minimum,
@@ -276,7 +288,9 @@ impl CodecPipelineImpl {
276288 partial_chunk_descriptions,
277289 map,
278290 |item| {
279- let input_handle = self . stores. decoder( item) ?;
291+ let storage_handle = Arc :: new( StorageHandle :: new( self . store. clone( ) ) ) ;
292+ let input_handle =
293+ StoragePartialDecoder :: new( storage_handle, item. key( ) . clone( ) ) ;
280294 let partial_decoder = self
281295 . codec_chain
282296 . clone( )
@@ -326,7 +340,9 @@ impl CodecPipelineImpl {
326340 && chunk_subset. shape ( ) == item. representation ( ) . shape_u64 ( )
327341 {
328342 // See zarrs::array::Array::retrieve_chunk_into
329- if let Some ( chunk_encoded) = self . stores . get ( & item) ? {
343+ if let Some ( chunk_encoded) =
344+ self . store . get ( item. key ( ) ) . map_py_err :: < PyRuntimeError > ( ) ?
345+ {
330346 // Decode the encoded data into the output buffer
331347 let chunk_encoded: Vec < u8 > = chunk_encoded. into ( ) ;
332348 self . codec_chain . decode_into (
0 commit comments