Repository: serde-rs/json (language: rust)

Issue:
With feature "arbitrary_precision" exponent marker get converted to lowercase
Comment in [`Cargo.toml`](https://github.com/serde-rs/json/blob/ea39063f9c8c7dde4ac43bbd9843287bece59b1a/Cargo.toml#L71) for feature `arbitrary_precision` states:
> This feature makes `JSON` -> `serde_json::Number` -> `JSON` produce output identical to the input.

But in [`serde_json::de::scan_exponent`](https://github.com/serde-rs/json/blob/ea39063f9c8c7dde4ac43bbd9843287bece59b1a/src/de.rs#L934), for the exponent marker (`e` or `E`), a lowercase `e` is inserted unconditionally to the internal representation. Therefore, for an input JSON `1.9E10` for example, a "`JSON` -> `serde_json::Number` -> `JSON`" roundtrip results in JSON `1.9e10`, which is different from the input JSON.

Is this behaviour intended? If no other code rely on `e` being lowercase, I suggest we insert an `e` or `E` based on the input. Some specification requires some fields always treated as string, and in case they are presented as numbers in JSON, they should be converted to strings *verbatim*. `arbitrary_precision` is the only method I found for such circumstances, and I believe it should behave as described in `Cargo.toml`.

P.S. If you see the above-mentioned change appropriate, I can make a PR for this.


Discussion / hints:

Fix patch:
diff --git a/src/de.rs b/src/de.rs
index 15c8236b6..1824117a0 100644
--- a/src/de.rs
+++ b/src/de.rs
@@ -898,7 +898,7 @@ impl<'de, R: Read<'de>> Deserializer<R> {
     fn scan_number(&mut self, buf: &mut String) -> Result<()> {
         match tri!(self.peek_or_null()) {
             b'.' => self.scan_decimal(buf),
-            b'e' | b'E' => self.scan_exponent(buf),
+            c @ (b'e' | b'E') => self.scan_exponent(c as char, buf),
             _ => Ok(()),
         }
     }
@@ -923,19 +923,20 @@ impl<'de, R: Read<'de>> Deserializer<R> {
         }
 
         match tri!(self.peek_or_null()) {
-            b'e' | b'E' => self.scan_exponent(buf),
+            c @ (b'e' | b'E') => self.scan_exponent(c as char, buf),
             _ => Ok(()),
         }
     }
 
     #[cfg(feature = "arbitrary_precision")]
-    fn scan_exponent(&mut self, buf: &mut String) -> Result<()> {
+    fn scan_exponent(&mut self, e: char, buf: &mut String) -> Result<()> {
         self.eat_char();
-        buf.push('e');
+        buf.push(e);
 
         match tri!(self.peek_or_null()) {
             b'+' => {
                 self.eat_char();
+                buf.push('+');
             }
             b'-' => {
                 self.eat_char();


Test patch:
diff --git a/tests/test.rs b/tests/test.rs
index 2fe7c560a..3d701d827 100644
--- a/tests/test.rs
+++ b/tests/test.rs
@@ -1007,8 +1007,14 @@ fn test_parse_number() {
     #[cfg(feature = "arbitrary_precision")]
     test_parse_ok(vec![
         ("1e999", Number::from_string_unchecked("1e999".to_owned())),
+        ("1e+999", Number::from_string_unchecked("1e+999".to_owned())),
         ("-1e999", Number::from_string_unchecked("-1e999".to_owned())),
         ("1e-999", Number::from_string_unchecked("1e-999".to_owned())),
+        ("1E999", Number::from_string_unchecked("1E999".to_owned())),
+        ("1E+999", Number::from_string_unchecked("1E+999".to_owned())),
+        ("-1E999", Number::from_string_unchecked("-1E999".to_owned())),
+        ("1E-999", Number::from_string_unchecked("1E-999".to_owned())),
+        ("1E+000", Number::from_string_unchecked("1E+000".to_owned())),
         (
             "2.3e999",
             Number::from_string_unchecked("2.3e999".to_owned()),