Skip to content

Commit cde1525

Browse files
xxchanxiangjinwu
andcommitted
AVRO-4024: [Rust] support nan/inf/-inf as float/double default
Co-authored-by: Xiangjin <xiangjin@risingwave-labs.com> Signed-off-by: xxchan <xxchan22f@gmail.com>
1 parent 42c54e6 commit cde1525

File tree

2 files changed

+32
-2
lines changed

2 files changed

+32
-2
lines changed

lang/rust/avro/src/types.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -908,6 +908,10 @@ 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) {
912+
Some(f) => Ok(Value::Float(f)),
913+
None => Err(Error::GetFloat(ValueKind::String)),
914+
},
911915
other => Err(Error::GetFloat(other.into())),
912916
}
913917
}
@@ -918,10 +922,25 @@ impl Value {
918922
Value::Long(n) => Ok(Value::Double(n as f64)),
919923
Value::Float(x) => Ok(Value::Double(f64::from(x))),
920924
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)),
928+
},
921929
other => Err(Error::GetDouble(other.into())),
922930
}
923931
}
924932

933+
/// IEEE 754 NaN and infinities are not valid JSON numbers.
934+
/// 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),
940+
_ => None,
941+
}
942+
}
943+
925944
fn resolve_bytes(self) -> Result<Self, Error> {
926945
match self {
927946
Value::Bytes(bytes) => Ok(Value::Bytes(bytes)),

lang/rust/avro/tests/io.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,14 @@ 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)),
111+
(
112+
r#""double""#,
113+
r#""-Infinity""#,
114+
Value::Double(f64::NEG_INFINITY),
115+
),
116+
(r#""float""#, r#""-NAN""#, Value::Float(f32::NAN)),
117+
(r#""double""#, r#""-NAN""#, Value::Double(f64::NAN)),
110118
(
111119
r#"{"type": "fixed", "name": "F", "size": 2}"#,
112120
r#""a""#,
@@ -312,10 +320,13 @@ fn test_default_value() -> TestResult {
312320
&mut Cursor::new(encoded),
313321
Some(&reader_schema),
314322
)?;
323+
// For float/double, NaN != NaN, so we compare the Debug representation here.
315324
assert_eq!(
316-
datum_read, datum_to_read,
325+
format!("{datum_read:?}"),
326+
format!("{datum_to_read:?}"),
317327
"{} -> {}",
318-
*field_type, *default_json
328+
*field_type,
329+
*default_json
319330
);
320331
}
321332

0 commit comments

Comments
 (0)