@@ -8,8 +8,7 @@ use pyo3::{
88} ;
99use pyo3_stub_gen:: derive:: { gen_stub_pyclass, gen_stub_pymethods} ;
1010use zarrs:: {
11- array:: { ChunkRepresentation , DataType , FillValue } ,
12- array_subset:: ArraySubset ,
11+ array:: { ArraySubset , ChunkShape , DataType , FillValue } ,
1312 metadata:: v3:: MetadataV3 ,
1413 storage:: StoreKey ,
1514} ;
@@ -18,15 +17,19 @@ use crate::utils::PyErrExt;
1817
1918pub ( crate ) trait ChunksItem {
2019 fn key ( & self ) -> & StoreKey ;
21- fn representation ( & self ) -> & ChunkRepresentation ;
20+ fn shape ( & self ) -> & [ NonZeroU64 ] ;
21+ fn data_type ( & self ) -> & DataType ;
22+ fn fill_value ( & self ) -> & FillValue ;
2223}
2324
2425#[ derive( Clone ) ]
2526#[ gen_stub_pyclass]
2627#[ pyclass]
2728pub ( crate ) struct Basic {
2829 key : StoreKey ,
29- representation : ChunkRepresentation ,
30+ shape : ChunkShape ,
31+ data_type : DataType ,
32+ fill_value : FillValue ,
3033}
3134
3235fn fill_value_to_bytes ( dtype : & str , fill_value : & Bound < ' _ , PyAny > ) -> PyResult < Vec < u8 > > {
@@ -62,7 +65,8 @@ impl Basic {
6265 fn new ( byte_interface : & Bound < ' _ , PyAny > , chunk_spec : & Bound < ' _ , PyAny > ) -> PyResult < Self > {
6366 let path: String = byte_interface. getattr ( "path" ) ?. extract ( ) ?;
6467
65- let chunk_shape = chunk_spec. getattr ( "shape" ) ?. extract ( ) ?;
68+ let shape: Vec < NonZeroU64 > = chunk_spec. getattr ( "shape" ) ?. extract ( ) ?;
69+
6670 let mut dtype: String = chunk_spec
6771 . getattr ( "dtype" ) ?
6872 . call_method0 ( "to_native_dtype" ) ?
@@ -73,11 +77,14 @@ impl Basic {
7377 // but maps it to "string" internally https://github.com/LDeakin/zarrs/blob/0532fe983b7b42b59dbf84e50a2fe5e6f7bad4ce/zarrs_metadata/src/v2_to_v3.rs#L288
7478 dtype = String :: from ( "string" ) ;
7579 }
80+ let data_type = get_data_type_from_dtype ( & dtype) ?;
7681 let fill_value: Bound < ' _ , PyAny > = chunk_spec. getattr ( "fill_value" ) ?;
77- let fill_value_bytes = fill_value_to_bytes ( & dtype, & fill_value) ?;
82+ let fill_value = FillValue :: new ( fill_value_to_bytes ( & dtype, & fill_value) ?) ;
7883 Ok ( Self {
7984 key : StoreKey :: new ( path) . map_py_err :: < PyValueError > ( ) ?,
80- representation : get_chunk_representation ( chunk_shape, & dtype, fill_value_bytes) ?,
85+ shape,
86+ data_type,
87+ fill_value,
8188 } )
8289 }
8390}
@@ -102,8 +109,15 @@ impl WithSubset {
102109 subset : Vec < Bound < ' _ , PySlice > > ,
103110 shape : Vec < u64 > ,
104111 ) -> PyResult < Self > {
105- let chunk_subset =
106- selection_to_array_subset ( & chunk_subset, & item. representation . shape_u64 ( ) ) ?;
112+ let chunk_subset = selection_to_array_subset ( & chunk_subset, & item. shape ) ?;
113+ let shape: Vec < NonZeroU64 > = shape
114+ . into_iter ( )
115+ . map ( |dim| {
116+ NonZeroU64 :: new ( dim)
117+ . ok_or ( "subset dimensions must be greater than zero" )
118+ . map_py_err :: < PyValueError > ( )
119+ } )
120+ . collect :: < PyResult < Vec < NonZeroU64 > > > ( ) ?;
107121 let subset = selection_to_array_subset ( & subset, & shape) ?;
108122 // Check that subset and chunk_subset have the same number of elements.
109123 // This permits broadcasting of a constant input.
@@ -124,39 +138,36 @@ impl ChunksItem for Basic {
124138 fn key ( & self ) -> & StoreKey {
125139 & self . key
126140 }
127- fn representation ( & self ) -> & ChunkRepresentation {
128- & self . representation
141+ fn shape ( & self ) -> & [ NonZeroU64 ] {
142+ & self . shape
143+ }
144+ fn data_type ( & self ) -> & DataType {
145+ & self . data_type
146+ }
147+ fn fill_value ( & self ) -> & FillValue {
148+ & self . fill_value
129149 }
130150}
131151
132152impl ChunksItem for WithSubset {
133153 fn key ( & self ) -> & StoreKey {
134154 & self . item . key
135155 }
136- fn representation ( & self ) -> & ChunkRepresentation {
137- & self . item . representation
156+ fn shape ( & self ) -> & [ NonZeroU64 ] {
157+ & self . item . shape
158+ }
159+ fn data_type ( & self ) -> & DataType {
160+ & self . item . data_type
161+ }
162+ fn fill_value ( & self ) -> & FillValue {
163+ & self . item . fill_value
138164 }
139165}
140166
141- fn get_chunk_representation (
142- chunk_shape : Vec < u64 > ,
143- dtype : & str ,
144- fill_value : Vec < u8 > ,
145- ) -> PyResult < ChunkRepresentation > {
146- // Get the chunk representation
147- let data_type = DataType :: from_metadata (
148- & MetadataV3 :: new ( dtype) ,
149- zarrs:: config:: global_config ( ) . data_type_aliases_v3 ( ) ,
150- )
151- . map_py_err :: < PyRuntimeError > ( ) ?;
152- let chunk_shape = chunk_shape
153- . into_iter ( )
154- . map ( |x| NonZeroU64 :: new ( x) . expect ( "chunk shapes should always be non-zero" ) )
155- . collect ( ) ;
156- let chunk_representation =
157- ChunkRepresentation :: new ( chunk_shape, data_type, FillValue :: new ( fill_value) )
158- . map_py_err :: < PyValueError > ( ) ?;
159- Ok ( chunk_representation)
167+ fn get_data_type_from_dtype ( dtype : & str ) -> PyResult < DataType > {
168+ let data_type =
169+ DataType :: from_metadata ( & MetadataV3 :: new ( dtype) ) . map_py_err :: < PyRuntimeError > ( ) ?;
170+ Ok ( data_type)
160171}
161172
162173fn slice_to_range ( slice : & Bound < ' _ , PySlice > , length : isize ) -> PyResult < std:: ops:: Range < u64 > > {
@@ -180,15 +191,15 @@ fn slice_to_range(slice: &Bound<'_, PySlice>, length: isize) -> PyResult<std::op
180191
181192fn selection_to_array_subset (
182193 selection : & [ Bound < ' _ , PySlice > ] ,
183- shape : & [ u64 ] ,
194+ shape : & [ NonZeroU64 ] ,
184195) -> PyResult < ArraySubset > {
185196 if selection. is_empty ( ) {
186197 Ok ( ArraySubset :: new_with_shape ( vec ! [ 1 ; shape. len( ) ] ) )
187198 } else {
188199 let chunk_ranges = selection
189200 . iter ( )
190201 . zip ( shape)
191- . map ( |( selection, & shape) | slice_to_range ( selection, isize:: try_from ( shape) ?) )
202+ . map ( |( selection, & shape) | slice_to_range ( selection, isize:: try_from ( shape. get ( ) ) ?) )
192203 . collect :: < PyResult < Vec < _ > > > ( ) ?;
193204 Ok ( ArraySubset :: new_with_ranges ( & chunk_ranges) )
194205 }
0 commit comments