@@ -6,6 +6,8 @@ use strum_macros::Display;
66use url:: Url ;
77use validator:: { Validate , ValidationError } ;
88
9+ use crate :: types:: { DValue , Missing } ;
10+
911/// Supported numerical data types
1012#[ derive( Clone , Copy , Debug , Deserialize , Display , PartialEq ) ]
1113#[ serde( rename_all = "lowercase" ) ]
@@ -14,11 +16,11 @@ pub enum DType {
1416 Int32 ,
1517 /// [i64]
1618 Int64 ,
17- /// [u64 ]
19+ /// [u32 ]
1820 Uint32 ,
1921 /// [u64]
2022 Uint64 ,
21- /// [f64 ]
23+ /// [f32 ]
2224 Float32 ,
2325 /// [f64]
2426 Float64 ,
@@ -142,6 +144,8 @@ pub struct RequestData {
142144 pub compression : Option < Compression > ,
143145 /// List of filter algorithms
144146 pub filters : Option < Vec < Filter > > ,
147+ /// Missing data
148+ pub missing : Option < Missing < DValue > > ,
145149}
146150
147151/// Validate an array shape
@@ -230,6 +234,9 @@ fn validate_request_data(request_data: &RequestData) -> Result<(), ValidationErr
230234 }
231235 _ => ( ) ,
232236 } ;
237+ if let Some ( missing) = & request_data. missing {
238+ missing. validate ( request_data. dtype ) ?;
239+ } ;
233240 Ok ( ( ) )
234241}
235242
@@ -359,6 +366,11 @@ mod tests {
359366 Token :: U32 ( 4 ) ,
360367 Token :: MapEnd ,
361368 Token :: SeqEnd ,
369+ Token :: Str ( "missing" ) ,
370+ Token :: Some ,
371+ Token :: Enum { name : "Missing" } ,
372+ Token :: Str ( "missing_value" ) ,
373+ Token :: I32 ( 42 ) ,
362374 Token :: StructEnd ,
363375 ] ,
364376 ) ;
@@ -664,14 +676,40 @@ mod tests {
664676 )
665677 }
666678
679+ #[ test]
680+ fn test_invalid_missing ( ) {
681+ assert_de_tokens_error :: < RequestData > (
682+ & [
683+ Token :: Struct {
684+ name : "RequestData" ,
685+ len : 2 ,
686+ } ,
687+ Token :: Str ( "missing" ) ,
688+ Token :: Some ,
689+ Token :: Enum { name : "Missing" } ,
690+ Token :: Str ( "foo" ) ,
691+ Token :: StructEnd
692+ ] ,
693+ "unknown variant `foo`, expected one of `missing_value`, `missing_values`, `valid_min`, `valid_max`, `valid_range`" ,
694+ )
695+ }
696+
697+ #[ test]
698+ #[ should_panic( expected = "Incompatible value 9223372036854775807 for missing" ) ]
699+ fn test_missing_invalid_value_for_dtype ( ) {
700+ let mut request_data = test_utils:: get_test_request_data ( ) ;
701+ request_data. missing = Some ( Missing :: MissingValue ( i64:: max_value ( ) . into ( ) ) ) ;
702+ request_data. validate ( ) . unwrap ( )
703+ }
704+
667705 #[ test]
668706 fn test_unknown_field ( ) {
669707 assert_de_tokens_error :: < RequestData > ( & [
670708 Token :: Struct { name : "RequestData" , len : 2 } ,
671709 Token :: Str ( "foo" ) ,
672710 Token :: StructEnd
673711 ] ,
674- "unknown field `foo`, expected one of `source`, `bucket`, `object`, `dtype`, `offset`, `size`, `shape`, `order`, `selection`, `compression`, `filters`"
712+ "unknown field `foo`, expected one of `source`, `bucket`, `object`, `dtype`, `offset`, `size`, `shape`, `order`, `selection`, `compression`, `filters`, `missing` "
675713 )
676714 }
677715
@@ -686,8 +724,82 @@ mod tests {
686724
687725 #[ test]
688726 fn test_json_optional_fields ( ) {
689- let json = r#"{"source": "http://example.com", "bucket": "bar", "object": "baz", "dtype": "int32", "offset": 4, "size": 8, "shape": [2, 5], "order": "C", "selection": [[1, 2, 3], [4, 5, 6]], "compression": {"id": "gzip"}, "filters": [{"id": "shuffle", "element_size": 4}]}"# ;
727+ let json = r#"{
728+ "source": "http://example.com",
729+ "bucket": "bar",
730+ "object": "baz",
731+ "dtype": "int32",
732+ "offset": 4,
733+ "size": 8,
734+ "shape": [2, 5],
735+ "order": "C",
736+ "selection": [[1, 2, 3], [4, 5, 6]],
737+ "compression": {"id": "gzip"},
738+ "filters": [{"id": "shuffle", "element_size": 4}],
739+ "missing": {"missing_value": 42}
740+ }"# ;
690741 let request_data = serde_json:: from_str :: < RequestData > ( json) . unwrap ( ) ;
691742 assert_eq ! ( request_data, test_utils:: get_test_request_data_optional( ) ) ;
692743 }
744+
745+ #[ test]
746+ fn test_json_optional_fields2 ( ) {
747+ let json = r#"{
748+ "source": "http://example.com",
749+ "bucket": "bar",
750+ "object": "baz",
751+ "dtype": "float64",
752+ "offset": 4,
753+ "size": 8,
754+ "shape": [2, 5, 10],
755+ "order": "F",
756+ "selection": [[1, 2, 3], [4, 5, 6], [7, 8, 9]],
757+ "compression": {"id": "zlib"},
758+ "filters": [{"id": "shuffle", "element_size": 8}],
759+ "missing": {"valid_range": [-1.0, 999.0]}
760+ }"# ;
761+ let request_data = serde_json:: from_str :: < RequestData > ( json) . unwrap ( ) ;
762+ let mut expected = test_utils:: get_test_request_data_optional ( ) ;
763+ expected. dtype = DType :: Float64 ;
764+ expected. shape = Some ( vec ! [ 2 , 5 , 10 ] ) ;
765+ expected. order = Some ( Order :: F ) ;
766+ expected. selection = Some ( vec ! [
767+ Slice :: new( 1 , 2 , 3 ) ,
768+ Slice :: new( 4 , 5 , 6 ) ,
769+ Slice :: new( 7 , 8 , 9 ) ,
770+ ] ) ;
771+ expected. compression = Some ( Compression :: Zlib ) ;
772+ expected. filters = Some ( vec ! [ Filter :: Shuffle { element_size: 8 } ] ) ;
773+ expected. missing = Some ( Missing :: ValidRange (
774+ DValue :: from_f64 ( -1.0 ) . unwrap ( ) ,
775+ DValue :: from_f64 ( 999.0 ) . unwrap ( ) ,
776+ ) ) ;
777+ assert_eq ! ( request_data, expected) ;
778+ }
779+
780+ #[ test]
781+ fn test_json_optional_fields3 ( ) {
782+ let json = format ! (
783+ r#"{{
784+ "source": "http://example.com",
785+ "bucket": "bar",
786+ "object": "baz",
787+ "dtype": "int32",
788+ "missing": {{"missing_values": [{}, -1, 0, 1, {}]}}
789+ }}"# ,
790+ i64 :: min_value( ) ,
791+ u64 :: max_value( )
792+ ) ;
793+ let request_data = serde_json:: from_str :: < RequestData > ( & json) . unwrap ( ) ;
794+ let mut expected = test_utils:: get_test_request_data ( ) ;
795+ expected. dtype = DType :: Int32 ;
796+ expected. missing = Some ( Missing :: MissingValues ( vec ! [
797+ i64 :: min_value( ) . into( ) ,
798+ ( -1 ) . into( ) ,
799+ 0 . into( ) ,
800+ 1 . into( ) ,
801+ u64 :: max_value( ) . into( ) ,
802+ ] ) ) ;
803+ assert_eq ! ( request_data, expected) ;
804+ }
693805}
0 commit comments