diff --git a/CHANGELOG.md b/CHANGELOG.md index 06d4a769..b9d2d599 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Allow float fill values to be created from int fill value metadata - Make `chunk_grid::{regular,rectangular}` public + - Support 8 and 16 bit integer data types with zfp codec by promoting to 32 bit ### Fixed - Fix `compute_encoded_size()` for `BitroundCodec` incorrectly indicating various data types were unsupported diff --git a/src/array/codec/array_to_bytes/zfp.rs b/src/array/codec/array_to_bytes/zfp.rs index d7927b99..6bc655b4 100644 --- a/src/array/codec/array_to_bytes/zfp.rs +++ b/src/array/codec/array_to_bytes/zfp.rs @@ -1,11 +1,13 @@ //! The `zfp` array to bytes codec. //! //! [zfp](https://zfp.io/) is a compressed number format for 1D to 4D arrays of 32/64-bit floating point or integer data. +//! 8/16-bit integer types are supported through promotion to 32-bit in accordance with the [zfp utility functions](https://zfp.readthedocs.io/en/release1.0.1/low-level-api.html#utility-functions). //! //! This codec requires the `zfp` feature, which is disabled by default. //! //! See [`ZfpCodecConfigurationV1`] for example `JSON` metadata. +mod zfp_array; mod zfp_bitstream; mod zfp_codec; mod zfp_configuration; @@ -23,20 +25,21 @@ pub use zfp_configuration::{ use zfp_sys::{ zfp_decompress, zfp_exec_policy_zfp_exec_omp, zfp_stream_rewind, zfp_stream_set_bit_stream, - zfp_stream_set_execution, zfp_type, zfp_type_zfp_type_double, zfp_type_zfp_type_float, - zfp_type_zfp_type_int32, zfp_type_zfp_type_int64, + zfp_stream_set_execution, }; use crate::{ array::{ codec::{Codec, CodecError, CodecPlugin}, - ChunkRepresentation, DataType, + transmute_from_bytes_vec, transmute_to_bytes_vec, ChunkRepresentation, DataType, }, metadata::Metadata, plugin::{PluginCreateError, PluginMetadataInvalidError}, }; -use self::{zfp_bitstream::ZfpBitstream, zfp_field::ZfpField, zfp_stream::ZfpStream}; +use self::{ + zfp_array::ZfpArray, zfp_bitstream::ZfpBitstream, zfp_field::ZfpField, zfp_stream::ZfpStream, +}; /// The identifier for the `zfp` codec. pub const IDENTIFIER: &str = "zfp"; @@ -99,27 +102,145 @@ pub struct ZfpExpertParams { pub minexp: i32, } -const fn zarr_data_type_to_zfp_data_type(data_type: &DataType) -> Option { +const fn zarr_to_zfp_data_type(data_type: &DataType) -> Option { match data_type { - DataType::Int32 | DataType::UInt32 => Some(zfp_type_zfp_type_int32), - DataType::Int64 | DataType::UInt64 => Some(zfp_type_zfp_type_int64), - DataType::Float32 => Some(zfp_type_zfp_type_float), - DataType::Float64 => Some(zfp_type_zfp_type_double), + DataType::Int8 + | DataType::UInt8 + | DataType::Int16 + | DataType::UInt16 + | DataType::Int32 + | DataType::UInt32 => Some(zfp_sys::zfp_type_zfp_type_int32), + DataType::Int64 | DataType::UInt64 => Some(zfp_sys::zfp_type_zfp_type_int64), + DataType::Float32 => Some(zfp_sys::zfp_type_zfp_type_float), + DataType::Float64 => Some(zfp_sys::zfp_type_zfp_type_double), _ => None, } } +fn promote_before_zfp_encoding( + decoded_value: Vec, + decoded_representation: &ChunkRepresentation, +) -> Result { + match decoded_representation.data_type() { + DataType::Int8 => { + let decoded_value = transmute_from_bytes_vec::(decoded_value); + let decoded_value_promoted = + decoded_value.iter().map(|i| i32::from(*i) << 23).collect(); + Ok(ZfpArray::Int32(decoded_value_promoted)) + } + DataType::UInt8 => { + let decoded_value = transmute_from_bytes_vec::(decoded_value); + let decoded_value_promoted = decoded_value + .iter() + .map(|i| (i32::from(*i) - 0x80) << 23) + .collect(); + Ok(ZfpArray::Int32(decoded_value_promoted)) + } + DataType::Int16 => { + let decoded_value = transmute_from_bytes_vec::(decoded_value); + let decoded_value_promoted = + decoded_value.iter().map(|i| i32::from(*i) << 15).collect(); + Ok(ZfpArray::Int32(decoded_value_promoted)) + } + DataType::UInt16 => { + let decoded_value = transmute_from_bytes_vec::(decoded_value); + let decoded_value_promoted = decoded_value + .iter() + .map(|i| (i32::from(*i) - 0x8000) << 15) + .collect(); + Ok(ZfpArray::Int32(decoded_value_promoted)) + } + DataType::Int32 | DataType::UInt32 => Ok(ZfpArray::Int32(transmute_from_bytes_vec::( + decoded_value, + ))), + DataType::Int64 | DataType::UInt64 => Ok(ZfpArray::Int64(transmute_from_bytes_vec::( + decoded_value, + ))), + DataType::Float32 => Ok(ZfpArray::Float(transmute_from_bytes_vec::( + decoded_value, + ))), + DataType::Float64 => Ok(ZfpArray::Double(transmute_from_bytes_vec::( + decoded_value, + ))), + _ => Err(CodecError::UnsupportedDataType( + decoded_representation.data_type().clone(), + IDENTIFIER.to_string(), + )), + } +} + +fn init_zfp_decoding_output( + decoded_representation: &ChunkRepresentation, +) -> Result { + let num_elements = decoded_representation.num_elements_usize(); + match decoded_representation.data_type() { + DataType::Int8 + | DataType::UInt8 + | DataType::Int16 + | DataType::UInt16 + | DataType::Int32 + | DataType::UInt32 => Ok(ZfpArray::Int32(vec![0; num_elements])), + DataType::Int64 | DataType::UInt64 => Ok(ZfpArray::Int64(vec![0; num_elements])), + DataType::Float32 => Ok(ZfpArray::Float(vec![0.0; num_elements])), + DataType::Float64 => Ok(ZfpArray::Double(vec![0.0; num_elements])), + _ => Err(CodecError::UnsupportedDataType( + decoded_representation.data_type().clone(), + IDENTIFIER.to_string(), + )), + } +} + +fn demote_after_zfp_decoding( + array: ZfpArray, + decoded_representation: &ChunkRepresentation, +) -> Result, CodecError> { + #[allow(non_upper_case_globals)] + match (decoded_representation.data_type(), array) { + (DataType::Int32 | DataType::UInt32, ZfpArray::Int32(vec)) => { + Ok(transmute_to_bytes_vec(vec)) + } + (DataType::Int64 | DataType::UInt64, ZfpArray::Int64(vec)) => { + Ok(transmute_to_bytes_vec(vec)) + } + (DataType::Float32, ZfpArray::Float(vec)) => Ok(transmute_to_bytes_vec(vec)), + (DataType::Float64, ZfpArray::Double(vec)) => Ok(transmute_to_bytes_vec(vec)), + (DataType::Int8, ZfpArray::Int32(vec)) => Ok(transmute_to_bytes_vec( + vec.into_iter() + .map(|i| i8::try_from((i >> 23).clamp(-0x80, 0x7f)).unwrap()) + .collect(), + )), + (DataType::UInt8, ZfpArray::Int32(vec)) => Ok(transmute_to_bytes_vec( + vec.into_iter() + .map(|i| u8::try_from(((i >> 23) + 0x80).clamp(0x00, 0xff)).unwrap()) + .collect(), + )), + (DataType::Int16, ZfpArray::Int32(vec)) => Ok(transmute_to_bytes_vec( + vec.into_iter() + .map(|i| i16::try_from((i >> 15).clamp(-0x8000, 0x7fff)).unwrap()) + .collect(), + )), + (DataType::UInt16, ZfpArray::Int32(vec)) => Ok(transmute_to_bytes_vec( + vec.into_iter() + .map(|i| u16::try_from(((i >> 15) + 0x8000).clamp(0x0000, 0xffff)).unwrap()) + .collect(), + )), + _ => Err(CodecError::UnsupportedDataType( + decoded_representation.data_type().clone(), + IDENTIFIER.to_string(), + )), + } +} + fn zfp_decode( zfp_mode: &ZfpMode, - zfp_type: zfp_type, mut encoded_value: Vec, decoded_representation: &ChunkRepresentation, parallel: bool, ) -> Result, CodecError> { - let mut decoded_value = vec![0u8; usize::try_from(decoded_representation.size()).unwrap()]; + let mut array = init_zfp_decoding_output(decoded_representation)?; + let zfp_type = array.zfp_type(); let Some(field) = ZfpField::new( - &mut decoded_value, - zfp_type, + &mut array, &decoded_representation .shape() .iter() @@ -148,15 +269,17 @@ fn zfp_decode( } let ret = unsafe { zfp_decompress(zfp.as_zfp_stream(), field.as_zfp_field()) }; + drop(field); if ret == 0 { Err(CodecError::from("zfp decompression failed")) } else { - Ok(decoded_value) + demote_after_zfp_decoding(array, decoded_representation) } } #[cfg(test)] mod tests { + use num::traits::AsPrimitive; use std::num::NonZeroU64; use crate::{ @@ -166,25 +289,40 @@ mod tests { use super::*; - const JSON_VALID: &'static str = r#"{ - "mode": "fixedprecision", - "precision": 12 + const JSON_REVERSIBLE: &'static str = r#"{ + "mode": "reversible" }"#; - #[test] - #[cfg_attr(miri, ignore)] - fn codec_zfp_round_trip1() { - let chunk_shape = vec![ + fn json_fixedrate(rate: f32) -> String { + format!(r#"{{ "mode": "fixedrate", "rate": {rate} }}"#) + } + + fn json_fixedprecision(precision: u32) -> String { + format!(r#"{{ "mode": "fixedprecision", "precision": {precision} }}"#) + } + + fn json_fixedaccuracy(tolerance: f32) -> String { + format!(r#"{{ "mode": "fixedaccuracy", "tolerance": {tolerance} }}"#) + } + + fn chunk_shape() -> Vec { + vec![ NonZeroU64::new(3).unwrap(), NonZeroU64::new(3).unwrap(), NonZeroU64::new(3).unwrap(), - ]; - let chunk_representation = - ChunkRepresentation::new(chunk_shape, DataType::Float32, 0.0f32.into()).unwrap(); - let elements: Vec = (0..27).map(|i| i as f32).collect(); + ] + } + + fn codec_zfp_round_trip( + chunk_representation: &ChunkRepresentation, + configuration: &str, + ) where + i32: num::traits::AsPrimitive, + { + let elements: Vec = (0..27).map(|i: i32| i.as_()).collect(); let bytes = crate::array::transmute_to_bytes_vec(elements.clone()); - let configuration: ZfpCodecConfiguration = serde_json::from_str(JSON_VALID).unwrap(); + let configuration: ZfpCodecConfiguration = serde_json::from_str(configuration).unwrap(); let codec = ZfpCodec::new_with_configuration(&configuration); let encoded = codec @@ -202,10 +340,156 @@ mod tests { ) .unwrap(); - let decoded_elements = crate::array::transmute_from_bytes_vec::(decoded); + let decoded_elements = crate::array::transmute_from_bytes_vec::(decoded); assert_eq!(elements, decoded_elements); } + #[test] + #[cfg_attr(miri, ignore)] + fn codec_zfp_round_trip_i8() { + codec_zfp_round_trip::( + &ChunkRepresentation::new(chunk_shape(), DataType::Int8, 0i8.into()).unwrap(), + JSON_REVERSIBLE, + ); + // codec_zfp_round_trip::( + // &ChunkRepresentation::new(chunk_shape(), DataType::Int8, 0i8.into()).unwrap(), + // &json_fixedprecision(8), + // ); + } + + #[test] + #[cfg_attr(miri, ignore)] + fn codec_zfp_round_trip_u8() { + codec_zfp_round_trip::( + &ChunkRepresentation::new(chunk_shape(), DataType::UInt8, 0u8.into()).unwrap(), + JSON_REVERSIBLE, + ); + // codec_zfp_round_trip::( + // &ChunkRepresentation::new(chunk_shape(), DataType::UInt8, 0u8.into()).unwrap(), + // &json_fixedprecision(8), + // ); + } + + #[test] + #[cfg_attr(miri, ignore)] + fn codec_zfp_round_trip_i16() { + codec_zfp_round_trip::( + &ChunkRepresentation::new(chunk_shape(), DataType::Int16, 0i16.into()).unwrap(), + JSON_REVERSIBLE, + ); + // codec_zfp_round_trip::( + // &ChunkRepresentation::new(chunk_shape(), DataType::Int16, 0i16.into()).unwrap(), + // &json_fixedprecision(16), + // ); + } + + #[test] + #[cfg_attr(miri, ignore)] + fn codec_zfp_round_trip_u16() { + codec_zfp_round_trip::( + &ChunkRepresentation::new(chunk_shape(), DataType::UInt16, 0u16.into()).unwrap(), + JSON_REVERSIBLE, + ); + // codec_zfp_round_trip::( + // &ChunkRepresentation::new(chunk_shape(), DataType::UInt16, 0u16.into()).unwrap(), + // &json_fixedprecision(16), + // ); + } + + #[test] + #[cfg_attr(miri, ignore)] + fn codec_zfp_round_trip_i32() { + codec_zfp_round_trip::( + &ChunkRepresentation::new(chunk_shape(), DataType::Int32, 0i32.into()).unwrap(), + JSON_REVERSIBLE, + ); + // codec_zfp_round_trip::( + // &ChunkRepresentation::new(chunk_shape(), DataType::Int32, 0i32.into()).unwrap(), + // &json_fixedprecision(32), + // ); + } + + #[test] + #[cfg_attr(miri, ignore)] + fn codec_zfp_round_trip_u32() { + codec_zfp_round_trip::( + &ChunkRepresentation::new(chunk_shape(), DataType::UInt32, 0u32.into()).unwrap(), + JSON_REVERSIBLE, + ); + // codec_zfp_round_trip::( + // &ChunkRepresentation::new(chunk_shape(), DataType::UInt32, 0u32.into()).unwrap(), + // &json_fixedprecision(32), + // ); + } + + #[test] + #[cfg_attr(miri, ignore)] + fn codec_zfp_round_trip_i64() { + codec_zfp_round_trip::( + &ChunkRepresentation::new(chunk_shape(), DataType::Int64, 0i64.into()).unwrap(), + JSON_REVERSIBLE, + ); + // codec_zfp_round_trip::( + // &ChunkRepresentation::new(chunk_shape(), DataType::Int64, 0i64.into()).unwrap(), + // &json_fixedprecision(64), + // ); + } + + #[test] + #[cfg_attr(miri, ignore)] + fn codec_zfp_round_trip_u64() { + codec_zfp_round_trip::( + &ChunkRepresentation::new(chunk_shape(), DataType::UInt64, 0u64.into()).unwrap(), + JSON_REVERSIBLE, + ); + // codec_zfp_round_trip::( + // &ChunkRepresentation::new(chunk_shape(), DataType::UInt64, 0u64.into()).unwrap(), + // &json_fixedprecision(64), + // ); + } + + #[test] + #[cfg_attr(miri, ignore)] + fn codec_zfp_round_trip_f32() { + codec_zfp_round_trip::( + &ChunkRepresentation::new(chunk_shape(), DataType::Float32, 0.0f32.into()).unwrap(), + JSON_REVERSIBLE, + ); + codec_zfp_round_trip::( + &ChunkRepresentation::new(chunk_shape(), DataType::Float32, 0.0f32.into()).unwrap(), + &json_fixedrate(2.5), + ); + codec_zfp_round_trip::( + &ChunkRepresentation::new(chunk_shape(), DataType::Float32, 0.0f32.into()).unwrap(), + &json_fixedaccuracy(1.0), + ); + codec_zfp_round_trip::( + &ChunkRepresentation::new(chunk_shape(), DataType::Float32, 0.0f32.into()).unwrap(), + &json_fixedprecision(13), + ); + } + + #[test] + #[cfg_attr(miri, ignore)] + fn codec_zfp_round_trip_f64() { + codec_zfp_round_trip::( + &ChunkRepresentation::new(chunk_shape(), DataType::Float64, 0.0f64.into()).unwrap(), + JSON_REVERSIBLE, + ); + codec_zfp_round_trip::( + &ChunkRepresentation::new(chunk_shape(), DataType::Float64, 0.0f64.into()).unwrap(), + &json_fixedrate(2.5), + ); + codec_zfp_round_trip::( + &ChunkRepresentation::new(chunk_shape(), DataType::Float64, 0.0f64.into()).unwrap(), + &json_fixedaccuracy(1.0), + ); + codec_zfp_round_trip::( + &ChunkRepresentation::new(chunk_shape(), DataType::Float64, 0.0f64.into()).unwrap(), + &json_fixedprecision(16), + ); + } + #[test] #[cfg_attr(miri, ignore)] fn codec_zfp_partial_decode() { @@ -219,7 +503,7 @@ mod tests { let elements: Vec = (0..27).map(|i| i as f32).collect(); let bytes = crate::array::transmute_to_bytes_vec(elements); - let configuration: ZfpCodecConfiguration = serde_json::from_str(JSON_VALID).unwrap(); + let configuration: ZfpCodecConfiguration = serde_json::from_str(JSON_REVERSIBLE).unwrap(); let codec = ZfpCodec::new_with_configuration(&configuration); let encoded = codec @@ -273,7 +557,7 @@ mod tests { let elements: Vec = (0..27).map(|i| i as f32).collect(); let bytes = crate::array::transmute_to_bytes_vec(elements); - let configuration: ZfpCodecConfiguration = serde_json::from_str(JSON_VALID).unwrap(); + let configuration: ZfpCodecConfiguration = serde_json::from_str(JSON_REVERSIBLE).unwrap(); let codec = ZfpCodec::new_with_configuration(&configuration); let max_encoded_size = codec.compute_encoded_size(&chunk_representation).unwrap(); diff --git a/src/array/codec/array_to_bytes/zfp/zfp_array.rs b/src/array/codec/array_to_bytes/zfp/zfp_array.rs new file mode 100644 index 00000000..50194ef2 --- /dev/null +++ b/src/array/codec/array_to_bytes/zfp/zfp_array.rs @@ -0,0 +1,45 @@ +#[derive(Debug)] +pub enum ZfpArray { + Int32(Vec), + Int64(Vec), + Float(Vec), + Double(Vec), +} + +impl ZfpArray { + pub fn len(&self) -> usize { + match self { + ZfpArray::Int32(v) => v.len(), + ZfpArray::Int64(v) => v.len(), + ZfpArray::Float(v) => v.len(), + ZfpArray::Double(v) => v.len(), + } + } + + pub fn zfp_type(&self) -> zfp_sys::zfp_type { + match self { + ZfpArray::Int32(_) => zfp_sys::zfp_type_zfp_type_int32, + ZfpArray::Int64(_) => zfp_sys::zfp_type_zfp_type_int64, + ZfpArray::Float(_) => zfp_sys::zfp_type_zfp_type_float, + ZfpArray::Double(_) => zfp_sys::zfp_type_zfp_type_double, + } + } + + // pub fn as_ptr(&self) -> *const std::ffi::c_void { + // match self { + // ZfpArray::Int32(v) => v.as_ptr().cast::(), + // ZfpArray::Int64(v) => v.as_ptr().cast::(), + // ZfpArray::Float(v) => v.as_ptr().cast::(), + // ZfpArray::Double(v) => v.as_ptr().cast::(), + // } + // } + + pub fn as_mut_ptr(&mut self) -> *mut std::ffi::c_void { + match self { + ZfpArray::Int32(v) => v.as_mut_ptr().cast::(), + ZfpArray::Int64(v) => v.as_mut_ptr().cast::(), + ZfpArray::Float(v) => v.as_mut_ptr().cast::(), + ZfpArray::Double(v) => v.as_mut_ptr().cast::(), + } + } +} diff --git a/src/array/codec/array_to_bytes/zfp/zfp_codec.rs b/src/array/codec/array_to_bytes/zfp/zfp_codec.rs index 57b2a62a..7ffa8ad2 100644 --- a/src/array/codec/array_to_bytes/zfp/zfp_codec.rs +++ b/src/array/codec/array_to_bytes/zfp/zfp_codec.rs @@ -22,7 +22,7 @@ use crate::{ use crate::array::codec::{AsyncArrayPartialDecoderTraits, AsyncBytesPartialDecoderTraits}; use super::{ - zarr_data_type_to_zfp_data_type, + promote_before_zfp_encoding, zarr_to_zfp_data_type, zfp_bitstream::ZfpBitstream, zfp_configuration::{ ZfpFixedAccuracyConfiguration, ZfpFixedPrecisionConfiguration, ZfpFixedRateConfiguration, @@ -136,19 +136,15 @@ impl ArrayCodecTraits for ZfpCodec { fn encode( &self, - mut decoded_value: Vec, + decoded_value: Vec, decoded_representation: &ChunkRepresentation, _options: &CodecOptions, ) -> Result, CodecError> { - let Some(zfp_type) = zarr_data_type_to_zfp_data_type(decoded_representation.data_type()) - else { - return Err(CodecError::from( - "data type {} is unsupported for zfp codec", - )); - }; + let mut decoded_value_promoted = + promote_before_zfp_encoding(decoded_value, decoded_representation)?; + let zfp_type = decoded_value_promoted.zfp_type(); let Some(field) = ZfpField::new( - &mut decoded_value, - zfp_type, + &mut decoded_value_promoted, &decoded_representation .shape() .iter() @@ -197,15 +193,8 @@ impl ArrayCodecTraits for ZfpCodec { decoded_representation: &ChunkRepresentation, _options: &CodecOptions, ) -> Result, CodecError> { - let Some(zfp_type) = zarr_data_type_to_zfp_data_type(decoded_representation.data_type()) - else { - return Err(CodecError::from( - "data type {} is unsupported for zfp codec", - )); - }; zfp_decode( &self.mode, - zfp_type, encoded_value, decoded_representation, false, // FIXME @@ -247,8 +236,7 @@ impl ArrayToBytesCodecTraits for ZfpCodec { decoded_representation: &ChunkRepresentation, ) -> Result { let data_type = decoded_representation.data_type(); - let Some(zfp_type) = zarr_data_type_to_zfp_data_type(decoded_representation.data_type()) - else { + let Some(zfp_type) = zarr_to_zfp_data_type(decoded_representation.data_type()) else { return Err(CodecError::from( "data type {} is unsupported for zfp codec", )); diff --git a/src/array/codec/array_to_bytes/zfp/zfp_field.rs b/src/array/codec/array_to_bytes/zfp/zfp_field.rs index 2733ea1a..b0e8e1e9 100644 --- a/src/array/codec/array_to_bytes/zfp/zfp_field.rs +++ b/src/array/codec/array_to_bytes/zfp/zfp_field.rs @@ -1,38 +1,31 @@ -use std::ptr::NonNull; +use super::ZfpArray; +use std::{marker::PhantomData, ptr::NonNull}; use zfp_sys::{ zfp_field, zfp_field_1d, zfp_field_2d, zfp_field_3d, zfp_field_4d, zfp_field_free, zfp_type, - zfp_type_zfp_type_double, zfp_type_zfp_type_float, zfp_type_zfp_type_int32, - zfp_type_zfp_type_int64, }; /// A `zfp` field. #[derive(Debug)] -pub(super) struct ZfpField(NonNull); +pub(super) struct ZfpField<'a> { + field: NonNull, + phantom: PhantomData<&'a zfp_field>, +} -impl Drop for ZfpField { +impl Drop for ZfpField<'_> { fn drop(&mut self) { unsafe { - zfp_field_free(self.0.as_ptr()); + zfp_field_free(self.field.as_ptr()); } } } -#[allow(non_upper_case_globals)] -const fn zfp_type_to_size(zfp_type_: zfp_type) -> Option { - match zfp_type_ { - zfp_type_zfp_type_int32 | zfp_type_zfp_type_float => Some(4), - zfp_type_zfp_type_int64 | zfp_type_zfp_type_double => Some(8), - _ => None, - } -} - -impl ZfpField { - pub fn new(data: &mut [u8], zfp_type_: zfp_type, shape: &[usize]) -> Option { +impl<'a> ZfpField<'a> { + pub fn new(array: &'a mut ZfpArray, shape: &[usize]) -> Option { match shape.len() { - 1 => Self::new_1d(data, zfp_type_, shape[0]), - 2 => Self::new_2d(data, zfp_type_, shape[1], shape[0]), - 3 => Self::new_3d(data, zfp_type_, shape[2], shape[1], shape[0]), - 4 => Self::new_4d(data, zfp_type_, shape[3], shape[2], shape[1], shape[0]), + 1 => Self::new_1d(array, shape[0]), + 2 => Self::new_2d(array, shape[1], shape[0]), + 3 => Self::new_3d(array, shape[2], shape[1], shape[0]), + 4 => Self::new_4d(array, shape[3], shape[2], shape[1], shape[0]), _ => None, } } @@ -40,87 +33,87 @@ impl ZfpField { pub unsafe fn new_empty(zfp_type_: zfp_type, shape: &[usize]) -> Option { let pointer = core::ptr::null_mut::().cast::(); match shape.len() { - 1 => NonNull::new(unsafe { zfp_field_1d(pointer, zfp_type_, shape[0]) }).map(Self), - 2 => NonNull::new(unsafe { zfp_field_2d(pointer, zfp_type_, shape[1], shape[0]) }) - .map(Self), + 1 => NonNull::new(unsafe { zfp_field_1d(pointer, zfp_type_, shape[0]) }).map(|field| { + Self { + field, + phantom: PhantomData, + } + }), + 2 => NonNull::new(unsafe { zfp_field_2d(pointer, zfp_type_, shape[1], shape[0]) }).map( + |field| Self { + field, + phantom: PhantomData, + }, + ), 3 => NonNull::new(unsafe { zfp_field_3d(pointer, zfp_type_, shape[2], shape[1], shape[0]) }) - .map(Self), + .map(|field| Self { + field, + phantom: PhantomData, + }), 4 => NonNull::new(unsafe { zfp_field_4d(pointer, zfp_type_, shape[3], shape[2], shape[1], shape[0]) }) - .map(Self), + .map(|field| Self { + field, + phantom: PhantomData, + }), _ => None, } } - pub fn new_1d(data: &mut [u8], zfp_type_: zfp_type, nx: usize) -> Option { - if let Some(size) = zfp_type_to_size(zfp_type_) { - if size * nx != data.len() { - return None; - } - } else { + pub fn new_1d(array: &mut ZfpArray, nx: usize) -> Option { + if nx != array.len() { return None; } - let pointer = data.as_mut_ptr().cast::(); - let field = unsafe { zfp_field_1d(pointer, zfp_type_, nx) }; - NonNull::new(field).map(Self) + let field = unsafe { zfp_field_1d(array.as_mut_ptr(), array.zfp_type(), nx) }; + NonNull::new(field).map(|field| Self { + field, + phantom: PhantomData, + }) } - pub fn new_2d(data: &mut [u8], zfp_type_: zfp_type, nx: usize, ny: usize) -> Option { - if let Some(size) = zfp_type_to_size(zfp_type_) { - if size * nx * ny != data.len() { - return None; - } - } else { + pub fn new_2d(array: &mut ZfpArray, nx: usize, ny: usize) -> Option { + if nx * ny != array.len() { return None; } - let pointer = data.as_mut_ptr().cast::(); - let field = unsafe { zfp_field_2d(pointer, zfp_type_, nx, ny) }; - NonNull::new(field).map(Self) + let field = unsafe { zfp_field_2d(array.as_mut_ptr(), array.zfp_type(), nx, ny) }; + NonNull::new(field).map(|field| Self { + field, + phantom: PhantomData, + }) } - pub fn new_3d( - data: &mut [u8], - zfp_type_: zfp_type, - nx: usize, - ny: usize, - nz: usize, - ) -> Option { - if let Some(size) = zfp_type_to_size(zfp_type_) { - if size * nx * ny * nz != data.len() { - return None; - } - } else { + pub fn new_3d(array: &'a mut ZfpArray, nx: usize, ny: usize, nz: usize) -> Option { + if nx * ny * nz != array.len() { return None; } - let pointer = data.as_mut_ptr().cast::(); - let field = unsafe { zfp_field_3d(pointer, zfp_type_, nx, ny, nz) }; - NonNull::new(field).map(Self) + let field = unsafe { zfp_field_3d(array.as_mut_ptr(), array.zfp_type(), nx, ny, nz) }; + NonNull::new(field).map(|field| Self { + field, + phantom: PhantomData, + }) } pub fn new_4d( - data: &mut [u8], - zfp_type_: zfp_type, + array: &mut ZfpArray, nx: usize, ny: usize, nz: usize, nw: usize, ) -> Option { - if let Some(size) = zfp_type_to_size(zfp_type_) { - if size * nx * ny * nz * nw != data.len() { - return None; - } - } else { + if nx * ny * nz * nw != array.len() { return None; } - let pointer = data.as_mut_ptr().cast::(); - let field = unsafe { zfp_field_4d(pointer, zfp_type_, nx, ny, nz, nw) }; - NonNull::new(field).map(Self) + let field = unsafe { zfp_field_4d(array.as_mut_ptr(), array.zfp_type(), nx, ny, nz, nw) }; + NonNull::new(field).map(|field| Self { + field, + phantom: PhantomData, + }) } pub const fn as_zfp_field(&self) -> *mut zfp_field { - self.0.as_ptr() + self.field.as_ptr() } } diff --git a/src/array/codec/array_to_bytes/zfp/zfp_partial_decoder.rs b/src/array/codec/array_to_bytes/zfp/zfp_partial_decoder.rs index 14fa502f..1327d0ee 100644 --- a/src/array/codec/array_to_bytes/zfp/zfp_partial_decoder.rs +++ b/src/array/codec/array_to_bytes/zfp/zfp_partial_decoder.rs @@ -1,5 +1,3 @@ -use zfp_sys::zfp_type; - use crate::{ array::{ codec::{ArrayPartialDecoderTraits, BytesPartialDecoderTraits, CodecError, CodecOptions}, @@ -12,14 +10,13 @@ use crate::{ #[cfg(feature = "async")] use crate::array::codec::{AsyncArrayPartialDecoderTraits, AsyncBytesPartialDecoderTraits}; -use super::{zarr_data_type_to_zfp_data_type, zfp_decode, ZfpMode}; +use super::{zarr_to_zfp_data_type, zfp_decode, ZfpMode}; /// Partial decoder for the `zfp` codec. pub struct ZfpPartialDecoder<'a> { input_handle: Box, decoded_representation: ChunkRepresentation, mode: ZfpMode, - zfp_type: zfp_type, } impl<'a> ZfpPartialDecoder<'a> { @@ -29,21 +26,17 @@ impl<'a> ZfpPartialDecoder<'a> { decoded_representation: &ChunkRepresentation, mode: ZfpMode, ) -> Result { - zarr_data_type_to_zfp_data_type(decoded_representation.data_type()).map_or_else( - || { - Err(CodecError::from( - "data type {} is unsupported for zfp codec", - )) - }, - |zfp_type| { - Ok(Self { - input_handle, - decoded_representation: decoded_representation.clone(), - mode, - zfp_type, - }) - }, - ) + if zarr_to_zfp_data_type(decoded_representation.data_type()).is_some() { + Ok(Self { + input_handle, + decoded_representation: decoded_representation.clone(), + mode, + }) + } else { + Err(CodecError::from( + "data type {} is unsupported for zfp codec", + )) + } } } @@ -73,7 +66,6 @@ impl ArrayPartialDecoderTraits for ZfpPartialDecoder<'_> { Some(encoded_value) => { let decoded_value = zfp_decode( &self.mode, - self.zfp_type, encoded_value, &self.decoded_representation, false, // FIXME @@ -109,7 +101,6 @@ pub struct AsyncZfpPartialDecoder<'a> { input_handle: Box, decoded_representation: ChunkRepresentation, mode: ZfpMode, - zfp_type: zfp_type, } #[cfg(feature = "async")] @@ -120,21 +111,17 @@ impl<'a> AsyncZfpPartialDecoder<'a> { decoded_representation: &ChunkRepresentation, mode: ZfpMode, ) -> Result { - zarr_data_type_to_zfp_data_type(decoded_representation.data_type()).map_or_else( - || { - Err(CodecError::from( - "data type {} is unsupported for zfp codec", - )) - }, - |zfp_type| { - Ok(Self { - input_handle, - decoded_representation: decoded_representation.clone(), - mode, - zfp_type, - }) - }, - ) + if zarr_to_zfp_data_type(decoded_representation.data_type()).is_some() { + Ok(Self { + input_handle, + decoded_representation: decoded_representation.clone(), + mode, + }) + } else { + Err(CodecError::from( + "data type {} is unsupported for zfp codec", + )) + } } } @@ -166,7 +153,6 @@ impl AsyncArrayPartialDecoderTraits for AsyncZfpPartialDecoder<'_> { Some(encoded_value) => { let decoded_value = zfp_decode( &self.mode, - self.zfp_type, encoded_value, &self.decoded_representation, false, // FIXME