@@ -37,6 +37,122 @@ fn check_scalar_types() {
3737 check_message ( & ScalarTypes :: default ( ) ) ;
3838}
3939
40+ /// A message with implicit presence floating point fields.
41+ #[ derive( Clone , PartialEq , Message ) ]
42+ pub struct Zeroes {
43+ #[ prost( float, tag = "1" ) ]
44+ pub float : f32 ,
45+ #[ prost( double, tag = "2" ) ]
46+ pub double : f64 ,
47+ }
48+
49+ /// `-0.0` differs from the default `0.0` and therefore has to be encoded, otherwise the sign bit
50+ /// is silently lost. See <https://github.com/tokio-rs/prost/issues/1177>.
51+ #[ test]
52+ fn check_negative_zero_is_encoded ( ) {
53+ const FLOAT : & [ u8 ] = & [ 0x0d , 0x00 , 0x00 , 0x00 , 0x80 ] ;
54+ const DOUBLE : & [ u8 ] = & [ 0x11 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x80 ] ;
55+ let both = [ FLOAT , DOUBLE ] . concat ( ) ;
56+
57+ let msg = Zeroes {
58+ float : -0.0 ,
59+ double : -0.0 ,
60+ } ;
61+ assert_eq ! ( msg. encoded_len( ) , both. len( ) ) ;
62+ assert_eq ! ( msg. encode_to_vec( ) , both) ;
63+
64+ // Decoding preserves the sign, and re-encoding reproduces the original bytes.
65+ let decoded = Zeroes :: decode ( both. as_slice ( ) ) . unwrap ( ) ;
66+ assert_eq ! ( decoded. float. to_bits( ) , ( -0.0f32 ) . to_bits( ) ) ;
67+ assert_eq ! ( decoded. double. to_bits( ) , ( -0.0f64 ) . to_bits( ) ) ;
68+ assert_eq ! ( decoded. encoded_len( ) , both. len( ) ) ;
69+ assert_eq ! ( decoded. encode_to_vec( ) , both) ;
70+
71+ // An absent field still decodes to a positive zero which is not re-encoded.
72+ let decoded = Zeroes :: decode ( FLOAT ) . unwrap ( ) ;
73+ assert_eq ! ( decoded. float. to_bits( ) , ( -0.0f32 ) . to_bits( ) ) ;
74+ assert_eq ! ( decoded. double. to_bits( ) , ( 0.0f64 ) . to_bits( ) ) ;
75+ assert_eq ! ( decoded. encoded_len( ) , FLOAT . len( ) ) ;
76+ assert_eq ! ( decoded. encode_to_vec( ) , FLOAT ) ;
77+ }
78+
79+ /// `0.0` is the default value and must not be encoded.
80+ #[ test]
81+ fn check_positive_zero_is_not_encoded ( ) {
82+ let msg = Zeroes {
83+ float : 0.0 ,
84+ double : 0.0 ,
85+ } ;
86+ assert_eq ! ( msg. encoded_len( ) , 0 ) ;
87+ assert_eq ! ( msg. encode_to_vec( ) , [ ] ) ;
88+ }
89+
90+ /// `google.protobuf.FloatValue` and `google.protobuf.DoubleValue` have hand written `Message`
91+ /// implementations which need the same treatment.
92+ #[ test]
93+ fn check_negative_zero_wrapper_types ( ) {
94+ let float = [ 0x0d , 0x00 , 0x00 , 0x00 , 0x80 ] ;
95+ assert_eq ! ( ( -0.0f32 ) . encoded_len( ) , float. len( ) ) ;
96+ assert_eq ! ( ( -0.0f32 ) . encode_to_vec( ) , float) ;
97+ assert_eq ! (
98+ f32 :: decode( float. as_slice( ) ) . unwrap( ) . to_bits( ) ,
99+ ( -0.0f32 ) . to_bits( )
100+ ) ;
101+ assert_eq ! ( ( 0.0f32 ) . encoded_len( ) , 0 ) ;
102+ assert_eq ! ( ( 0.0f32 ) . encode_to_vec( ) , [ ] ) ;
103+
104+ let double = [ 0x09 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x80 ] ;
105+ assert_eq ! ( ( -0.0f64 ) . encoded_len( ) , double. len( ) ) ;
106+ assert_eq ! ( ( -0.0f64 ) . encode_to_vec( ) , double) ;
107+ assert_eq ! (
108+ f64 :: decode( double. as_slice( ) ) . unwrap( ) . to_bits( ) ,
109+ ( -0.0f64 ) . to_bits( )
110+ ) ;
111+ assert_eq ! ( ( 0.0f64 ) . encoded_len( ) , 0 ) ;
112+ assert_eq ! ( ( 0.0f64 ) . encode_to_vec( ) , [ ] ) ;
113+ }
114+
115+ /// A message with implicit presence floating point fields with a custom default.
116+ #[ derive( Clone , PartialEq , Message ) ]
117+ pub struct FloatDefaults {
118+ #[ prost( float, tag = "1" , default = "-1.5" ) ]
119+ pub negative : f32 ,
120+ #[ prost( double, tag = "2" , default = "nan" ) ]
121+ pub nan : f64 ,
122+ }
123+
124+ /// Custom floating point defaults are compared by bit pattern too. Note that this makes a field
125+ /// which is equal to a `NaN` default no longer encoded, matching every other default value.
126+ #[ test]
127+ fn check_float_defaults ( ) {
128+ let default = FloatDefaults :: default ( ) ;
129+ assert_eq ! ( default . negative. to_bits( ) , ( -1.5f32 ) . to_bits( ) ) ;
130+ assert ! ( default . nan. is_nan( ) ) ;
131+ assert_eq ! ( default . encoded_len( ) , 0 ) ;
132+ assert_eq ! ( default . encode_to_vec( ) , [ ] ) ;
133+
134+ // Both zeroes differ from the negative default and are encoded.
135+ for ( value, expected) in [
136+ ( 0.0f32 , [ 0x0d , 0x00 , 0x00 , 0x00 , 0x00 ] ) ,
137+ ( -0.0f32 , [ 0x0d , 0x00 , 0x00 , 0x00 , 0x80 ] ) ,
138+ ] {
139+ let msg = FloatDefaults {
140+ negative : value,
141+ ..Default :: default ( )
142+ } ;
143+ assert_eq ! ( msg. encoded_len( ) , expected. len( ) ) ;
144+ assert_eq ! ( msg. encode_to_vec( ) , expected) ;
145+ }
146+
147+ let msg = FloatDefaults {
148+ nan : 0.0 ,
149+ ..Default :: default ( )
150+ } ;
151+ let expected = [ 0x11 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ] ;
152+ assert_eq ! ( msg. encoded_len( ) , expected. len( ) ) ;
153+ assert_eq ! ( msg. encode_to_vec( ) , expected) ;
154+ }
155+
40156/// A protobuf message which contains all scalar types.
41157#[ derive( Clone , PartialEq , Message ) ]
42158pub struct ScalarTypes {
0 commit comments