Skip to content

Commit 5277c14

Browse files
committed
AVRO-4024: [Rust] Sync the possible String default values for floating numbers with Java and C# (#3073)
* AVRO-4024: [Rust] Improve the error messages when parsing unknown String into Value::Float/Double Signed-off-by: Martin Tzvetanov Grigorov <mgrigorov@apache.org> * AVRO-4024: [Rust] Accept only "Nan", "INF", "-INF", "Infinity" and "-Infinity" This is what the Java SDK (via Jackson library) supports (#3066). This is what the C# SDK also would support (#3070) Signed-off-by: Martin Tzvetanov Grigorov <mgrigorov@apache.org> --------- Signed-off-by: Martin Tzvetanov Grigorov <mgrigorov@apache.org> (cherry picked from commit dffc13a)
1 parent adf5df5 commit 5277c14

3 files changed

Lines changed: 61 additions & 17 deletions

File tree

lang/rust/avro/src/error.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,10 +189,10 @@ pub enum Error {
189189
GetLong(ValueKind),
190190

191191
#[error("Double expected, got {0:?}")]
192-
GetDouble(ValueKind),
192+
GetDouble(Value),
193193

194194
#[error("Float expected, got {0:?}")]
195-
GetFloat(ValueKind),
195+
GetFloat(Value),
196196

197197
#[error("Bytes expected, got {0:?}")]
198198
GetBytes(ValueKind),

lang/rust/avro/src/types.rs

Lines changed: 48 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -908,11 +908,11 @@ impl Value {
908908
Value::Long(n) => Ok(Value::Float(n as f32)),
909909
Value::Float(x) => Ok(Value::Float(x)),
910910
Value::Double(x) => Ok(Value::Float(x as f32)),
911-
Value::String(x) => match Self::parse_special_float(&x) {
911+
Value::String(ref x) => match Self::parse_special_float(x) {
912912
Some(f) => Ok(Value::Float(f)),
913-
None => Err(Error::GetFloat(ValueKind::String)),
913+
None => Err(Error::GetFloat(self)),
914914
},
915-
other => Err(Error::GetFloat(other.into())),
915+
other => Err(Error::GetFloat(other)),
916916
}
917917
}
918918

@@ -922,21 +922,21 @@ impl Value {
922922
Value::Long(n) => Ok(Value::Double(n as f64)),
923923
Value::Float(x) => Ok(Value::Double(f64::from(x))),
924924
Value::Double(x) => Ok(Value::Double(x)),
925-
Value::String(x) => match Self::parse_special_float(&x) {
926-
Some(f) => Ok(Value::Double(f.into())),
927-
None => Err(Error::GetDouble(ValueKind::String)),
925+
Value::String(ref x) => match Self::parse_special_float(x) {
926+
Some(f) => Ok(Value::Double(f64::from(f))),
927+
None => Err(Error::GetDouble(self)),
928928
},
929-
other => Err(Error::GetDouble(other.into())),
929+
other => Err(Error::GetDouble(other)),
930930
}
931931
}
932932

933933
/// IEEE 754 NaN and infinities are not valid JSON numbers.
934934
/// So they are represented in JSON as strings.
935-
fn parse_special_float(s: &str) -> Option<f32> {
936-
match s.trim().to_ascii_lowercase().as_str() {
937-
"nan" | "+nan" | "-nan" => Some(f32::NAN),
938-
"inf" | "+inf" | "infinity" | "+infinity" => Some(f32::INFINITY),
939-
"-inf" | "-infinity" => Some(f32::NEG_INFINITY),
935+
fn parse_special_float(value: &str) -> Option<f32> {
936+
match value {
937+
"NaN" => Some(f32::NAN),
938+
"INF" | "Infinity" => Some(f32::INFINITY),
939+
"-INF" | "-Infinity" => Some(f32::NEG_INFINITY),
940940
_ => None,
941941
}
942942
}
@@ -3138,4 +3138,40 @@ Field with name '"b"' is not a member of the map items"#,
31383138
)
31393139
);
31403140
}
3141+
3142+
#[test]
3143+
fn avro_4024_resolve_double_from_unknown_string_err() -> TestResult {
3144+
let schema = Schema::parse_str(r#"{"type": "double"}"#)?;
3145+
let value = Value::String("unknown".to_owned());
3146+
match value.resolve(&schema) {
3147+
Err(err @ Error::GetDouble(_)) => {
3148+
assert_eq!(
3149+
format!("{err:?}"),
3150+
r#"Double expected, got String("unknown")"#
3151+
);
3152+
}
3153+
other => {
3154+
panic!("Expected Error::GetDouble, got {other:?}");
3155+
}
3156+
}
3157+
Ok(())
3158+
}
3159+
3160+
#[test]
3161+
fn avro_4024_resolve_float_from_unknown_string_err() -> TestResult {
3162+
let schema = Schema::parse_str(r#"{"type": "float"}"#)?;
3163+
let value = Value::String("unknown".to_owned());
3164+
match value.resolve(&schema) {
3165+
Err(err @ Error::GetFloat(_)) => {
3166+
assert_eq!(
3167+
format!("{err:?}"),
3168+
r#"Float expected, got String("unknown")"#
3169+
);
3170+
}
3171+
other => {
3172+
panic!("Expected Error::GetFloat, got {other:?}");
3173+
}
3174+
}
3175+
Ok(())
3176+
}
31413177
}

lang/rust/avro/tests/io.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,14 +107,22 @@ fn default_value_examples() -> &'static Vec<(&'static str, &'static str, Value)>
107107
(r#""long""#, "5", Value::Long(5)),
108108
(r#""float""#, "1.1", Value::Float(1.1)),
109109
(r#""double""#, "1.1", Value::Double(1.1)),
110-
(r#""float""#, r#"" +inf ""#, Value::Float(f32::INFINITY)),
110+
(r#""float""#, r#""INF""#, Value::Float(f32::INFINITY)),
111+
(r#""double""#, r#""INF""#, Value::Double(f64::INFINITY)),
112+
(r#""float""#, r#""Infinity""#, Value::Float(f32::INFINITY)),
113+
(
114+
r#""float""#,
115+
r#""-Infinity""#,
116+
Value::Float(f32::NEG_INFINITY),
117+
),
118+
(r#""double""#, r#""Infinity""#, Value::Double(f64::INFINITY)),
111119
(
112120
r#""double""#,
113121
r#""-Infinity""#,
114122
Value::Double(f64::NEG_INFINITY),
115123
),
116-
(r#""float""#, r#""-NAN""#, Value::Float(f32::NAN)),
117-
(r#""double""#, r#""-NAN""#, Value::Double(f64::NAN)),
124+
(r#""float""#, r#""NaN""#, Value::Float(f32::NAN)),
125+
(r#""double""#, r#""NaN""#, Value::Double(f64::NAN)),
118126
(
119127
r#"{"type": "fixed", "name": "F", "size": 2}"#,
120128
r#""a""#,

0 commit comments

Comments
 (0)