@@ -7,13 +7,15 @@ use hdf5_sys::h5p::{
77} ;
88use hdf5_sys:: h5t:: H5T_class_t ;
99use hdf5_sys:: h5z:: {
10- H5Z_filter_t , H5Zfilter_avail , H5Zget_filter_info , H5Z_FILTER_CONFIG_DECODE_ENABLED ,
10+ H5Zfilter_avail , H5Zget_filter_info , H5Z_FILTER_CONFIG_DECODE_ENABLED ,
1111 H5Z_FILTER_CONFIG_ENCODE_ENABLED , H5Z_FILTER_DEFLATE , H5Z_FILTER_FLETCHER32 , H5Z_FILTER_NBIT ,
1212 H5Z_FILTER_SCALEOFFSET , H5Z_FILTER_SHUFFLE , H5Z_FILTER_SZIP , H5Z_FLAG_OPTIONAL ,
1313 H5Z_SO_FLOAT_DSCALE , H5Z_SO_INT , H5_SZIP_EC_OPTION_MASK , H5_SZIP_MAX_PIXELS_PER_BLOCK ,
1414 H5_SZIP_NN_OPTION_MASK ,
1515} ;
1616
17+ pub use hdf5_sys:: h5z:: H5Z_filter_t ;
18+
1719use crate :: internal_prelude:: * ;
1820
1921#[ cfg( feature = "blosc" ) ]
@@ -121,19 +123,26 @@ pub struct FilterInfo {
121123pub ( crate ) fn register_filters ( ) {
122124 #[ cfg( feature = "lzf" ) ]
123125 if let Err ( e) = lzf:: register_lzf ( ) {
124- eprintln ! ( "{}" , e) ;
126+ eprintln ! ( "Error while registering LZF filter: {}" , e) ;
125127 }
126128 #[ cfg( feature = "blosc" ) ]
127129 if let Err ( e) = blosc:: register_blosc ( ) {
128- eprintln ! ( "{}" , e) ;
130+ eprintln ! ( "Error while registering Blosc filter: {}" , e) ;
129131 }
130132}
131133
132- /// Returns `true` if gzip filter is available.
133- pub fn gzip_available ( ) -> bool {
134+ /// Returns `true` if deflate filter is available.
135+ pub fn deflate_available ( ) -> bool {
134136 h5lock ! ( H5Zfilter_avail ( H5Z_FILTER_DEFLATE ) == 1 )
135137}
136138
139+ /// Returns `true` if deflate filter is available.
140+ #[ doc( hidden) ]
141+ #[ deprecated( note = "deprecated; use deflate_available()" ) ]
142+ pub fn gzip_available ( ) -> bool {
143+ deflate_available ( )
144+ }
145+
137146/// Returns `true` if szip filter is available.
138147pub fn szip_available ( ) -> bool {
139148 h5lock ! ( H5Zfilter_avail ( H5Z_FILTER_SZIP ) == 1 )
@@ -167,7 +176,7 @@ impl Filter {
167176 }
168177
169178 pub fn get_info ( filter_id : H5Z_filter_t ) -> FilterInfo {
170- if h5call ! ( H5Zfilter_avail ( filter_id) ) . map ( |x| x > 0 ) . unwrap_or_default ( ) {
179+ if ! h5call ! ( H5Zfilter_avail ( filter_id) ) . map ( |x| x > 0 ) . unwrap_or_default ( ) {
171180 return FilterInfo :: default ( ) ;
172181 }
173182 let mut flags: c_uint = 0 ;
@@ -281,28 +290,25 @@ impl Filter {
281290 }
282291
283292 fn parse_deflate ( cdata : & [ c_uint ] ) -> Result < Self > {
284- ensure ! ( cdata. len ( ) == 1 , "expected length 1 cdata for deflate filter" ) ;
293+ ensure ! ( ! cdata. is_empty ( ) , "expected cdata.len() >= 1 for deflate filter" ) ;
285294 ensure ! ( cdata[ 0 ] <= 9 , "invalid deflate level: {}" , cdata[ 0 ] ) ;
286295 Ok ( Self :: deflate ( cdata[ 0 ] as _ ) )
287296 }
288297
289- fn parse_shuffle ( cdata : & [ c_uint ] ) -> Result < Self > {
290- ensure ! ( cdata. is_empty( ) , "expected length 0 cdata for shuffle filter" ) ;
298+ fn parse_shuffle ( _cdata : & [ c_uint ] ) -> Result < Self > {
291299 Ok ( Self :: shuffle ( ) )
292300 }
293301
294- fn parse_fletcher32 ( cdata : & [ c_uint ] ) -> Result < Self > {
295- ensure ! ( cdata. is_empty( ) , "expected length 0 cdata for fletcher32 filter" ) ;
302+ fn parse_fletcher32 ( _cdata : & [ c_uint ] ) -> Result < Self > {
296303 Ok ( Self :: fletcher32 ( ) )
297304 }
298305
299- fn parse_nbit ( cdata : & [ c_uint ] ) -> Result < Self > {
300- ensure ! ( cdata. is_empty( ) , "expected length 0 cdata for nbit filter" ) ;
306+ fn parse_nbit ( _cdata : & [ c_uint ] ) -> Result < Self > {
301307 Ok ( Self :: nbit ( ) )
302308 }
303309
304310 fn parse_szip ( cdata : & [ c_uint ] ) -> Result < Self > {
305- ensure ! ( cdata. len( ) == 2 , "expected length 2 cdata for szip filter" ) ;
311+ ensure ! ( cdata. len( ) >= 2 , "expected cdata.len() >= 2 for szip filter" ) ;
306312 let m = cdata[ 0 ] ;
307313 ensure ! (
308314 ( m & H5_SZIP_EC_OPTION_MASK != 0 ) != ( m & H5_SZIP_NN_OPTION_MASK != 0 ) ,
@@ -321,7 +327,7 @@ impl Filter {
321327 }
322328
323329 fn parse_scaleoffset ( cdata : & [ c_uint ] ) -> Result < Self > {
324- ensure ! ( cdata. len( ) == 2 , "expected length 2 cdata for scaleoffset filter" ) ;
330+ ensure ! ( cdata. len( ) >= 2 , "expected cdata.len() >= 2 for scaleoffset filter" ) ;
325331 let scale_type = cdata[ 0 ] ;
326332 let mode = if scale_type == ( H5Z_SO_INT as c_uint ) {
327333 ensure ! (
@@ -344,8 +350,7 @@ impl Filter {
344350 }
345351
346352 #[ cfg( feature = "lzf" ) ]
347- fn parse_lzf ( cdata : & [ c_uint ] ) -> Result < Self > {
348- ensure ! ( cdata. is_empty( ) , "expected length 0 cdata for lzf filter" ) ;
353+ fn parse_lzf ( _cdata : & [ c_uint ] ) -> Result < Self > {
349354 Ok ( Self :: lzf ( ) )
350355 }
351356
@@ -506,9 +511,7 @@ impl Filter {
506511 ptr:: null_mut( ) ,
507512 ) ) ;
508513 let cdata = & cd_values[ ..( cd_nelmts as _) ] ;
509- let flt = Self :: from_raw( filter_id, cdata)
510- . ok( )
511- . unwrap_or_else( || Self :: user( filter_id, cdata) ) ;
514+ let flt = Self :: from_raw( filter_id, cdata) ?;
512515 filters. push( flt) ;
513516 }
514517 Ok ( filters)
@@ -523,6 +526,8 @@ pub(crate) fn validate_filters(filters: &[Filter], type_class: H5T_class_t) -> R
523526 let mut comp_filter: Option < & Filter > = None ;
524527
525528 for filter in filters {
529+ ensure ! ( filter. is_available( ) , "Filter not available: {:?}" , filter) ;
530+
526531 let id = filter. id ( ) ;
527532
528533 if let Some ( f) = map. get ( & id) {
@@ -563,3 +568,91 @@ pub(crate) fn validate_filters(filters: &[Filter], type_class: H5T_class_t) -> R
563568
564569 Ok ( ( ) )
565570}
571+
572+ #[ cfg( test) ]
573+ mod tests {
574+ use hdf5_sys:: h5t:: H5T_class_t ;
575+
576+ use super :: {
577+ blosc_available, deflate_available, lzf_available, szip_available, validate_filters,
578+ Filter , FilterInfo , SZip , ScaleOffset ,
579+ } ;
580+ use crate :: test:: with_tmp_file;
581+ use crate :: { plist:: DatasetCreate , Result } ;
582+
583+ #[ test]
584+ fn test_filter_pipeline ( ) -> Result < ( ) > {
585+ let mut comp_filters = vec ! [ ] ;
586+ if deflate_available ( ) {
587+ comp_filters. push ( Filter :: deflate ( 3 ) ) ;
588+ }
589+ if szip_available ( ) {
590+ comp_filters. push ( Filter :: szip ( SZip :: Entropy , 8 ) ) ;
591+ }
592+ assert_eq ! ( cfg!( feature = "lzf" ) , lzf_available( ) ) ;
593+ #[ cfg( feature = "lzf" ) ]
594+ {
595+ comp_filters. push ( Filter :: lzf ( ) ) ;
596+ }
597+ assert_eq ! ( cfg!( feature = "blosc" ) , blosc_available( ) ) ;
598+ #[ cfg( feature = "blosc" ) ]
599+ {
600+ use super :: BloscShuffle ;
601+ comp_filters. push ( Filter :: blosc_blosclz ( 1 , false ) ) ;
602+ comp_filters. push ( Filter :: blosc_lz4 ( 3 , true ) ) ;
603+ comp_filters. push ( Filter :: blosc_lz4hc ( 5 , BloscShuffle :: Bit ) ) ;
604+ comp_filters. push ( Filter :: blosc_zlib ( 7 , BloscShuffle :: None ) ) ;
605+ comp_filters. push ( Filter :: blosc_zstd ( 9 , BloscShuffle :: Byte ) ) ;
606+ comp_filters. push ( Filter :: blosc_snappy ( 0 , BloscShuffle :: Bit ) ) ;
607+ }
608+ for c in & comp_filters {
609+ assert ! ( c. is_available( ) ) ;
610+ assert ! ( c. encode_enabled( ) ) ;
611+ assert ! ( c. decode_enabled( ) ) ;
612+
613+ let pipeline = vec ! [
614+ Filter :: nbit( ) ,
615+ Filter :: shuffle( ) ,
616+ c. clone( ) ,
617+ Filter :: fletcher32( ) ,
618+ Filter :: scale_offset( ScaleOffset :: Integer ( 3 ) ) ,
619+ ] ;
620+ validate_filters ( & pipeline, H5T_class_t :: H5T_INTEGER ) ?;
621+
622+ let plist = DatasetCreate :: try_new ( ) ?;
623+ for flt in & pipeline {
624+ flt. apply_to_plist ( plist. id ( ) ) ?;
625+ }
626+ assert_eq ! ( Filter :: extract_pipeline( plist. id( ) ) ?, pipeline) ;
627+
628+ let mut b = DatasetCreate :: build ( ) ;
629+ b. set_filters ( & pipeline) ;
630+ let plist = b. finish ( ) ?;
631+ assert_eq ! ( Filter :: extract_pipeline( plist. id( ) ) ?, pipeline) ;
632+
633+ let res = with_tmp_file ( |file| {
634+ file. new_dataset_builder ( )
635+ . empty :: < i32 > ( )
636+ . shape ( ( 10_000 , 20 ) )
637+ . with_dcpl ( |p| p. set_filters ( & pipeline) )
638+ . create ( "foo" )
639+ . unwrap ( ) ;
640+ let plist = file. dataset ( "foo" ) . unwrap ( ) . dcpl ( ) . unwrap ( ) ;
641+ Filter :: extract_pipeline ( plist. id ( ) ) . unwrap ( )
642+ } ) ;
643+ assert_eq ! ( res, pipeline) ;
644+ }
645+
646+ let bad_filter = Filter :: user ( 12_345 , & [ 1 , 2 , 3 , 4 , 5 ] ) ;
647+ assert_eq ! ( Filter :: get_info( bad_filter. id( ) ) , FilterInfo :: default ( ) ) ;
648+ assert ! ( !bad_filter. is_available( ) ) ;
649+ assert ! ( !bad_filter. encode_enabled( ) ) ;
650+ assert ! ( !bad_filter. decode_enabled( ) ) ;
651+ assert_err ! (
652+ validate_filters( & [ bad_filter] , H5T_class_t :: H5T_INTEGER ) ,
653+ "Filter not available"
654+ ) ;
655+
656+ Ok ( ( ) )
657+ }
658+ }
0 commit comments