diff --git a/arrow-json/src/reader/string_array.rs b/arrow-json/src/reader/string_array.rs index 03d07ad8c8b3..cf19f32cd2cd 100644 --- a/arrow-json/src/reader/string_array.rs +++ b/arrow-json/src/reader/string_array.rs @@ -20,6 +20,7 @@ use arrow_array::{Array, GenericStringArray, OffsetSizeTrait}; use arrow_data::ArrayData; use arrow_schema::ArrowError; use std::marker::PhantomData; +use std::io::Write; use crate::reader::tape::{Tape, TapeElement}; use crate::reader::ArrayDecoder; @@ -30,6 +31,7 @@ const FALSE: &str = "false"; pub struct StringArrayDecoder { coerce_primitive: bool, phantom: PhantomData, + number_buffer: Vec, } impl StringArrayDecoder { @@ -37,8 +39,17 @@ impl StringArrayDecoder { Self { coerce_primitive, phantom: Default::default(), + number_buffer: Vec::with_capacity(32), } } + + fn write_number(&mut self, n: T) -> &str { + self.number_buffer.clear(); + write!(&mut self.number_buffer, "{}", n).unwrap(); + // SAFETY: We only write ASCII characters (digits, signs, decimal points, + // exponent symbols) into `number_buffer`, which are guaranteed valid UTF-8. + unsafe { std::str::from_utf8_unchecked(&self.number_buffer) } + } } impl ArrayDecoder for StringArrayDecoder { @@ -103,20 +114,24 @@ impl ArrayDecoder for StringArrayDecoder { TapeElement::I64(high) if coerce_primitive => match tape.get(p + 1) { TapeElement::I32(low) => { let val = ((high as i64) << 32) | (low as u32) as i64; - builder.append_value(val.to_string()); + let s = self.write_number(val); + builder.append_value(s); } _ => unreachable!(), }, TapeElement::I32(n) if coerce_primitive => { - builder.append_value(n.to_string()); + let s = self.write_number(n); + builder.append_value(s); } TapeElement::F32(n) if coerce_primitive => { - builder.append_value(n.to_string()); + let s = self.write_number(n); + builder.append_value(s); } TapeElement::F64(high) if coerce_primitive => match tape.get(p + 1) { TapeElement::F32(low) => { let val = f64::from_bits(((high as u64) << 32) | low as u64); - builder.append_value(val.to_string()); + let s = self.write_number(val); + builder.append_value(s); } _ => unreachable!(), },