This is an automated email from the ASF dual-hosted git repository.

mgrigorov pushed a commit to branch branch-1.12
in repository https://gitbox.apache.org/repos/asf/avro.git


The following commit(s) were added to refs/heads/branch-1.12 by this push:
     new 5277c1497 AVRO-4024: [Rust] Sync the possible String default values 
for floating numbers with Java and C# (#3073)
5277c1497 is described below

commit 5277c1497697eaf4e48b081a2d5b8cbd2101dd05
Author: Martin Grigorov <[email protected]>
AuthorDate: Wed Aug 7 14:42:38 2024 +0300

    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 <[email protected]>
    
    * AVRO-4024: [Rust] Accept only "Nan", "INF", "-INF", "Infinity" and 
"-Infinity"
    
    This is what the Java SDK (via Jackson library) supports 
(https://github.com/apache/avro/pull/3066).
    This is what the C# SDK also would support 
(https://github.com/apache/avro/pull/3070)
    
    Signed-off-by: Martin Tzvetanov Grigorov <[email protected]>
    
    ---------
    
    Signed-off-by: Martin Tzvetanov Grigorov <[email protected]>
    (cherry picked from commit dffc13a6b3b71bfd6fd01e3041955e65c0697f3b)
---
 lang/rust/avro/src/error.rs |  4 +--
 lang/rust/avro/src/types.rs | 60 ++++++++++++++++++++++++++++++++++++---------
 lang/rust/avro/tests/io.rs  | 14 ++++++++---
 3 files changed, 61 insertions(+), 17 deletions(-)

diff --git a/lang/rust/avro/src/error.rs b/lang/rust/avro/src/error.rs
index 6e0de0dcb..c4ec2baa8 100644
--- a/lang/rust/avro/src/error.rs
+++ b/lang/rust/avro/src/error.rs
@@ -189,10 +189,10 @@ pub enum Error {
     GetLong(ValueKind),
 
     #[error("Double expected, got {0:?}")]
-    GetDouble(ValueKind),
+    GetDouble(Value),
 
     #[error("Float expected, got {0:?}")]
-    GetFloat(ValueKind),
+    GetFloat(Value),
 
     #[error("Bytes expected, got {0:?}")]
     GetBytes(ValueKind),
diff --git a/lang/rust/avro/src/types.rs b/lang/rust/avro/src/types.rs
index 0840c87ae..0ce6afc53 100644
--- a/lang/rust/avro/src/types.rs
+++ b/lang/rust/avro/src/types.rs
@@ -908,11 +908,11 @@ impl Value {
             Value::Long(n) => Ok(Value::Float(n as f32)),
             Value::Float(x) => Ok(Value::Float(x)),
             Value::Double(x) => Ok(Value::Float(x as f32)),
-            Value::String(x) => match Self::parse_special_float(&x) {
+            Value::String(ref x) => match Self::parse_special_float(x) {
                 Some(f) => Ok(Value::Float(f)),
-                None => Err(Error::GetFloat(ValueKind::String)),
+                None => Err(Error::GetFloat(self)),
             },
-            other => Err(Error::GetFloat(other.into())),
+            other => Err(Error::GetFloat(other)),
         }
     }
 
@@ -922,21 +922,21 @@ impl Value {
             Value::Long(n) => Ok(Value::Double(n as f64)),
             Value::Float(x) => Ok(Value::Double(f64::from(x))),
             Value::Double(x) => Ok(Value::Double(x)),
-            Value::String(x) => match Self::parse_special_float(&x) {
-                Some(f) => Ok(Value::Double(f.into())),
-                None => Err(Error::GetDouble(ValueKind::String)),
+            Value::String(ref x) => match Self::parse_special_float(x) {
+                Some(f) => Ok(Value::Double(f64::from(f))),
+                None => Err(Error::GetDouble(self)),
             },
-            other => Err(Error::GetDouble(other.into())),
+            other => Err(Error::GetDouble(other)),
         }
     }
 
     /// IEEE 754 NaN and infinities are not valid JSON numbers.
     /// So they are represented in JSON as strings.
-    fn parse_special_float(s: &str) -> Option<f32> {
-        match s.trim().to_ascii_lowercase().as_str() {
-            "nan" | "+nan" | "-nan" => Some(f32::NAN),
-            "inf" | "+inf" | "infinity" | "+infinity" => Some(f32::INFINITY),
-            "-inf" | "-infinity" => Some(f32::NEG_INFINITY),
+    fn parse_special_float(value: &str) -> Option<f32> {
+        match value {
+            "NaN" => Some(f32::NAN),
+            "INF" | "Infinity" => Some(f32::INFINITY),
+            "-INF" | "-Infinity" => Some(f32::NEG_INFINITY),
             _ => None,
         }
     }
@@ -3138,4 +3138,40 @@ Field with name '"b"' is not a member of the map items"#,
             )
         );
     }
+
+    #[test]
+    fn avro_4024_resolve_double_from_unknown_string_err() -> TestResult {
+        let schema = Schema::parse_str(r#"{"type": "double"}"#)?;
+        let value = Value::String("unknown".to_owned());
+        match value.resolve(&schema) {
+            Err(err @ Error::GetDouble(_)) => {
+                assert_eq!(
+                    format!("{err:?}"),
+                    r#"Double expected, got String("unknown")"#
+                );
+            }
+            other => {
+                panic!("Expected Error::GetDouble, got {other:?}");
+            }
+        }
+        Ok(())
+    }
+
+    #[test]
+    fn avro_4024_resolve_float_from_unknown_string_err() -> TestResult {
+        let schema = Schema::parse_str(r#"{"type": "float"}"#)?;
+        let value = Value::String("unknown".to_owned());
+        match value.resolve(&schema) {
+            Err(err @ Error::GetFloat(_)) => {
+                assert_eq!(
+                    format!("{err:?}"),
+                    r#"Float expected, got String("unknown")"#
+                );
+            }
+            other => {
+                panic!("Expected Error::GetFloat, got {other:?}");
+            }
+        }
+        Ok(())
+    }
 }
diff --git a/lang/rust/avro/tests/io.rs b/lang/rust/avro/tests/io.rs
index 6a59a5071..c6589a978 100644
--- a/lang/rust/avro/tests/io.rs
+++ b/lang/rust/avro/tests/io.rs
@@ -107,14 +107,22 @@ fn default_value_examples() -> &'static Vec<(&'static 
str, &'static str, Value)>
             (r#""long""#, "5", Value::Long(5)),
             (r#""float""#, "1.1", Value::Float(1.1)),
             (r#""double""#, "1.1", Value::Double(1.1)),
-            (r#""float""#, r#""  +inf ""#, Value::Float(f32::INFINITY)),
+            (r#""float""#, r#""INF""#, Value::Float(f32::INFINITY)),
+            (r#""double""#, r#""INF""#, Value::Double(f64::INFINITY)),
+            (r#""float""#, r#""Infinity""#, Value::Float(f32::INFINITY)),
+            (
+                r#""float""#,
+                r#""-Infinity""#,
+                Value::Float(f32::NEG_INFINITY),
+            ),
+            (r#""double""#, r#""Infinity""#, Value::Double(f64::INFINITY)),
             (
                 r#""double""#,
                 r#""-Infinity""#,
                 Value::Double(f64::NEG_INFINITY),
             ),
-            (r#""float""#, r#""-NAN""#, Value::Float(f32::NAN)),
-            (r#""double""#, r#""-NAN""#, Value::Double(f64::NAN)),
+            (r#""float""#, r#""NaN""#, Value::Float(f32::NAN)),
+            (r#""double""#, r#""NaN""#, Value::Double(f64::NAN)),
             (
                 r#"{"type": "fixed", "name": "F", "size": 2}"#,
                 r#""a""#,

Reply via email to