@@ -70,6 +70,10 @@ pub enum Error {
7070 /// Error with a custom message that we had to discard.
7171 CustomError ,
7272
73+ /// Error with a custom message that was preserved.
74+ #[ cfg( feature = "custom-error-messages" ) ]
75+ CustomErrorWithMessage ( heapless:: String < heapless:: consts:: U64 > ) ,
76+
7377 #[ doc( hidden) ]
7478 __Extensible,
7579}
@@ -608,17 +612,23 @@ impl<'a, 'de> de::Deserializer<'de> for &'a mut Deserializer<'de> {
608612}
609613
610614impl de:: Error for Error {
611- // We can’t alloc a String to save the msg in, so we have this less-than-useful
612- // error as better than panicking with unreachable!. These errors can arise from
613- // derive, such as "not enough elements in a tuple" and "missing required field".
614- //
615- // TODO: consider using a heapless::String to save the first n characters of this
616- // message.
617- fn custom < T > ( _msg : T ) -> Self
615+ #[ cfg_attr( not( feature = "custom-error-messages" ) , allow( unused_variables) ) ]
616+ fn custom < T > ( msg : T ) -> Self
618617 where
619618 T : fmt:: Display ,
620619 {
621- Error :: CustomError
620+ #[ cfg( not( feature = "custom-error-messages" ) ) ]
621+ {
622+ Error :: CustomError
623+ }
624+ #[ cfg( feature = "custom-error-messages" ) ]
625+ {
626+ use core:: fmt:: Write ;
627+
628+ let mut string = heapless:: String :: new ( ) ;
629+ write ! ( string, "{:.64}" , msg) . unwrap ( ) ;
630+ Error :: CustomErrorWithMessage ( string)
631+ }
622632 }
623633}
624634
@@ -659,6 +669,8 @@ impl fmt::Display for Error {
659669 }
660670 Error :: TrailingComma => "JSON has a comma after the last value in an array or map." ,
661671 Error :: CustomError => "JSON does not match deserializer’s expected format." ,
672+ #[ cfg( feature = "custom-error-messages" ) ]
673+ Error :: CustomErrorWithMessage ( msg) => msg. as_str( ) ,
662674 _ => "Invalid JSON" ,
663675 }
664676 )
@@ -867,6 +879,7 @@ mod tests {
867879 }
868880
869881 #[ test]
882+ #[ cfg( not( feature = "custom-error-messages" ) ) ]
870883 fn struct_tuple ( ) {
871884 #[ derive( Debug , Deserialize , PartialEq ) ]
872885 struct Xy ( i8 , i8 ) ;
@@ -885,6 +898,28 @@ mod tests {
885898 ) ;
886899 }
887900
901+ #[ test]
902+ #[ cfg( feature = "custom-error-messages" ) ]
903+ fn struct_tuple ( ) {
904+ #[ derive( Debug , Deserialize , PartialEq ) ]
905+ struct Xy ( i8 , i8 ) ;
906+
907+ assert_eq ! ( crate :: from_str( r#"[10, 20]"# ) , Ok ( Xy ( 10 , 20 ) ) ) ;
908+ assert_eq ! ( crate :: from_str( r#"[10, -20]"# ) , Ok ( Xy ( 10 , -20 ) ) ) ;
909+
910+ // wrong number of args
911+ assert_eq ! (
912+ crate :: from_str:: <Xy >( r#"[10]"# ) ,
913+ Err ( crate :: de:: Error :: CustomErrorWithMessage (
914+ "invalid length 1, expected tuple struct Xy with 2 elements" . into( )
915+ ) )
916+ ) ;
917+ assert_eq ! (
918+ crate :: from_str:: <Xy >( r#"[10, 20, 30]"# ) ,
919+ Err ( crate :: de:: Error :: TrailingCharacters )
920+ ) ;
921+ }
922+
888923 #[ test]
889924 fn ignoring_extra_fields ( ) {
890925 #[ derive( Debug , Deserialize , PartialEq ) ]
@@ -937,6 +972,28 @@ mod tests {
937972 ) ;
938973 }
939974
975+ #[ test]
976+ #[ cfg( feature = "custom-error-messages" ) ]
977+ fn preserve_short_error_message ( ) {
978+ use serde:: de:: Error ;
979+ assert_eq ! (
980+ crate :: de:: Error :: custom( "something bad happened" ) ,
981+ crate :: de:: Error :: CustomErrorWithMessage ( "something bad happened" . into( ) )
982+ ) ;
983+ }
984+
985+ #[ test]
986+ #[ cfg( feature = "custom-error-messages" ) ]
987+ fn truncate_error_message ( ) {
988+ use serde:: de:: Error ;
989+ assert_eq ! (
990+ crate :: de:: Error :: custom( "0123456789012345678901234567890123456789012345678901234567890123 <- after here the message should be truncated" ) ,
991+ crate :: de:: Error :: CustomErrorWithMessage (
992+ "0123456789012345678901234567890123456789012345678901234567890123" . into( )
993+ )
994+ ) ;
995+ }
996+
940997 // See https://iot.mozilla.org/wot/#thing-resource
941998 #[ test]
942999 #[ ignore]
0 commit comments