@@ -63,6 +63,9 @@ pub enum Error {
6363 /// JSON has a comma after the last value in an array or map.
6464 TrailingComma ,
6565
66+ /// Error with a custom message that we had to discard.
67+ CustomError ,
68+
6669 #[ doc( hidden) ]
6770 __Extensible,
6871}
@@ -276,6 +279,7 @@ macro_rules! deserialize_signed {
276279impl < ' a , ' de > de:: Deserializer < ' de > for & ' a mut Deserializer < ' de > {
277280 type Error = Error ;
278281
282+ /// Unsupported. Can’t parse a value without knowing its expected type.
279283 fn deserialize_any < V > ( self , _visitor : V ) -> Result < V :: Value >
280284 where
281285 V : Visitor < ' de > ,
@@ -396,20 +400,23 @@ impl<'a, 'de> de::Deserializer<'de> for &'a mut Deserializer<'de> {
396400 }
397401 }
398402
403+ /// Unsupported. String is not available in no-std.
399404 fn deserialize_string < V > ( self , _visitor : V ) -> Result < V :: Value >
400405 where
401406 V : Visitor < ' de > ,
402407 {
403408 unreachable ! ( )
404409 }
405410
411+ /// Unsupported
406412 fn deserialize_bytes < V > ( self , _visitor : V ) -> Result < V :: Value >
407413 where
408414 V : Visitor < ' de > ,
409415 {
410416 unreachable ! ( )
411417 }
412418
419+ /// Unsupported
413420 fn deserialize_byte_buf < V > ( self , _visitor : V ) -> Result < V :: Value >
414421 where
415422 V : Visitor < ' de > ,
@@ -431,20 +438,23 @@ impl<'a, 'de> de::Deserializer<'de> for &'a mut Deserializer<'de> {
431438 }
432439 }
433440
441+ /// Unsupported. Use a more specific deserialize_* method
434442 fn deserialize_unit < V > ( self , _visitor : V ) -> Result < V :: Value >
435443 where
436444 V : Visitor < ' de > ,
437445 {
438446 unreachable ! ( )
439447 }
440448
449+ /// Unsupported. Use a more specific deserialize_* method
441450 fn deserialize_unit_struct < V > ( self , _name : & ' static str , _visitor : V ) -> Result < V :: Value >
442451 where
443452 V : Visitor < ' de > ,
444453 {
445454 unreachable ! ( )
446455 }
447456
457+ /// Unsupported. We can’t parse newtypes because we don’t know the underlying type.
448458 fn deserialize_newtype_struct < V > ( self , _name : & ' static str , _visitor : V ) -> Result < V :: Value >
449459 where
450460 V : Visitor < ' de > ,
@@ -480,14 +490,17 @@ impl<'a, 'de> de::Deserializer<'de> for &'a mut Deserializer<'de> {
480490 self ,
481491 _name : & ' static str ,
482492 _len : usize ,
483- _visitor : V ,
493+ visitor : V ,
484494 ) -> Result < V :: Value >
485495 where
486496 V : Visitor < ' de > ,
487497 {
488- unreachable ! ( )
498+ self . deserialize_seq ( visitor )
489499 }
490500
501+ /// Unsupported. Can’t make an arbitrary-sized map in no-std. Use a struct with a
502+ /// known format, or implement a custom map deserializer / visitor:
503+ /// https://serde.rs/deserialize-map.html
491504 fn deserialize_map < V > ( self , _visitor : V ) -> Result < V :: Value >
492505 where
493506 V : Visitor < ' de > ,
@@ -541,20 +554,45 @@ impl<'a, 'de> de::Deserializer<'de> for &'a mut Deserializer<'de> {
541554 self . deserialize_str ( visitor)
542555 }
543556
544- fn deserialize_ignored_any < V > ( self , _visitor : V ) -> Result < V :: Value >
557+ /// Used to throw out fields from JSON objects that we don’t want to
558+ /// keep in our structs.
559+ fn deserialize_ignored_any < V > ( self , visitor : V ) -> Result < V :: Value >
545560 where
546561 V : Visitor < ' de > ,
547562 {
548- unreachable ! ( )
563+ match self . parse_whitespace ( ) . ok_or ( Error :: EofWhileParsingValue ) ? {
564+ b'"' => self . deserialize_str ( visitor) ,
565+ b'[' => self . deserialize_seq ( visitor) ,
566+ b'{' => self . deserialize_struct ( "ignored" , & [ ] , visitor) ,
567+ b',' | b'}' | b']' => Err ( Error :: ExpectedSomeValue ) ,
568+ // If it’s something else then we chomp until we get to an end delimiter.
569+ // This does technically allow for illegal JSON since we’re just ignoring
570+ // characters rather than parsing them.
571+ _ => loop {
572+ match self . peek ( ) {
573+ // The visitor is expected to be UnknownAny’s visitor, which
574+ // implements visit_unit to return its unit Ok result.
575+ Some ( b',' ) | Some ( b'}' ) | Some ( b']' ) => break visitor. visit_unit ( ) ,
576+ Some ( _) => self . eat_char ( ) ,
577+ None => break Err ( Error :: EofWhileParsingString ) ,
578+ }
579+ } ,
580+ }
549581 }
550582}
551583
552584impl de:: Error for Error {
585+ // We can’t alloc a String to save the msg in, so we have this less-than-useful
586+ // error as better than panicking with unreachable!. These errors can arise from
587+ // derive, such as "not enough elements in a tuple" and "missing required field".
588+ //
589+ // TODO: consider using a heapless::String to save the first n characters of this
590+ // message.
553591 fn custom < T > ( _msg : T ) -> Self
554592 where
555593 T : fmt:: Display ,
556594 {
557- unreachable ! ( )
595+ Error :: CustomError
558596 }
559597}
560598
@@ -594,6 +632,7 @@ impl fmt::Display for Error {
594632 value."
595633 }
596634 Error :: TrailingComma => "JSON has a comma after the last value in an array or map." ,
635+ Error :: CustomError => "JSON does not match deserializer’s expected format." ,
597636 _ => "Invalid JSON" ,
598637 }
599638 )
@@ -756,6 +795,69 @@ mod tests {
756795 assert ! ( crate :: from_str:: <Temperature >( r#"{ "temperature": -1 }"# ) . is_err( ) ) ;
757796 }
758797
798+ #[ test]
799+ fn struct_tuple ( ) {
800+ #[ derive( Debug , Deserialize , PartialEq ) ]
801+ struct Xy ( i8 , i8 ) ;
802+
803+ assert_eq ! ( crate :: from_str( r#"[10, 20]"# ) , Ok ( Xy ( 10 , 20 ) ) ) ;
804+ assert_eq ! ( crate :: from_str( r#"[10, -20]"# ) , Ok ( Xy ( 10 , -20 ) ) ) ;
805+
806+ // wrong number of args
807+ assert_eq ! ( crate :: from_str:: <Xy >( r#"[10]"# ) , Err ( crate :: de:: Error :: CustomError ) ) ;
808+ assert_eq ! ( crate :: from_str:: <Xy >( r#"[10, 20, 30]"# ) , Err ( crate :: de:: Error :: TrailingCharacters ) ) ;
809+ }
810+
811+ #[ test]
812+ fn ignoring_extra_fields ( ) {
813+ #[ derive( Debug , Deserialize , PartialEq ) ]
814+ struct Temperature {
815+ temperature : u8 ,
816+ }
817+
818+ assert_eq ! (
819+ crate :: from_str( r#"{ "temperature": 20, "high": 80, "low": -10, "updated": true }"# ) ,
820+ Ok ( Temperature { temperature: 20 } )
821+ ) ;
822+
823+ assert_eq ! (
824+ crate :: from_str(
825+ r#"{ "temperature": 20, "conditions": "windy", "forecast": "cloudy" }"#
826+ ) ,
827+ Ok ( Temperature { temperature: 20 } )
828+ ) ;
829+
830+ assert_eq ! (
831+ crate :: from_str( r#"{ "temperature": 20, "hourly_conditions": ["windy", "rainy"] }"# ) ,
832+ Ok ( Temperature { temperature: 20 } )
833+ ) ;
834+
835+ assert_eq ! (
836+ crate :: from_str( r#"{ "temperature": 20, "source": { "station": "dock", "sensors": ["front", "back"] } }"# ) ,
837+ Ok ( Temperature { temperature: 20 } )
838+ ) ;
839+
840+ assert_eq ! (
841+ crate :: from_str( r#"{ "temperature": 20, "invalid": this-is-ignored }"# ) ,
842+ Ok ( Temperature { temperature: 20 } )
843+ ) ;
844+
845+ assert_eq ! (
846+ crate :: from_str:: <Temperature >( r#"{ "temperature": 20, "broken": }"# ) ,
847+ Err ( crate :: de:: Error :: ExpectedSomeValue )
848+ ) ;
849+
850+ assert_eq ! (
851+ crate :: from_str:: <Temperature >( r#"{ "temperature": 20, "broken": [ }"# ) ,
852+ Err ( crate :: de:: Error :: ExpectedSomeValue )
853+ ) ;
854+
855+ assert_eq ! (
856+ crate :: from_str:: <Temperature >( r#"{ "temperature": 20, "broken": ] }"# ) ,
857+ Err ( crate :: de:: Error :: ExpectedSomeValue )
858+ ) ;
859+ }
860+
759861 // See https://iot.mozilla.org/wot/#thing-resource
760862 #[ test]
761863 #[ ignore]
0 commit comments