@@ -67,6 +67,9 @@ pub enum Error {
6767 /// JSON has a comma after the last value in an array or map.
6868 TrailingComma ,
6969
70+ /// Error with a custom message that we had to discard.
71+ CustomError ,
72+
7073 #[ doc( hidden) ]
7174 __Extensible,
7275}
@@ -303,6 +306,7 @@ macro_rules! deserialize_fromstr {
303306impl < ' a , ' de > de:: Deserializer < ' de > for & ' a mut Deserializer < ' de > {
304307 type Error = Error ;
305308
309+ /// Unsupported. Can’t parse a value without knowing its expected type.
306310 fn deserialize_any < V > ( self , _visitor : V ) -> Result < V :: Value >
307311 where
308312 V : Visitor < ' de > ,
@@ -425,20 +429,23 @@ impl<'a, 'de> de::Deserializer<'de> for &'a mut Deserializer<'de> {
425429 }
426430 }
427431
432+ /// Unsupported. String is not available in no-std.
428433 fn deserialize_string < V > ( self , _visitor : V ) -> Result < V :: Value >
429434 where
430435 V : Visitor < ' de > ,
431436 {
432437 unreachable ! ( )
433438 }
434439
440+ /// Unsupported
435441 fn deserialize_bytes < V > ( self , _visitor : V ) -> Result < V :: Value >
436442 where
437443 V : Visitor < ' de > ,
438444 {
439445 unreachable ! ( )
440446 }
441447
448+ /// Unsupported
442449 fn deserialize_byte_buf < V > ( self , _visitor : V ) -> Result < V :: Value >
443450 where
444451 V : Visitor < ' de > ,
@@ -460,20 +467,23 @@ impl<'a, 'de> de::Deserializer<'de> for &'a mut Deserializer<'de> {
460467 }
461468 }
462469
470+ /// Unsupported. Use a more specific deserialize_* method
463471 fn deserialize_unit < V > ( self , _visitor : V ) -> Result < V :: Value >
464472 where
465473 V : Visitor < ' de > ,
466474 {
467475 unreachable ! ( )
468476 }
469477
478+ /// Unsupported. Use a more specific deserialize_* method
470479 fn deserialize_unit_struct < V > ( self , _name : & ' static str , _visitor : V ) -> Result < V :: Value >
471480 where
472481 V : Visitor < ' de > ,
473482 {
474483 unreachable ! ( )
475484 }
476485
486+ /// Unsupported. We can’t parse newtypes because we don’t know the underlying type.
477487 fn deserialize_newtype_struct < V > ( self , _name : & ' static str , _visitor : V ) -> Result < V :: Value >
478488 where
479489 V : Visitor < ' de > ,
@@ -509,14 +519,17 @@ impl<'a, 'de> de::Deserializer<'de> for &'a mut Deserializer<'de> {
509519 self ,
510520 _name : & ' static str ,
511521 _len : usize ,
512- _visitor : V ,
522+ visitor : V ,
513523 ) -> Result < V :: Value >
514524 where
515525 V : Visitor < ' de > ,
516526 {
517- unreachable ! ( )
527+ self . deserialize_seq ( visitor )
518528 }
519529
530+ /// Unsupported. Can’t make an arbitrary-sized map in no-std. Use a struct with a
531+ /// known format, or implement a custom map deserializer / visitor:
532+ /// https://serde.rs/deserialize-map.html
520533 fn deserialize_map < V > ( self , _visitor : V ) -> Result < V :: Value >
521534 where
522535 V : Visitor < ' de > ,
@@ -570,20 +583,45 @@ impl<'a, 'de> de::Deserializer<'de> for &'a mut Deserializer<'de> {
570583 self . deserialize_str ( visitor)
571584 }
572585
573- fn deserialize_ignored_any < V > ( self , _visitor : V ) -> Result < V :: Value >
586+ /// Used to throw out fields from JSON objects that we don’t want to
587+ /// keep in our structs.
588+ fn deserialize_ignored_any < V > ( self , visitor : V ) -> Result < V :: Value >
574589 where
575590 V : Visitor < ' de > ,
576591 {
577- unreachable ! ( )
592+ match self . parse_whitespace ( ) . ok_or ( Error :: EofWhileParsingValue ) ? {
593+ b'"' => self . deserialize_str ( visitor) ,
594+ b'[' => self . deserialize_seq ( visitor) ,
595+ b'{' => self . deserialize_struct ( "ignored" , & [ ] , visitor) ,
596+ b',' | b'}' | b']' => Err ( Error :: ExpectedSomeValue ) ,
597+ // If it’s something else then we chomp until we get to an end delimiter.
598+ // This does technically allow for illegal JSON since we’re just ignoring
599+ // characters rather than parsing them.
600+ _ => loop {
601+ match self . peek ( ) {
602+ // The visitor is expected to be UnknownAny’s visitor, which
603+ // implements visit_unit to return its unit Ok result.
604+ Some ( b',' ) | Some ( b'}' ) | Some ( b']' ) => break visitor. visit_unit ( ) ,
605+ Some ( _) => self . eat_char ( ) ,
606+ None => break Err ( Error :: EofWhileParsingString ) ,
607+ }
608+ } ,
609+ }
578610 }
579611}
580612
581613impl de:: Error for Error {
614+ // We can’t alloc a String to save the msg in, so we have this less-than-useful
615+ // error as better than panicking with unreachable!. These errors can arise from
616+ // derive, such as "not enough elements in a tuple" and "missing required field".
617+ //
618+ // TODO: consider using a heapless::String to save the first n characters of this
619+ // message.
582620 fn custom < T > ( _msg : T ) -> Self
583621 where
584622 T : fmt:: Display ,
585623 {
586- unreachable ! ( )
624+ Error :: CustomError
587625 }
588626}
589627
@@ -623,6 +661,7 @@ impl fmt::Display for Error {
623661 value."
624662 }
625663 Error :: TrailingComma => "JSON has a comma after the last value in an array or map." ,
664+ Error :: CustomError => "JSON does not match deserializer’s expected format." ,
626665 _ => "Invalid JSON" ,
627666 }
628667 )
@@ -830,6 +869,69 @@ mod tests {
830869 assert ! ( crate :: from_str:: <Temperature >( r#"{ "temperature": -1 }"# ) . is_err( ) ) ;
831870 }
832871
872+ #[ test]
873+ fn struct_tuple ( ) {
874+ #[ derive( Debug , Deserialize , PartialEq ) ]
875+ struct Xy ( i8 , i8 ) ;
876+
877+ assert_eq ! ( crate :: from_str( r#"[10, 20]"# ) , Ok ( Xy ( 10 , 20 ) ) ) ;
878+ assert_eq ! ( crate :: from_str( r#"[10, -20]"# ) , Ok ( Xy ( 10 , -20 ) ) ) ;
879+
880+ // wrong number of args
881+ assert_eq ! ( crate :: from_str:: <Xy >( r#"[10]"# ) , Err ( crate :: de:: Error :: CustomError ) ) ;
882+ assert_eq ! ( crate :: from_str:: <Xy >( r#"[10, 20, 30]"# ) , Err ( crate :: de:: Error :: TrailingCharacters ) ) ;
883+ }
884+
885+ #[ test]
886+ fn ignoring_extra_fields ( ) {
887+ #[ derive( Debug , Deserialize , PartialEq ) ]
888+ struct Temperature {
889+ temperature : u8 ,
890+ }
891+
892+ assert_eq ! (
893+ crate :: from_str( r#"{ "temperature": 20, "high": 80, "low": -10, "updated": true }"# ) ,
894+ Ok ( Temperature { temperature: 20 } )
895+ ) ;
896+
897+ assert_eq ! (
898+ crate :: from_str(
899+ r#"{ "temperature": 20, "conditions": "windy", "forecast": "cloudy" }"#
900+ ) ,
901+ Ok ( Temperature { temperature: 20 } )
902+ ) ;
903+
904+ assert_eq ! (
905+ crate :: from_str( r#"{ "temperature": 20, "hourly_conditions": ["windy", "rainy"] }"# ) ,
906+ Ok ( Temperature { temperature: 20 } )
907+ ) ;
908+
909+ assert_eq ! (
910+ crate :: from_str( r#"{ "temperature": 20, "source": { "station": "dock", "sensors": ["front", "back"] } }"# ) ,
911+ Ok ( Temperature { temperature: 20 } )
912+ ) ;
913+
914+ assert_eq ! (
915+ crate :: from_str( r#"{ "temperature": 20, "invalid": this-is-ignored }"# ) ,
916+ Ok ( Temperature { temperature: 20 } )
917+ ) ;
918+
919+ assert_eq ! (
920+ crate :: from_str:: <Temperature >( r#"{ "temperature": 20, "broken": }"# ) ,
921+ Err ( crate :: de:: Error :: ExpectedSomeValue )
922+ ) ;
923+
924+ assert_eq ! (
925+ crate :: from_str:: <Temperature >( r#"{ "temperature": 20, "broken": [ }"# ) ,
926+ Err ( crate :: de:: Error :: ExpectedSomeValue )
927+ ) ;
928+
929+ assert_eq ! (
930+ crate :: from_str:: <Temperature >( r#"{ "temperature": 20, "broken": ] }"# ) ,
931+ Err ( crate :: de:: Error :: ExpectedSomeValue )
932+ ) ;
933+ }
934+
833935 // See https://iot.mozilla.org/wot/#thing-resource
834936 #[ test]
835937 #[ ignore]
0 commit comments