From d0b66b268cee9d4462e767acbe7033a14d337771 Mon Sep 17 00:00:00 2001 From: Michal Piatkowski <291740709+MassivePizza@users.noreply.github.com> Date: Thu, 16 Jul 2026 12:30:47 +0200 Subject: [PATCH 1/7] split one contiguous Bytes instead of allocating ByteArray per element --- parquet/src/arrow/arrow_writer/mod.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/parquet/src/arrow/arrow_writer/mod.rs b/parquet/src/arrow/arrow_writer/mod.rs index 7dd7fb778909..da8df7e2910e 100644 --- a/parquet/src/arrow/arrow_writer/mod.rs +++ b/parquet/src/arrow/arrow_writer/mod.rs @@ -1880,12 +1880,20 @@ fn get_decimal_128_array_slice( array: &arrow_array::Decimal128Array, indices: impl ExactSizeIterator, ) -> Vec { - let mut values = Vec::with_capacity(indices.len()); let size = decimal_length_from_precision(array.precision()); + let mut arena = Vec::with_capacity(indices.len() * size); + let mut values = Vec::with_capacity(indices.len()); + for i in indices { - let as_be_bytes = array.value(i).to_be_bytes(); - let resized_value = as_be_bytes[(16 - size)..].to_vec(); - values.push(FixedLenByteArray::from(ByteArray::from(resized_value))); + let as_be_bytes = array.value(*i).to_be_bytes(); + let resized_value = &as_be_bytes[(16 - size)..]; + arena.extend_from_slice(resized_value); + } + + let mut arena = Bytes::from(arena); + while arena.len() >= size { + let slice = arena.split_to(size); + values.push(FixedLenByteArray::from(ByteArray::from(slice))); } values } From f62743e84fbc5b83d0a3a2bea21676b2b3005116 Mon Sep 17 00:00:00 2001 From: Michal Piatkowski <291740709+MassivePizza@users.noreply.github.com> Date: Thu, 16 Jul 2026 16:51:42 +0200 Subject: [PATCH 2/7] chunk_contiguous_vec for all decimal types, f16, and fsb --- parquet/src/arrow/arrow_writer/mod.rs | 148 ++++++++++++++------------ 1 file changed, 77 insertions(+), 71 deletions(-) diff --git a/parquet/src/arrow/arrow_writer/mod.rs b/parquet/src/arrow/arrow_writer/mod.rs index da8df7e2910e..5aab0c772051 100644 --- a/parquet/src/arrow/arrow_writer/mod.rs +++ b/parquet/src/arrow/arrow_writer/mod.rs @@ -26,8 +26,8 @@ use std::sync::{Arc, Mutex}; use std::vec::IntoIter; use arrow_array::cast::AsArray; -use arrow_array::types::*; use arrow_array::{ArrayRef, Int32Array, RecordBatch, RecordBatchWriter}; +use arrow_array::{PrimitiveArray, types::*}; use arrow_schema::{ ArrowError, DataType as ArrowDataType, Field, IntervalUnit, SchemaRef, TimeUnit, }; @@ -1751,19 +1751,19 @@ fn write_leaf( } ArrowDataType::Decimal32(_, _) => { let array = column.as_primitive::(); - get_decimal_32_array_slice(array, indices.iter().copied()) + get_decimal_array_slice(array, indices.iter().copied()) } ArrowDataType::Decimal64(_, _) => { let array = column.as_primitive::(); - get_decimal_64_array_slice(array, indices.iter().copied()) + get_decimal_array_slice(array, indices.iter().copied()) } ArrowDataType::Decimal128(_, _) => { let array = column.as_primitive::(); - get_decimal_128_array_slice(array, indices.iter().copied()) + get_decimal_array_slice(array, indices.iter().copied()) } ArrowDataType::Decimal256(_, _) => { let array = column.as_primitive::(); - get_decimal_256_array_slice(array, indices.iter().copied()) + get_decimal_array_slice(array, indices.iter().copied()) } ArrowDataType::Float16 => { let array = column.as_primitive::(); @@ -1821,14 +1821,15 @@ fn get_interval_ym_array_slice( array: &arrow_array::IntervalYearMonthArray, indices: impl ExactSizeIterator, ) -> Vec { - let mut values = Vec::with_capacity(indices.len()); + const VALUE_SIZE: usize = 12; + let mut arena = Vec::with_capacity(indices.len() * VALUE_SIZE); for i in indices { - let mut value = array.value(i).to_le_bytes().to_vec(); - let mut suffix = vec![0; 8]; - value.append(&mut suffix); - values.push(FixedLenByteArray::from(ByteArray::from(value))) + let mut out = [0; 12]; + let value = array.value(i); + out[0..4].copy_from_slice(&value.to_le_bytes()); + arena.extend_from_slice(&out); } - values + chunk_contiguous_vec(arena, VALUE_SIZE) } /// Returns 12-byte values representing 3 values of months, days and milliseconds (4-bytes each). @@ -1837,101 +1838,106 @@ fn get_interval_dt_array_slice( array: &arrow_array::IntervalDayTimeArray, indices: impl ExactSizeIterator, ) -> Vec { - let mut values = Vec::with_capacity(indices.len()); + const VALUE_SIZE: usize = 12; + let mut arena = Vec::with_capacity(indices.len() * VALUE_SIZE); for i in indices { - let mut out = [0; 12]; - let value = array.value(i); + let mut out = [0; VALUE_SIZE]; + let value = array.value(*i); out[4..8].copy_from_slice(&value.days.to_le_bytes()); out[8..12].copy_from_slice(&value.milliseconds.to_le_bytes()); - values.push(FixedLenByteArray::from(ByteArray::from(out.to_vec()))); + arena.extend_from_slice(&out); } - values + chunk_contiguous_vec(arena, VALUE_SIZE) } -fn get_decimal_32_array_slice( - array: &arrow_array::Decimal32Array, - indices: impl ExactSizeIterator, -) -> Vec { - let mut values = Vec::with_capacity(indices.len()); - let size = decimal_length_from_precision(array.precision()); - for i in indices { - let as_be_bytes = array.value(i).to_be_bytes(); - let resized_value = as_be_bytes[(4 - size)..].to_vec(); - values.push(FixedLenByteArray::from(ByteArray::from(resized_value))); - } - values +trait NativeDecimalType: DecimalType { + type NativeBytes: AsRef<[u8]>; + + fn to_be_bytes(value: Self::Native) -> Self::NativeBytes; } +impl NativeDecimalType for Decimal32Type { + type NativeBytes = [u8; Self::BYTE_LENGTH]; -fn get_decimal_64_array_slice( - array: &arrow_array::Decimal64Array, - indices: impl ExactSizeIterator, -) -> Vec { - let mut values = Vec::with_capacity(indices.len()); - let size = decimal_length_from_precision(array.precision()); - for i in indices { - let as_be_bytes = array.value(i).to_be_bytes(); - let resized_value = as_be_bytes[(8 - size)..].to_vec(); - values.push(FixedLenByteArray::from(ByteArray::from(resized_value))); + fn to_be_bytes(value: Self::Native) -> Self::NativeBytes { + value.to_be_bytes() } - values } +impl NativeDecimalType for Decimal64Type { + type NativeBytes = [u8; Self::BYTE_LENGTH]; -fn get_decimal_128_array_slice( - array: &arrow_array::Decimal128Array, - indices: impl ExactSizeIterator, -) -> Vec { - let size = decimal_length_from_precision(array.precision()); - let mut arena = Vec::with_capacity(indices.len() * size); - let mut values = Vec::with_capacity(indices.len()); + fn to_be_bytes(value: Self::Native) -> Self::NativeBytes { + value.to_be_bytes() + } +} +impl NativeDecimalType for Decimal128Type { + type NativeBytes = [u8; Self::BYTE_LENGTH]; - for i in indices { - let as_be_bytes = array.value(*i).to_be_bytes(); - let resized_value = &as_be_bytes[(16 - size)..]; - arena.extend_from_slice(resized_value); + fn to_be_bytes(value: Self::Native) -> Self::NativeBytes { + value.to_be_bytes() } +} +impl NativeDecimalType for Decimal256Type { + type NativeBytes = [u8; Self::BYTE_LENGTH]; - let mut arena = Bytes::from(arena); - while arena.len() >= size { - let slice = arena.split_to(size); - values.push(FixedLenByteArray::from(ByteArray::from(slice))); + fn to_be_bytes(value: Self::Native) -> Self::NativeBytes { + value.to_be_bytes() } - values } -fn get_decimal_256_array_slice( - array: &arrow_array::Decimal256Array, +fn get_decimal_array_slice( + array: &PrimitiveArray, indices: impl ExactSizeIterator, ) -> Vec { - let mut values = Vec::with_capacity(indices.len()); - let size = decimal_length_from_precision(array.precision()); - for i in indices { - let as_be_bytes = array.value(i).to_be_bytes(); - let resized_value = as_be_bytes[(32 - size)..].to_vec(); - values.push(FixedLenByteArray::from(ByteArray::from(resized_value))); + let value_size = decimal_length_from_precision(array.precision()); + let mut arena = Vec::with_capacity(indices.len() * value_size); + + if value_size == T::BYTE_LENGTH { + for i in indices { + let as_be_bytes = T::to_be_bytes(array.value(*i)); + arena.extend_from_slice(as_be_bytes.as_ref()); + } + } else { + for i in indices { + let as_be_bytes = T::to_be_bytes(array.value(*i)); + let resized_value = &as_be_bytes.as_ref()[(T::BYTE_LENGTH - value_size)..]; + arena.extend_from_slice(resized_value); + } } - values + chunk_contiguous_vec(arena, value_size) } fn get_float_16_array_slice( array: &arrow_array::Float16Array, indices: impl ExactSizeIterator, ) -> Vec { - let mut values = Vec::with_capacity(indices.len()); + const VALUE_SIZE: usize = size_of::<::Native>(); + let mut arena = Vec::with_capacity(indices.len() * VALUE_SIZE); for i in indices { - let value = array.value(i).to_le_bytes().to_vec(); - values.push(FixedLenByteArray::from(ByteArray::from(value))); + let value = array.value(i).to_le_bytes(); + arena.extend_from_slice(&value); } - values + chunk_contiguous_vec(arena, VALUE_SIZE) } fn get_fsb_array_slice( array: &arrow_array::FixedSizeBinaryArray, indices: impl ExactSizeIterator, ) -> Vec { - let mut values = Vec::with_capacity(indices.len()); + let value_size = array.value_length() as usize; + let mut arena = Vec::with_capacity(indices.len() * value_size); for i in indices { - let value = array.value(i).to_vec(); - values.push(FixedLenByteArray::from(ByteArray::from(value))) + let value = array.value(*i); + arena.extend_from_slice(value); + } + chunk_contiguous_vec(arena, value_size) +} + +fn chunk_contiguous_vec(arena: Vec, value_size: usize) -> Vec { + let mut values = Vec::with_capacity(arena.len() / value_size); + let mut arena = Bytes::from(arena); + while arena.len() >= value_size { + let slice = arena.split_to(value_size); + values.push(FixedLenByteArray::from(ByteArray::from(slice))); } values } From 3118acd2c277488f1645c6b2c9b1e1647dd887ab Mon Sep 17 00:00:00 2001 From: Michal Piatkowski <291740709+MassivePizza@users.noreply.github.com> Date: Mon, 20 Jul 2026 15:53:50 +0200 Subject: [PATCH 3/7] fix rebase errors --- parquet/src/arrow/arrow_writer/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/parquet/src/arrow/arrow_writer/mod.rs b/parquet/src/arrow/arrow_writer/mod.rs index 5aab0c772051..2000150832b7 100644 --- a/parquet/src/arrow/arrow_writer/mod.rs +++ b/parquet/src/arrow/arrow_writer/mod.rs @@ -1842,7 +1842,7 @@ fn get_interval_dt_array_slice( let mut arena = Vec::with_capacity(indices.len() * VALUE_SIZE); for i in indices { let mut out = [0; VALUE_SIZE]; - let value = array.value(*i); + let value = array.value(i); out[4..8].copy_from_slice(&value.days.to_le_bytes()); out[8..12].copy_from_slice(&value.milliseconds.to_le_bytes()); arena.extend_from_slice(&out); @@ -1893,12 +1893,12 @@ fn get_decimal_array_slice( if value_size == T::BYTE_LENGTH { for i in indices { - let as_be_bytes = T::to_be_bytes(array.value(*i)); + let as_be_bytes = T::to_be_bytes(array.value(i)); arena.extend_from_slice(as_be_bytes.as_ref()); } } else { for i in indices { - let as_be_bytes = T::to_be_bytes(array.value(*i)); + let as_be_bytes = T::to_be_bytes(array.value(i)); let resized_value = &as_be_bytes.as_ref()[(T::BYTE_LENGTH - value_size)..]; arena.extend_from_slice(resized_value); } @@ -1926,7 +1926,7 @@ fn get_fsb_array_slice( let value_size = array.value_length() as usize; let mut arena = Vec::with_capacity(indices.len() * value_size); for i in indices { - let value = array.value(*i); + let value = array.value(i); arena.extend_from_slice(value); } chunk_contiguous_vec(arena, value_size) From baa13dd29c458595eb6913fc2a24885309cbf6c1 Mon Sep 17 00:00:00 2001 From: Michal Piatkowski <291740709+MassivePizza@users.noreply.github.com> Date: Mon, 20 Jul 2026 18:26:26 +0200 Subject: [PATCH 4/7] Rewrite to use chunks_exact_mut. This allows optimizations since iterators uphold invariants. --- parquet/src/arrow/arrow_writer/mod.rs | 89 ++++++++++++++------------- 1 file changed, 46 insertions(+), 43 deletions(-) diff --git a/parquet/src/arrow/arrow_writer/mod.rs b/parquet/src/arrow/arrow_writer/mod.rs index 2000150832b7..8a82939d7b0f 100644 --- a/parquet/src/arrow/arrow_writer/mod.rs +++ b/parquet/src/arrow/arrow_writer/mod.rs @@ -21,6 +21,7 @@ use crate::column::chunker::ContentDefinedChunker; use bytes::Bytes; use std::io::Write; +use std::mem::MaybeUninit; use std::slice::Iter; use std::sync::{Arc, Mutex}; use std::vec::IntoIter; @@ -1821,15 +1822,12 @@ fn get_interval_ym_array_slice( array: &arrow_array::IntervalYearMonthArray, indices: impl ExactSizeIterator, ) -> Vec { - const VALUE_SIZE: usize = 12; - let mut arena = Vec::with_capacity(indices.len() * VALUE_SIZE); - for i in indices { - let mut out = [0; 12]; + chunk_array_slice(12, indices, move |i, chunk| { let value = array.value(i); - out[0..4].copy_from_slice(&value.to_le_bytes()); - arena.extend_from_slice(&out); - } - chunk_contiguous_vec(arena, VALUE_SIZE) + chunk[0..4].write_copy_of_slice(&value.to_le_bytes()); + chunk[4..12].fill(MaybeUninit::new(0)); + unsafe { chunk.assume_init_mut() } + }) } /// Returns 12-byte values representing 3 values of months, days and milliseconds (4-bytes each). @@ -1838,16 +1836,13 @@ fn get_interval_dt_array_slice( array: &arrow_array::IntervalDayTimeArray, indices: impl ExactSizeIterator, ) -> Vec { - const VALUE_SIZE: usize = 12; - let mut arena = Vec::with_capacity(indices.len() * VALUE_SIZE); - for i in indices { - let mut out = [0; VALUE_SIZE]; + chunk_array_slice(12, indices, move |i, chunk| { let value = array.value(i); - out[4..8].copy_from_slice(&value.days.to_le_bytes()); - out[8..12].copy_from_slice(&value.milliseconds.to_le_bytes()); - arena.extend_from_slice(&out); - } - chunk_contiguous_vec(arena, VALUE_SIZE) + chunk[0..4].fill(MaybeUninit::new(0)); + chunk[4..8].write_copy_of_slice(&value.days.to_le_bytes()); + chunk[8..12].write_copy_of_slice(&value.milliseconds.to_le_bytes()); + unsafe { chunk.assume_init_mut() } + }) } trait NativeDecimalType: DecimalType { @@ -1888,55 +1883,63 @@ fn get_decimal_array_slice( array: &PrimitiveArray, indices: impl ExactSizeIterator, ) -> Vec { - let value_size = decimal_length_from_precision(array.precision()); - let mut arena = Vec::with_capacity(indices.len() * value_size); + let chunk_size = decimal_length_from_precision(array.precision()); + assert!(chunk_size <= T::BYTE_LENGTH); - if value_size == T::BYTE_LENGTH { - for i in indices { + if chunk_size == T::BYTE_LENGTH { + // Special-case that allows inlining memcpy. + chunk_array_slice(chunk_size, indices, move |i, chunk| { let as_be_bytes = T::to_be_bytes(array.value(i)); - arena.extend_from_slice(as_be_bytes.as_ref()); - } + chunk.write_copy_of_slice(as_be_bytes.as_ref()) + }) } else { - for i in indices { + chunk_array_slice(chunk_size, indices, move |i, chunk| { let as_be_bytes = T::to_be_bytes(array.value(i)); - let resized_value = &as_be_bytes.as_ref()[(T::BYTE_LENGTH - value_size)..]; - arena.extend_from_slice(resized_value); - } + let resized_value = &as_be_bytes.as_ref()[(T::BYTE_LENGTH - chunk.len())..]; + chunk.write_copy_of_slice(resized_value) + }) } - chunk_contiguous_vec(arena, value_size) } fn get_float_16_array_slice( array: &arrow_array::Float16Array, indices: impl ExactSizeIterator, ) -> Vec { - const VALUE_SIZE: usize = size_of::<::Native>(); - let mut arena = Vec::with_capacity(indices.len() * VALUE_SIZE); - for i in indices { + chunk_array_slice(2, indices, move |i, chunk| { let value = array.value(i).to_le_bytes(); - arena.extend_from_slice(&value); - } - chunk_contiguous_vec(arena, VALUE_SIZE) + chunk.write_copy_of_slice(&value) + }) } fn get_fsb_array_slice( array: &arrow_array::FixedSizeBinaryArray, indices: impl ExactSizeIterator, ) -> Vec { - let value_size = array.value_length() as usize; - let mut arena = Vec::with_capacity(indices.len() * value_size); - for i in indices { + chunk_array_slice(array.value_size(), indices, move |i, chunk| { let value = array.value(i); - arena.extend_from_slice(value); + chunk.write_copy_of_slice(value) + }) +} + +#[inline] +fn chunk_array_slice( + chunk_size: usize, + indices: impl ExactSizeIterator, + writer: impl Fn(usize, &mut [MaybeUninit]) -> &mut [u8], +) -> Vec { + let mut arena = Vec::with_capacity(indices.len() * chunk_size); + for (i, chunk) in indices.zip(arena.spare_capacity_mut().chunks_exact_mut(chunk_size)) { + let filled_chunk = writer(i, chunk); + debug_assert_eq!(filled_chunk.len(), chunk_size); } - chunk_contiguous_vec(arena, value_size) + chunk_contiguous_vec(arena, chunk_size) } -fn chunk_contiguous_vec(arena: Vec, value_size: usize) -> Vec { - let mut values = Vec::with_capacity(arena.len() / value_size); +fn chunk_contiguous_vec(arena: Vec, chunk_size: usize) -> Vec { + let mut values = Vec::with_capacity(arena.len() / chunk_size); let mut arena = Bytes::from(arena); - while arena.len() >= value_size { - let slice = arena.split_to(value_size); + while arena.len() >= chunk_size { + let slice = arena.split_to(chunk_size); values.push(FixedLenByteArray::from(ByteArray::from(slice))); } values From 3aac92f81508d81ccbd9ef2620774dba10cf920c Mon Sep 17 00:00:00 2001 From: Michal Piatkowski <291740709+MassivePizza@users.noreply.github.com> Date: Mon, 20 Jul 2026 18:57:20 +0200 Subject: [PATCH 5/7] set_len on Vec --- parquet/src/arrow/arrow_writer/mod.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/parquet/src/arrow/arrow_writer/mod.rs b/parquet/src/arrow/arrow_writer/mod.rs index 8a82939d7b0f..26d341aa55d2 100644 --- a/parquet/src/arrow/arrow_writer/mod.rs +++ b/parquet/src/arrow/arrow_writer/mod.rs @@ -1927,10 +1927,15 @@ fn chunk_array_slice( indices: impl ExactSizeIterator, writer: impl Fn(usize, &mut [MaybeUninit]) -> &mut [u8], ) -> Vec { - let mut arena = Vec::with_capacity(indices.len() * chunk_size); + let capacity = indices.len() * chunk_size; + let mut arena = Vec::with_capacity(capacity); for (i, chunk) in indices.zip(arena.spare_capacity_mut().chunks_exact_mut(chunk_size)) { let filled_chunk = writer(i, chunk); - debug_assert_eq!(filled_chunk.len(), chunk_size); + assert_eq!(filled_chunk.len(), chunk_size); + } + // SAFETY: all chunks were initialized with writer closure + unsafe { + arena.set_len(capacity); } chunk_contiguous_vec(arena, chunk_size) } From 0aaedd00ec80a644815562d72763b5696a2b7e5a Mon Sep 17 00:00:00 2001 From: Michal Piatkowski <291740709+MassivePizza@users.noreply.github.com> Date: Mon, 20 Jul 2026 19:50:51 +0200 Subject: [PATCH 6/7] go back to tmp bufs --- parquet/src/arrow/arrow_writer/mod.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/parquet/src/arrow/arrow_writer/mod.rs b/parquet/src/arrow/arrow_writer/mod.rs index 26d341aa55d2..319cf9840cc8 100644 --- a/parquet/src/arrow/arrow_writer/mod.rs +++ b/parquet/src/arrow/arrow_writer/mod.rs @@ -1823,10 +1823,10 @@ fn get_interval_ym_array_slice( indices: impl ExactSizeIterator, ) -> Vec { chunk_array_slice(12, indices, move |i, chunk| { + let mut out = [0; 12]; let value = array.value(i); - chunk[0..4].write_copy_of_slice(&value.to_le_bytes()); - chunk[4..12].fill(MaybeUninit::new(0)); - unsafe { chunk.assume_init_mut() } + out[0..4].copy_from_slice(&value.to_le_bytes()); + chunk.write_copy_of_slice(&out) }) } @@ -1837,11 +1837,11 @@ fn get_interval_dt_array_slice( indices: impl ExactSizeIterator, ) -> Vec { chunk_array_slice(12, indices, move |i, chunk| { + let mut out = [0; 12]; let value = array.value(i); - chunk[0..4].fill(MaybeUninit::new(0)); - chunk[4..8].write_copy_of_slice(&value.days.to_le_bytes()); - chunk[8..12].write_copy_of_slice(&value.milliseconds.to_le_bytes()); - unsafe { chunk.assume_init_mut() } + out[4..8].copy_from_slice(&value.days.to_le_bytes()); + out[8..12].copy_from_slice(&value.milliseconds.to_le_bytes()); + chunk.write_copy_of_slice(&out) }) } @@ -1933,7 +1933,7 @@ fn chunk_array_slice( let filled_chunk = writer(i, chunk); assert_eq!(filled_chunk.len(), chunk_size); } - // SAFETY: all chunks were initialized with writer closure + // SAFETY: all chunks were initialized with writer closure unsafe { arena.set_len(capacity); } From 07c347170c370bc7f214ccfdf61e73b67cded537 Mon Sep 17 00:00:00 2001 From: Michal Piatkowski <291740709+MassivePizza@users.noreply.github.com> Date: Mon, 20 Jul 2026 21:32:34 +0200 Subject: [PATCH 7/7] Make changes compatible with MSRV 1.85. Revert this when MSRV is bumped to at least 1.93. --- parquet/src/arrow/arrow_writer/mod.rs | 34 ++++++++++----------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/parquet/src/arrow/arrow_writer/mod.rs b/parquet/src/arrow/arrow_writer/mod.rs index 319cf9840cc8..207b4c3327ef 100644 --- a/parquet/src/arrow/arrow_writer/mod.rs +++ b/parquet/src/arrow/arrow_writer/mod.rs @@ -21,7 +21,6 @@ use crate::column::chunker::ContentDefinedChunker; use bytes::Bytes; use std::io::Write; -use std::mem::MaybeUninit; use std::slice::Iter; use std::sync::{Arc, Mutex}; use std::vec::IntoIter; @@ -1823,10 +1822,8 @@ fn get_interval_ym_array_slice( indices: impl ExactSizeIterator, ) -> Vec { chunk_array_slice(12, indices, move |i, chunk| { - let mut out = [0; 12]; let value = array.value(i); - out[0..4].copy_from_slice(&value.to_le_bytes()); - chunk.write_copy_of_slice(&out) + chunk[0..4].copy_from_slice(&value.to_le_bytes()); }) } @@ -1837,11 +1834,9 @@ fn get_interval_dt_array_slice( indices: impl ExactSizeIterator, ) -> Vec { chunk_array_slice(12, indices, move |i, chunk| { - let mut out = [0; 12]; let value = array.value(i); - out[4..8].copy_from_slice(&value.days.to_le_bytes()); - out[8..12].copy_from_slice(&value.milliseconds.to_le_bytes()); - chunk.write_copy_of_slice(&out) + chunk[4..8].copy_from_slice(&value.days.to_le_bytes()); + chunk[8..12].copy_from_slice(&value.milliseconds.to_le_bytes()); }) } @@ -1890,13 +1885,13 @@ fn get_decimal_array_slice( // Special-case that allows inlining memcpy. chunk_array_slice(chunk_size, indices, move |i, chunk| { let as_be_bytes = T::to_be_bytes(array.value(i)); - chunk.write_copy_of_slice(as_be_bytes.as_ref()) + chunk.copy_from_slice(as_be_bytes.as_ref()); }) } else { chunk_array_slice(chunk_size, indices, move |i, chunk| { let as_be_bytes = T::to_be_bytes(array.value(i)); let resized_value = &as_be_bytes.as_ref()[(T::BYTE_LENGTH - chunk.len())..]; - chunk.write_copy_of_slice(resized_value) + chunk.copy_from_slice(resized_value); }) } } @@ -1907,7 +1902,7 @@ fn get_float_16_array_slice( ) -> Vec { chunk_array_slice(2, indices, move |i, chunk| { let value = array.value(i).to_le_bytes(); - chunk.write_copy_of_slice(&value) + chunk.copy_from_slice(&value); }) } @@ -1917,7 +1912,7 @@ fn get_fsb_array_slice( ) -> Vec { chunk_array_slice(array.value_size(), indices, move |i, chunk| { let value = array.value(i); - chunk.write_copy_of_slice(value) + chunk.copy_from_slice(value); }) } @@ -1925,17 +1920,14 @@ fn get_fsb_array_slice( fn chunk_array_slice( chunk_size: usize, indices: impl ExactSizeIterator, - writer: impl Fn(usize, &mut [MaybeUninit]) -> &mut [u8], + writer: impl Fn(usize, &mut [u8]), ) -> Vec { let capacity = indices.len() * chunk_size; - let mut arena = Vec::with_capacity(capacity); - for (i, chunk) in indices.zip(arena.spare_capacity_mut().chunks_exact_mut(chunk_size)) { - let filled_chunk = writer(i, chunk); - assert_eq!(filled_chunk.len(), chunk_size); - } - // SAFETY: all chunks were initialized with writer closure - unsafe { - arena.set_len(capacity); + // TODO: This could be done with Vec::spare_capacity_mut, + // but [MaybeUninit]::write_copy_of_slice is gated behind MSRV 1.93 + let mut arena = vec![0; capacity]; + for (i, chunk) in indices.zip(arena.chunks_exact_mut(chunk_size)) { + writer(i, chunk); } chunk_contiguous_vec(arena, chunk_size) }