diff --git a/crates/polars-arrow/src/array/growable/binary.rs b/crates/polars-arrow/src/array/growable/binary.rs index a91590a6984c..f0b746de2535 100644 --- a/crates/polars-arrow/src/array/growable/binary.rs +++ b/crates/polars-arrow/src/array/growable/binary.rs @@ -1,5 +1,7 @@ use std::sync::Arc; +use polars_utils::slice::GetSaferUnchecked; + use super::utils::extend_offset_values; use super::Growable; use crate::array::growable::utils::{extend_validity, prepare_validity}; @@ -55,8 +57,8 @@ impl<'a, O: Offset> GrowableBinary<'a, O> { } impl<'a, O: Offset> Growable<'a> for GrowableBinary<'a, O> { - fn extend(&mut self, index: usize, start: usize, len: usize) { - let array = self.arrays[index]; + unsafe fn extend(&mut self, index: usize, start: usize, len: usize) { + let array = *self.arrays.get_unchecked_release(index); extend_validity(&mut self.validity, array, start, len); let offsets = array.offsets(); diff --git a/crates/polars-arrow/src/array/growable/binview.rs b/crates/polars-arrow/src/array/growable/binview.rs index 11e60b58705d..9d4230e5e705 100644 --- a/crates/polars-arrow/src/array/growable/binview.rs +++ b/crates/polars-arrow/src/array/growable/binview.rs @@ -137,8 +137,7 @@ impl<'a, T: ViewType + ?Sized> GrowableBinaryViewArray<'a, T> { } impl<'a, T: ViewType + ?Sized> Growable<'a> for GrowableBinaryViewArray<'a, T> { - fn extend(&mut self, index: usize, start: usize, len: usize) { - assert!(index < self.arrays.len()); + unsafe fn extend(&mut self, index: usize, start: usize, len: usize) { unsafe { self.extend_unchecked(index, start, len) } } diff --git a/crates/polars-arrow/src/array/growable/boolean.rs b/crates/polars-arrow/src/array/growable/boolean.rs index 47b3f66c8d44..e293d0051ca8 100644 --- a/crates/polars-arrow/src/array/growable/boolean.rs +++ b/crates/polars-arrow/src/array/growable/boolean.rs @@ -1,5 +1,7 @@ use std::sync::Arc; +use polars_utils::slice::GetSaferUnchecked; + use super::Growable; use crate::array::growable::utils::{extend_validity, prepare_validity}; use crate::array::{Array, BooleanArray}; @@ -48,8 +50,8 @@ impl<'a> GrowableBoolean<'a> { } impl<'a> Growable<'a> for GrowableBoolean<'a> { - fn extend(&mut self, index: usize, start: usize, len: usize) { - let array = self.arrays[index]; + unsafe fn extend(&mut self, index: usize, start: usize, len: usize) { + let array = *self.arrays.get_unchecked_release(index); extend_validity(&mut self.validity, array, start, len); let values = array.values(); diff --git a/crates/polars-arrow/src/array/growable/dictionary.rs b/crates/polars-arrow/src/array/growable/dictionary.rs index 38817215e041..3c08b1cd65d9 100644 --- a/crates/polars-arrow/src/array/growable/dictionary.rs +++ b/crates/polars-arrow/src/array/growable/dictionary.rs @@ -1,5 +1,7 @@ use std::sync::Arc; +use polars_utils::slice::GetSaferUnchecked; + use super::{make_growable, Growable}; use crate::array::growable::utils::{extend_validity, prepare_validity}; use crate::array::{Array, DictionaryArray, DictionaryKey, PrimitiveArray}; @@ -28,7 +30,7 @@ fn concatenate_values( let mut offsets = Vec::with_capacity(arrays_keys.len() + 1); offsets.push(0); for (i, values) in arrays_values.iter().enumerate() { - mutable.extend(i, 0, values.len()); + unsafe { mutable.extend(i, 0, values.len()) }; offsets.push(offsets[i] + values.len()); } (mutable.as_box(), offsets) @@ -94,12 +96,14 @@ impl<'a, T: DictionaryKey> GrowableDictionary<'a, T> { impl<'a, T: DictionaryKey> Growable<'a> for GrowableDictionary<'a, T> { #[inline] - fn extend(&mut self, index: usize, start: usize, len: usize) { - let keys_array = self.keys[index]; + unsafe fn extend(&mut self, index: usize, start: usize, len: usize) { + let keys_array = *self.keys.get_unchecked_release(index); extend_validity(&mut self.validity, keys_array, start, len); - let values = &keys_array.values()[start..start + len]; - let offset = self.offsets[index]; + let values = &keys_array + .values() + .get_unchecked_release(start..start + len); + let offset = self.offsets.get_unchecked_release(index); self.key_values.extend( values .iter() diff --git a/crates/polars-arrow/src/array/growable/fixed_binary.rs b/crates/polars-arrow/src/array/growable/fixed_binary.rs index 3de21930b3c3..0f52fcd51410 100644 --- a/crates/polars-arrow/src/array/growable/fixed_binary.rs +++ b/crates/polars-arrow/src/array/growable/fixed_binary.rs @@ -1,5 +1,7 @@ use std::sync::Arc; +use polars_utils::slice::GetSaferUnchecked; + use super::Growable; use crate::array::growable::utils::{extend_validity, prepare_validity}; use crate::array::{Array, FixedSizeBinaryArray}; @@ -50,14 +52,15 @@ impl<'a> GrowableFixedSizeBinary<'a> { } impl<'a> Growable<'a> for GrowableFixedSizeBinary<'a> { - fn extend(&mut self, index: usize, start: usize, len: usize) { - let array = self.arrays[index]; + unsafe fn extend(&mut self, index: usize, start: usize, len: usize) { + let array = *self.arrays.get_unchecked_release(index); extend_validity(&mut self.validity, array, start, len); let values = array.values(); - self.values - .extend_from_slice(&values[start * self.size..start * self.size + len * self.size]); + self.values.extend_from_slice( + values.get_unchecked_release(start * self.size..start * self.size + len * self.size), + ); } fn extend_validity(&mut self, additional: usize) { diff --git a/crates/polars-arrow/src/array/growable/fixed_size_list.rs b/crates/polars-arrow/src/array/growable/fixed_size_list.rs index d8d6e48396a1..8226f1867b68 100644 --- a/crates/polars-arrow/src/array/growable/fixed_size_list.rs +++ b/crates/polars-arrow/src/array/growable/fixed_size_list.rs @@ -1,5 +1,7 @@ use std::sync::Arc; +use polars_utils::slice::GetSaferUnchecked; + use super::{make_growable, Growable}; use crate::array::growable::utils::{extend_validity, prepare_validity}; use crate::array::{Array, FixedSizeListArray}; @@ -66,8 +68,8 @@ impl<'a> GrowableFixedSizeList<'a> { } impl<'a> Growable<'a> for GrowableFixedSizeList<'a> { - fn extend(&mut self, index: usize, start: usize, len: usize) { - let array = self.arrays[index]; + unsafe fn extend(&mut self, index: usize, start: usize, len: usize) { + let array = *self.arrays.get_unchecked_release(index); extend_validity(&mut self.validity, array, start, len); self.values diff --git a/crates/polars-arrow/src/array/growable/list.rs b/crates/polars-arrow/src/array/growable/list.rs index 59a850232050..30aa1a2d2c7f 100644 --- a/crates/polars-arrow/src/array/growable/list.rs +++ b/crates/polars-arrow/src/array/growable/list.rs @@ -1,12 +1,14 @@ use std::sync::Arc; +use polars_utils::slice::GetSaferUnchecked; + use super::{make_growable, Growable}; use crate::array::growable::utils::{extend_validity, prepare_validity}; use crate::array::{Array, ListArray}; use crate::bitmap::MutableBitmap; use crate::offset::{Offset, Offsets}; -fn extend_offset_values( +unsafe fn extend_offset_values( growable: &mut GrowableList<'_, O>, index: usize, start: usize, @@ -20,8 +22,11 @@ fn extend_offset_values( .try_extend_from_slice(offsets, start, len) .unwrap(); - let end = offsets.buffer()[start + len].to_usize(); - let start = offsets.buffer()[start].to_usize(); + let end = offsets + .buffer() + .get_unchecked_release(start + len) + .to_usize(); + let start = offsets.buffer().get_unchecked_release(start).to_usize(); let len = end - start; growable.values.extend(index, start, len); } @@ -74,8 +79,8 @@ impl<'a, O: Offset> GrowableList<'a, O> { } impl<'a, O: Offset> Growable<'a> for GrowableList<'a, O> { - fn extend(&mut self, index: usize, start: usize, len: usize) { - let array = self.arrays[index]; + unsafe fn extend(&mut self, index: usize, start: usize, len: usize) { + let array = *self.arrays.get_unchecked_release(index); extend_validity(&mut self.validity, array, start, len); extend_offset_values::(self, index, start, len); } diff --git a/crates/polars-arrow/src/array/growable/map.rs b/crates/polars-arrow/src/array/growable/map.rs deleted file mode 100644 index 92eab04d6da0..000000000000 --- a/crates/polars-arrow/src/array/growable/map.rs +++ /dev/null @@ -1,103 +0,0 @@ -use std::sync::Arc; - -use super::{make_growable, Growable}; -use crate::array::growable::utils::{extend_validity, prepare_validity}; -use crate::array::{Array, MapArray}; -use crate::bitmap::MutableBitmap; -use crate::offset::Offsets; - -fn extend_offset_values(growable: &mut GrowableMap<'_>, index: usize, start: usize, len: usize) { - let array = growable.arrays[index]; - let offsets = array.offsets(); - - growable - .offsets - .try_extend_from_slice(offsets, start, len) - .unwrap(); - - let end = offsets.buffer()[start + len] as usize; - let start = offsets.buffer()[start] as usize; - let len = end - start; - growable.values.extend(index, start, len); -} - -/// Concrete [`Growable`] for the [`MapArray`]. -pub struct GrowableMap<'a> { - arrays: Vec<&'a MapArray>, - validity: Option, - values: Box + 'a>, - offsets: Offsets, -} - -impl<'a> GrowableMap<'a> { - /// Creates a new [`GrowableMap`] bound to `arrays` with a pre-allocated `capacity`. - /// # Panics - /// If `arrays` is empty. - pub fn new(arrays: Vec<&'a MapArray>, mut use_validity: bool, capacity: usize) -> Self { - // if any of the arrays has nulls, insertions from any array requires setting bits - // as there is at least one array with nulls. - if !use_validity & arrays.iter().any(|array| array.null_count() > 0) { - use_validity = true; - }; - - let inner = arrays - .iter() - .map(|array| array.field().as_ref()) - .collect::>(); - let values = make_growable(&inner, use_validity, 0); - - Self { - arrays, - offsets: Offsets::with_capacity(capacity), - values, - validity: prepare_validity(use_validity, capacity), - } - } - - fn to(&mut self) -> MapArray { - let validity = std::mem::take(&mut self.validity); - let offsets = std::mem::take(&mut self.offsets); - let values = self.values.as_box(); - - MapArray::new( - self.arrays[0].data_type().clone(), - offsets.into(), - values, - validity.map(|v| v.into()), - ) - } -} - -impl<'a> Growable<'a> for GrowableMap<'a> { - fn extend(&mut self, index: usize, start: usize, len: usize) { - let array = self.arrays[index]; - extend_validity(&mut self.validity, array, start, len); - extend_offset_values(self, index, start, len); - } - - fn extend_validity(&mut self, additional: usize) { - self.offsets.extend_constant(additional); - if let Some(validity) = &mut self.validity { - validity.extend_constant(additional, false); - } - } - - #[inline] - fn len(&self) -> usize { - self.offsets.len() - 1 - } - - fn as_arc(&mut self) -> Arc { - Arc::new(self.to()) - } - - fn as_box(&mut self) -> Box { - Box::new(self.to()) - } -} - -impl<'a> From> for MapArray { - fn from(mut val: GrowableMap<'a>) -> Self { - val.to() - } -} diff --git a/crates/polars-arrow/src/array/growable/mod.rs b/crates/polars-arrow/src/array/growable/mod.rs index 4799d0384ed5..aea9cdd8789e 100644 --- a/crates/polars-arrow/src/array/growable/mod.rs +++ b/crates/polars-arrow/src/array/growable/mod.rs @@ -8,8 +8,6 @@ use crate::datatypes::*; mod binary; pub use binary::GrowableBinary; -mod union; -pub use union::GrowableUnion; mod boolean; pub use boolean::GrowableBoolean; mod fixed_binary; @@ -20,8 +18,6 @@ mod primitive; pub use primitive::GrowablePrimitive; mod list; pub use list::GrowableList; -mod map; -pub use map::GrowableMap; mod structure; pub use structure::GrowableStruct; mod fixed_size_list; @@ -41,11 +37,13 @@ mod utils; pub trait Growable<'a> { /// Extends this [`Growable`] with elements from the bounded [`Array`] at index `index` from /// a slice starting at `start` and length `len`. - /// # Panic - /// This function panics if the range is out of bounds, i.e. if `start + len >= array.len()`. - fn extend(&mut self, index: usize, start: usize, len: usize); + /// # Safety + /// Doesn't do any bound checks + unsafe fn extend(&mut self, index: usize, start: usize, len: usize); /// Extends this [`Growable`] with null elements, disregarding the bound arrays + /// # Safety + /// Doesn't do any bound checks fn extend_validity(&mut self, additional: usize); /// The current length of the [`Growable`]. @@ -155,13 +153,6 @@ pub fn make_growable<'a>( )) }) }, - Map => dyn_growable!(map::GrowableMap, arrays, use_validity, capacity), - Union => { - let arrays = arrays - .iter() - .map(|array| array.as_any().downcast_ref().unwrap()) - .collect::>(); - Box::new(union::GrowableUnion::new(arrays, capacity)) - }, + Union | Map => unimplemented!(), } } diff --git a/crates/polars-arrow/src/array/growable/null.rs b/crates/polars-arrow/src/array/growable/null.rs index 355040e85bfb..155f90d190aa 100644 --- a/crates/polars-arrow/src/array/growable/null.rs +++ b/crates/polars-arrow/src/array/growable/null.rs @@ -27,7 +27,7 @@ impl GrowableNull { } impl<'a> Growable<'a> for GrowableNull { - fn extend(&mut self, _: usize, _: usize, len: usize) { + unsafe fn extend(&mut self, _: usize, _: usize, len: usize) { self.length += len; } diff --git a/crates/polars-arrow/src/array/growable/primitive.rs b/crates/polars-arrow/src/array/growable/primitive.rs index 64273e4b9ff3..16f72cb868ee 100644 --- a/crates/polars-arrow/src/array/growable/primitive.rs +++ b/crates/polars-arrow/src/array/growable/primitive.rs @@ -1,5 +1,7 @@ use std::sync::Arc; +use polars_utils::slice::GetSaferUnchecked; + use super::Growable; use crate::array::growable::utils::{extend_validity, prepare_validity}; use crate::array::{Array, PrimitiveArray}; @@ -55,12 +57,13 @@ impl<'a, T: NativeType> GrowablePrimitive<'a, T> { impl<'a, T: NativeType> Growable<'a> for GrowablePrimitive<'a, T> { #[inline] - fn extend(&mut self, index: usize, start: usize, len: usize) { - let array = self.arrays[index]; + unsafe fn extend(&mut self, index: usize, start: usize, len: usize) { + let array = *self.arrays.get_unchecked_release(index); extend_validity(&mut self.validity, array, start, len); let values = array.values().as_slice(); - self.values.extend_from_slice(&values[start..start + len]); + self.values + .extend_from_slice(values.get_unchecked_release(start..start + len)); } #[inline] diff --git a/crates/polars-arrow/src/array/growable/structure.rs b/crates/polars-arrow/src/array/growable/structure.rs index fddd009ef921..a27a9cfe6bee 100644 --- a/crates/polars-arrow/src/array/growable/structure.rs +++ b/crates/polars-arrow/src/array/growable/structure.rs @@ -1,5 +1,7 @@ use std::sync::Arc; +use polars_utils::slice::GetSaferUnchecked; + use super::{make_growable, Growable}; use crate::array::growable::utils::{extend_validity, prepare_validity}; use crate::array::{Array, StructArray}; @@ -65,8 +67,8 @@ impl<'a> GrowableStruct<'a> { } impl<'a> Growable<'a> for GrowableStruct<'a> { - fn extend(&mut self, index: usize, start: usize, len: usize) { - let array = self.arrays[index]; + unsafe fn extend(&mut self, index: usize, start: usize, len: usize) { + let array = *self.arrays.get_unchecked_release(index); extend_validity(&mut self.validity, array, start, len); if array.null_count() == 0 { diff --git a/crates/polars-arrow/src/array/growable/union.rs b/crates/polars-arrow/src/array/growable/union.rs deleted file mode 100644 index 4ef39f16fbb3..000000000000 --- a/crates/polars-arrow/src/array/growable/union.rs +++ /dev/null @@ -1,120 +0,0 @@ -use std::sync::Arc; - -use super::{make_growable, Growable}; -use crate::array::{Array, UnionArray}; - -/// Concrete [`Growable`] for the [`UnionArray`]. -pub struct GrowableUnion<'a> { - arrays: Vec<&'a UnionArray>, - types: Vec, - offsets: Option>, - fields: Vec + 'a>>, -} - -impl<'a> GrowableUnion<'a> { - /// Creates a new [`GrowableUnion`] bound to `arrays` with a pre-allocated `capacity`. - /// # Panics - /// Panics iff - /// * `arrays` is empty. - /// * any of the arrays has a different - pub fn new(arrays: Vec<&'a UnionArray>, capacity: usize) -> Self { - let first = arrays[0].data_type(); - assert!(arrays.iter().all(|x| x.data_type() == first)); - - let has_offsets = arrays[0].offsets().is_some(); - - let fields = (0..arrays[0].fields().len()) - .map(|i| { - make_growable( - &arrays - .iter() - .map(|x| x.fields()[i].as_ref()) - .collect::>(), - false, - capacity, - ) - }) - .collect::>>(); - - Self { - arrays, - fields, - offsets: if has_offsets { - Some(Vec::with_capacity(capacity)) - } else { - None - }, - types: Vec::with_capacity(capacity), - } - } - - fn to(&mut self) -> UnionArray { - let types = std::mem::take(&mut self.types); - let fields = std::mem::take(&mut self.fields); - let offsets = std::mem::take(&mut self.offsets); - let fields = fields.into_iter().map(|mut x| x.as_box()).collect(); - - UnionArray::new( - self.arrays[0].data_type().clone(), - types.into(), - fields, - offsets.map(|x| x.into()), - ) - } -} - -impl<'a> Growable<'a> for GrowableUnion<'a> { - fn extend(&mut self, index: usize, start: usize, len: usize) { - let array = self.arrays[index]; - - let types = &array.types()[start..start + len]; - self.types.extend(types); - if let Some(x) = self.offsets.as_mut() { - let offsets = &array.offsets().unwrap()[start..start + len]; - - // in a dense union, each slot has its own offset. We extend the fields accordingly. - for (&type_, &offset) in types.iter().zip(offsets.iter()) { - let field = &mut self.fields[type_ as usize]; - // The offset for the element that is about to be extended is the current length - // of the child field of the corresponding type. Note that this may be very - // different than the original offset from the array we are extending from as - // it is a function of the previous extensions to this child. - x.push(field.len() as i32); - field.extend(index, offset as usize, 1); - } - } else { - // in a sparse union, every field has the same length => extend all fields equally - self.fields - .iter_mut() - .for_each(|field| field.extend(index, start, len)) - } - } - - fn extend_validity(&mut self, _additional: usize) {} - - #[inline] - fn len(&self) -> usize { - self.types.len() - } - - fn as_arc(&mut self) -> Arc { - self.to().arced() - } - - fn as_box(&mut self) -> Box { - self.to().boxed() - } -} - -impl<'a> From> for UnionArray { - fn from(val: GrowableUnion<'a>) -> Self { - let fields = val.fields.into_iter().map(|mut x| x.as_box()).collect(); - - UnionArray::new( - val.arrays[0].data_type().clone(), - val.types.into(), - fields, - val.offsets.map(|x| x.into()), - ) - } -} diff --git a/crates/polars-arrow/src/array/growable/utf8.rs b/crates/polars-arrow/src/array/growable/utf8.rs index b01aab8b83bf..f4e4e762fc67 100644 --- a/crates/polars-arrow/src/array/growable/utf8.rs +++ b/crates/polars-arrow/src/array/growable/utf8.rs @@ -1,5 +1,7 @@ use std::sync::Arc; +use polars_utils::slice::GetSaferUnchecked; + use super::utils::extend_offset_values; use super::Growable; use crate::array::growable::utils::{extend_validity, prepare_validity}; @@ -56,8 +58,8 @@ impl<'a, O: Offset> GrowableUtf8<'a, O> { } impl<'a, O: Offset> Growable<'a> for GrowableUtf8<'a, O> { - fn extend(&mut self, index: usize, start: usize, len: usize) { - let array = self.arrays[index]; + unsafe fn extend(&mut self, index: usize, start: usize, len: usize) { + let array = *self.arrays.get_unchecked_release(index); extend_validity(&mut self.validity, array, start, len); let offsets = array.offsets(); diff --git a/crates/polars-arrow/src/array/growable/utils.rs b/crates/polars-arrow/src/array/growable/utils.rs index 6eb3f85a0b1d..7357f661b199 100644 --- a/crates/polars-arrow/src/array/growable/utils.rs +++ b/crates/polars-arrow/src/array/growable/utils.rs @@ -1,18 +1,20 @@ +use polars_utils::slice::GetSaferUnchecked; + use crate::array::Array; use crate::bitmap::MutableBitmap; use crate::offset::Offset; #[inline] -pub(super) fn extend_offset_values( +pub(super) unsafe fn extend_offset_values( buffer: &mut Vec, offsets: &[O], values: &[u8], start: usize, len: usize, ) { - let start_values = offsets[start].to_usize(); - let end_values = offsets[start + len].to_usize(); - let new_values = &values[start_values..end_values]; + let start_values = offsets.get_unchecked_release(start).to_usize(); + let end_values = offsets.get_unchecked_release(start + len).to_usize(); + let new_values = &values.get_unchecked_release(start_values..end_values); buffer.extend_from_slice(new_values); } diff --git a/crates/polars-arrow/src/compute/cast/dictionary_to.rs b/crates/polars-arrow/src/compute/cast/dictionary_to.rs index e69cf8c87c60..d29dbe3fdd94 100644 --- a/crates/polars-arrow/src/compute/cast/dictionary_to.rs +++ b/crates/polars-arrow/src/compute/cast/dictionary_to.rs @@ -3,7 +3,7 @@ use polars_error::{polars_bail, PolarsResult}; use super::{primitive_as_primitive, primitive_to_primitive, CastOptions}; use crate::array::{Array, DictionaryArray, DictionaryKey, PrimitiveArray}; use crate::compute::cast::cast; -use crate::compute::take::take; +use crate::compute::take::take_unchecked; use crate::datatypes::ArrowDataType; use crate::match_integer_type; @@ -168,7 +168,7 @@ where // take requires first casting i32 let indices = primitive_to_primitive::<_, i32>(keys, &ArrowDataType::Int32); - take(values.as_ref(), &indices) + Ok(unsafe { take_unchecked(values.as_ref(), &indices) }) } /// Casts a [`DictionaryArray`] to its values' [`ArrowDataType`], also known as unpacking. @@ -180,6 +180,7 @@ where // take requires first casting i64 let indices = primitive_to_primitive::<_, i64>(from.keys(), &ArrowDataType::Int64); - // unwrap: The dictionary guarantees that the keys are not out-of-bounds. - take(from.values().as_ref(), &indices).unwrap() + // SAFETY: + // The dictionary guarantees that the keys are not out-of-bounds. + unsafe { take_unchecked(from.values().as_ref(), &indices) } } diff --git a/crates/polars-arrow/src/compute/concatenate.rs b/crates/polars-arrow/src/compute/concatenate.rs index 5cabcca2c3e8..0f4d394f3915 100644 --- a/crates/polars-arrow/src/compute/concatenate.rs +++ b/crates/polars-arrow/src/compute/concatenate.rs @@ -38,7 +38,8 @@ pub fn concatenate(arrays: &[&dyn Array]) -> PolarsResult> { let mut mutable = make_growable(arrays, false, capacity); for (i, len) in lengths.iter().enumerate() { - mutable.extend(i, 0, *len) + // SAFETY: len is correct + unsafe { mutable.extend(i, 0, *len) } } Ok(mutable.as_box()) diff --git a/crates/polars-arrow/src/compute/if_then_else.rs b/crates/polars-arrow/src/compute/if_then_else.rs index 9433f431fb19..834a1fefad3a 100644 --- a/crates/polars-arrow/src/compute/if_then_else.rs +++ b/crates/polars-arrow/src/compute/if_then_else.rs @@ -31,7 +31,7 @@ pub fn if_then_else( let mut growable = growable::make_growable(&[lhs, rhs], true, lhs.len()); for (i, v) in predicate.iter().enumerate() { match v { - Some(v) => growable.extend(!v as usize, i, 1), + Some(v) => unsafe { growable.extend(!v as usize, i, 1) }, None => growable.extend_validity(1), } } @@ -42,15 +42,15 @@ pub fn if_then_else( let mut total_len = 0; for (start, len) in SlicesIterator::new(predicate.values()) { if start != start_falsy { - growable.extend(1, start_falsy, start - start_falsy); + unsafe { growable.extend(1, start_falsy, start - start_falsy) }; total_len += start - start_falsy; }; - growable.extend(0, start, len); + unsafe { growable.extend(0, start, len) }; total_len += len; start_falsy = start + len; } if total_len != lhs.len() { - growable.extend(1, total_len, lhs.len() - total_len); + unsafe { growable.extend(1, total_len, lhs.len() - total_len) }; } growable.as_box() }; diff --git a/crates/polars-arrow/src/compute/take/binary.rs b/crates/polars-arrow/src/compute/take/binary.rs index 0e6460206f0e..fa0a1ceb4b57 100644 --- a/crates/polars-arrow/src/compute/take/binary.rs +++ b/crates/polars-arrow/src/compute/take/binary.rs @@ -21,7 +21,7 @@ use crate::array::{Array, BinaryArray, PrimitiveArray}; use crate::offset::Offset; /// `take` implementation for utf8 arrays -pub fn take( +pub unsafe fn take_unchecked( values: &BinaryArray, indices: &PrimitiveArray, ) -> BinaryArray { @@ -37,5 +37,5 @@ pub fn take( (false, true) => take_indices_validity(values.offsets(), values.values(), indices), (true, true) => take_values_indices_validity(values, indices), }; - BinaryArray::::new(data_type, offsets, values, validity) + BinaryArray::::new_unchecked(data_type, offsets, values, validity) } diff --git a/crates/polars-arrow/src/compute/take/boolean.rs b/crates/polars-arrow/src/compute/take/boolean.rs index 62be88e46226..45971d995c8a 100644 --- a/crates/polars-arrow/src/compute/take/boolean.rs +++ b/crates/polars-arrow/src/compute/take/boolean.rs @@ -3,35 +3,37 @@ use crate::array::{Array, BooleanArray, PrimitiveArray}; use crate::bitmap::{Bitmap, MutableBitmap}; // take implementation when neither values nor indices contain nulls -fn take_no_validity(values: &Bitmap, indices: &[I]) -> (Bitmap, Option) { - let values = indices.iter().map(|index| values.get_bit(index.to_usize())); +unsafe fn take_no_validity(values: &Bitmap, indices: &[I]) -> (Bitmap, Option) { + let values = indices + .iter() + .map(|index| values.get_bit_unchecked(index.to_usize())); let buffer = Bitmap::from_trusted_len_iter(values); (buffer, None) } // take implementation when only values contain nulls -fn take_values_validity( +unsafe fn take_values_validity( values: &BooleanArray, indices: &[I], ) -> (Bitmap, Option) { let validity_values = values.validity().unwrap(); let validity = indices .iter() - .map(|index| validity_values.get_bit(index.to_usize())); + .map(|index| validity_values.get_bit_unchecked(index.to_usize())); let validity = Bitmap::from_trusted_len_iter(validity); let values_values = values.values(); let values = indices .iter() - .map(|index| values_values.get_bit(index.to_usize())); + .map(|index| values_values.get_bit_unchecked(index.to_usize())); let buffer = Bitmap::from_trusted_len_iter(values); (buffer, validity.into()) } // take implementation when only indices contain nulls -fn take_indices_validity( +pub(super) unsafe fn take_indices_validity( values: &Bitmap, indices: &PrimitiveArray, ) -> (Bitmap, Option) { @@ -41,13 +43,7 @@ fn take_indices_validity( let index = index.to_usize(); match values.get(index) { Some(value) => value, - None => { - if !validity.get_bit(i) { - false - } else { - panic!("Out-of-bounds index {index}") - } - }, + None => validity.get_bit_unchecked(i), } }); @@ -57,7 +53,7 @@ fn take_indices_validity( } // take implementation when both values and indices contain nulls -fn take_values_indices_validity( +unsafe fn take_values_indices_validity( values: &BooleanArray, indices: &PrimitiveArray, ) -> (Bitmap, Option) { @@ -69,8 +65,8 @@ fn take_values_indices_validity( let values = indices.iter().map(|index| match index { Some(index) => { let index = index.to_usize(); - validity.push(values_validity.get_bit(index)); - values_values.get_bit(index) + validity.push(values_validity.get_bit_unchecked(index)); + values_values.get_bit_unchecked(index) }, None => { validity.push(false); @@ -82,7 +78,10 @@ fn take_values_indices_validity( } /// `take` implementation for boolean arrays -pub fn take(values: &BooleanArray, indices: &PrimitiveArray) -> BooleanArray { +pub(super) unsafe fn take_unchecked( + values: &BooleanArray, + indices: &PrimitiveArray, +) -> BooleanArray { let data_type = values.data_type().clone(); let indices_has_validity = indices.null_count() > 0; let values_has_validity = values.null_count() > 0; @@ -96,43 +95,3 @@ pub fn take(values: &BooleanArray, indices: &PrimitiveArray) -> Boo BooleanArray::new(data_type, values, validity) } - -#[cfg(test)] -mod tests { - use super::*; - use crate::array::Int32Array; - - fn _all_cases() -> Vec<(Int32Array, BooleanArray, BooleanArray)> { - vec![ - ( - Int32Array::from(&[Some(1), Some(0)]), - BooleanArray::from(vec![Some(true), Some(false)]), - BooleanArray::from(vec![Some(false), Some(true)]), - ), - ( - Int32Array::from(&[Some(1), None]), - BooleanArray::from(vec![Some(true), Some(false)]), - BooleanArray::from(vec![Some(false), None]), - ), - ( - Int32Array::from(&[Some(1), Some(0)]), - BooleanArray::from(vec![None, Some(false)]), - BooleanArray::from(vec![Some(false), None]), - ), - ( - Int32Array::from(&[Some(1), None, Some(0)]), - BooleanArray::from(vec![None, Some(false)]), - BooleanArray::from(vec![Some(false), None, None]), - ), - ] - } - - #[test] - fn all_cases() { - let cases = _all_cases(); - for (indices, input, expected) in cases { - let output = take(&input, &indices); - assert_eq!(expected, output); - } - } -} diff --git a/crates/polars-arrow/src/compute/take/dict.rs b/crates/polars-arrow/src/compute/take/dict.rs index bb60c09193f7..e000aff57344 100644 --- a/crates/polars-arrow/src/compute/take/dict.rs +++ b/crates/polars-arrow/src/compute/take/dict.rs @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -use super::primitive::take as take_primitive; +use super::primitive::take_unchecked as take_primitive; use super::Index; use crate::array::{DictionaryArray, DictionaryKey, PrimitiveArray}; @@ -23,7 +23,10 @@ use crate::array::{DictionaryArray, DictionaryKey, PrimitiveArray}; /// /// applies `take` to the keys of the dictionary array and returns a new dictionary array /// with the same dictionary values and reordered keys -pub fn take(values: &DictionaryArray, indices: &PrimitiveArray) -> DictionaryArray +pub(super) unsafe fn take_unchecked( + values: &DictionaryArray, + indices: &PrimitiveArray, +) -> DictionaryArray where K: DictionaryKey, I: Index, diff --git a/crates/polars-arrow/src/compute/take/fixed_size_list.rs b/crates/polars-arrow/src/compute/take/fixed_size_list.rs index 6e7e74b91720..9eccd4bc043b 100644 --- a/crates/polars-arrow/src/compute/take/fixed_size_list.rs +++ b/crates/polars-arrow/src/compute/take/fixed_size_list.rs @@ -20,7 +20,7 @@ use crate::array::growable::{Growable, GrowableFixedSizeList}; use crate::array::{FixedSizeListArray, PrimitiveArray}; /// `take` implementation for FixedSizeListArrays -pub fn take( +pub(super) unsafe fn take_unchecked( values: &FixedSizeListArray, indices: &PrimitiveArray, ) -> FixedSizeListArray { @@ -43,7 +43,7 @@ pub fn take( GrowableFixedSizeList::new(arrays, true, capacity); for index in 0..indices.len() { - if validity.get_bit(index) { + if validity.get_bit_unchecked(index) { growable.extend(index, 0, 1); } else { growable.extend_validity(1) diff --git a/crates/polars-arrow/src/compute/take/generic_binary.rs b/crates/polars-arrow/src/compute/take/generic_binary.rs index 9f6658c7d5a0..ac8d9d004ded 100644 --- a/crates/polars-arrow/src/compute/take/generic_binary.rs +++ b/crates/polars-arrow/src/compute/take/generic_binary.rs @@ -1,10 +1,12 @@ +use polars_utils::slice::GetSaferUnchecked; + use super::Index; use crate::array::{GenericBinaryArray, PrimitiveArray}; use crate::bitmap::{Bitmap, MutableBitmap}; use crate::buffer::Buffer; use crate::offset::{Offset, Offsets, OffsetsBuffer}; -pub fn take_values( +pub(super) unsafe fn take_values( length: O, starts: &[O], offsets: &OffsetsBuffer, @@ -18,7 +20,7 @@ pub fn take_values( .zip(offsets.lengths()) .for_each(|(start, length)| { let end = start + length; - buffer.extend_from_slice(&values[start..end]); + buffer.extend_from_slice(values.get_unchecked(start..end)); }); buffer.into() } @@ -42,7 +44,7 @@ pub fn take_no_validity( } // take implementation when only values contain nulls -pub fn take_values_validity>( +pub(super) unsafe fn take_values_validity>( values: &A, indices: &[I], ) -> (OffsetsBuffer, Buffer, Option) { @@ -60,8 +62,8 @@ pub fn take_values_validity>( let mut starts = Vec::::with_capacity(indices.len()); let offsets = indices.iter().map(|index| { let index = index.to_usize(); - let start = offsets[index]; - length += offsets[index + 1] - start; + let start = *offsets.get_unchecked(index); + length += *offsets.get_unchecked(index + 1) - start; starts.push(start); length }); @@ -77,7 +79,7 @@ pub fn take_values_validity>( } // take implementation when only indices contain nulls -pub fn take_indices_validity( +pub(super) unsafe fn take_indices_validity( offsets: &OffsetsBuffer, values: &[u8], indices: &PrimitiveArray, @@ -91,7 +93,7 @@ pub fn take_indices_validity( let index = index.to_usize(); match offsets.get(index + 1) { Some(&next) => { - let start = offsets[index]; + let start = *offsets.get_unchecked(index); length += next - start; starts.push(start); }, @@ -111,7 +113,7 @@ pub fn take_indices_validity( } // take implementation when both indices and values contain nulls -pub fn take_values_indices_validity>( +pub(super) unsafe fn take_values_indices_validity>( values: &A, indices: &PrimitiveArray, ) -> (OffsetsBuffer, Buffer, Option) { @@ -129,8 +131,9 @@ pub fn take_values_indices_validity( +pub(super) unsafe fn take_unchecked( values: &ListArray, indices: &PrimitiveArray, ) -> ListArray { @@ -43,7 +43,7 @@ pub fn take( let mut growable: GrowableList = GrowableList::new(arrays, true, capacity); for index in 0..indices.len() { - if validity.get_bit(index) { + if validity.get_bit_unchecked(index) { growable.extend(index, 0, 1); } else { growable.extend_validity(1) diff --git a/crates/polars-arrow/src/compute/take/mod.rs b/crates/polars-arrow/src/compute/take/mod.rs index da28c762f353..1abf854a4a65 100644 --- a/crates/polars-arrow/src/compute/take/mod.rs +++ b/crates/polars-arrow/src/compute/take/mod.rs @@ -18,7 +18,6 @@ //! Defines take kernel for [`Array`] use crate::array::{new_empty_array, Array, NullArray, PrimitiveArray}; -use crate::datatypes::ArrowDataType; use crate::types::Index; mod binary; @@ -31,106 +30,57 @@ mod primitive; mod structure; mod utf8; -use polars_error::PolarsResult; - use crate::{match_integer_type, with_match_primitive_type}; /// Returns a new [`Array`] with only indices at `indices`. Null indices are taken as nulls. /// The returned array has a length equal to `indices.len()`. -pub fn take( +/// # Safety +/// Doesn't do bound checks +pub unsafe fn take_unchecked( values: &dyn Array, indices: &PrimitiveArray, -) -> PolarsResult> { +) -> Box { if indices.len() == 0 { - return Ok(new_empty_array(values.data_type().clone())); + return new_empty_array(values.data_type().clone()); } use crate::datatypes::PhysicalType::*; match values.data_type().to_physical_type() { - Null => Ok(Box::new(NullArray::new( - values.data_type().clone(), - indices.len(), - ))), + Null => Box::new(NullArray::new(values.data_type().clone(), indices.len())), Boolean => { let values = values.as_any().downcast_ref().unwrap(); - Ok(Box::new(boolean::take::(values, indices))) + Box::new(boolean::take_unchecked::(values, indices)) }, Primitive(primitive) => with_match_primitive_type!(primitive, |$T| { let values = values.as_any().downcast_ref().unwrap(); - Ok(Box::new(primitive::take::<$T, _>(&values, indices))) + Box::new(primitive::take_unchecked::<$T, _>(&values, indices)) }), LargeUtf8 => { let values = values.as_any().downcast_ref().unwrap(); - Ok(Box::new(utf8::take::(values, indices))) + Box::new(utf8::take_unchecked::(values, indices)) }, LargeBinary => { let values = values.as_any().downcast_ref().unwrap(); - Ok(Box::new(binary::take::(values, indices))) + Box::new(binary::take_unchecked::(values, indices)) }, Dictionary(key_type) => { match_integer_type!(key_type, |$T| { let values = values.as_any().downcast_ref().unwrap(); - Ok(Box::new(dict::take::<$T, _>(&values, indices))) + Box::new(dict::take_unchecked::<$T, _>(&values, indices)) }) }, Struct => { let array = values.as_any().downcast_ref().unwrap(); - Ok(Box::new(structure::take::<_>(array, indices)?)) + structure::take_unchecked::<_>(array, indices).boxed() }, LargeList => { let array = values.as_any().downcast_ref().unwrap(); - Ok(Box::new(list::take::(array, indices))) + Box::new(list::take_unchecked::(array, indices)) }, FixedSizeList => { let array = values.as_any().downcast_ref().unwrap(); - Ok(Box::new(fixed_size_list::take::(array, indices))) + Box::new(fixed_size_list::take_unchecked::(array, indices)) }, t => unimplemented!("Take not supported for data type {:?}", t), } } - -/// Checks if an array of type `datatype` can perform take operation -/// -/// # Examples -/// ``` -/// use polars_arrow::compute::take::can_take; -/// use polars_arrow::datatypes::{ArrowDataType}; -/// -/// let data_type = ArrowDataType::Int8; -/// assert_eq!(can_take(&data_type), true); -/// ``` -pub fn can_take(data_type: &ArrowDataType) -> bool { - matches!( - data_type, - ArrowDataType::Null - | ArrowDataType::Boolean - | ArrowDataType::Int8 - | ArrowDataType::Int16 - | ArrowDataType::Int32 - | ArrowDataType::Date32 - | ArrowDataType::Time32(_) - | ArrowDataType::Interval(_) - | ArrowDataType::Int64 - | ArrowDataType::Date64 - | ArrowDataType::Time64(_) - | ArrowDataType::Duration(_) - | ArrowDataType::Timestamp(_, _) - | ArrowDataType::UInt8 - | ArrowDataType::UInt16 - | ArrowDataType::UInt32 - | ArrowDataType::UInt64 - | ArrowDataType::Float16 - | ArrowDataType::Float32 - | ArrowDataType::Float64 - | ArrowDataType::Decimal(_, _) - | ArrowDataType::Utf8 - | ArrowDataType::LargeUtf8 - | ArrowDataType::Binary - | ArrowDataType::LargeBinary - | ArrowDataType::Struct(_) - | ArrowDataType::List(_) - | ArrowDataType::LargeList(_) - | ArrowDataType::FixedSizeList(_, _) - | ArrowDataType::Dictionary(..) - ) -} diff --git a/crates/polars-arrow/src/compute/take/primitive.rs b/crates/polars-arrow/src/compute/take/primitive.rs index 5ce53ba7cc20..c8db6fac319c 100644 --- a/crates/polars-arrow/src/compute/take/primitive.rs +++ b/crates/polars-arrow/src/compute/take/primitive.rs @@ -5,20 +5,20 @@ use crate::buffer::Buffer; use crate::types::NativeType; // take implementation when neither values nor indices contain nulls -fn take_no_validity( +unsafe fn take_no_validity( values: &[T], indices: &[I], ) -> (Buffer, Option) { let values = indices .iter() - .map(|index| values[index.to_usize()]) + .map(|index| *values.get_unchecked(index.to_usize())) .collect::>(); (values.into(), None) } // take implementation when only values contain nulls -fn take_values_validity( +unsafe fn take_values_validity( values: &PrimitiveArray, indices: &[I], ) -> (Buffer, Option) { @@ -26,41 +26,30 @@ fn take_values_validity( let validity = indices .iter() - .map(|index| values_validity.get_bit(index.to_usize())); + .map(|index| values_validity.get_bit_unchecked(index.to_usize())); let validity = MutableBitmap::from_trusted_len_iter(validity); let values_values = values.values(); let values = indices .iter() - .map(|index| values_values[index.to_usize()]) + .map(|index| *values_values.get_unchecked(index.to_usize())) .collect::>(); (values.into(), validity.into()) } // take implementation when only indices contain nulls -fn take_indices_validity( +unsafe fn take_indices_validity( values: &[T], indices: &PrimitiveArray, ) -> (Buffer, Option) { - let validity = indices.validity().unwrap(); let values = indices .values() .iter() - .enumerate() - .map(|(i, index)| { + .map(|index| { let index = index.to_usize(); - match values.get(index) { - Some(value) => *value, - None => { - if !validity.get_bit(i) { - T::default() - } else { - panic!("Out-of-bounds index {index}") - } - }, - } + *values.get_unchecked(index) }) .collect::>(); @@ -68,7 +57,7 @@ fn take_indices_validity( } // take implementation when both values and indices contain nulls -fn take_values_indices_validity( +unsafe fn take_values_indices_validity( values: &PrimitiveArray, indices: &PrimitiveArray, ) -> (Buffer, Option) { @@ -82,8 +71,8 @@ fn take_values_indices_validity( .map(|index| match index { Some(index) => { let index = index.to_usize(); - bitmap.push(values_validity.get_bit(index)); - values_values[index] + bitmap.push(values_validity.get_bit_unchecked(index)); + *values_values.get_unchecked(index) }, None => { bitmap.push(false); @@ -95,7 +84,7 @@ fn take_values_indices_validity( } /// `take` implementation for primitive arrays -pub fn take( +pub(super) unsafe fn take_unchecked( values: &PrimitiveArray, indices: &PrimitiveArray, ) -> PrimitiveArray { diff --git a/crates/polars-arrow/src/compute/take/structure.rs b/crates/polars-arrow/src/compute/take/structure.rs index 63bfc8d65cc2..b186e5e0e352 100644 --- a/crates/polars-arrow/src/compute/take/structure.rs +++ b/crates/polars-arrow/src/compute/take/structure.rs @@ -15,53 +15,47 @@ // specific language governing permissions and limitations // under the License. -use polars_error::PolarsResult; - use super::Index; use crate::array::{Array, PrimitiveArray, StructArray}; use crate::bitmap::{Bitmap, MutableBitmap}; #[inline] -fn take_validity( +unsafe fn take_validity( validity: Option<&Bitmap>, indices: &PrimitiveArray, -) -> PolarsResult> { +) -> Option { let indices_validity = indices.validity(); match (validity, indices_validity) { - (None, _) => Ok(indices_validity.cloned()), + (None, _) => indices_validity.cloned(), (Some(validity), None) => { let iter = indices.values().iter().map(|index| { let index = index.to_usize(); - validity.get_bit(index) + validity.get_bit_unchecked(index) }); - Ok(MutableBitmap::from_trusted_len_iter(iter).into()) + MutableBitmap::from_trusted_len_iter(iter).into() }, (Some(validity), _) => { let iter = indices.iter().map(|x| match x { Some(index) => { let index = index.to_usize(); - validity.get_bit(index) + validity.get_bit_unchecked(index) }, None => false, }); - Ok(MutableBitmap::from_trusted_len_iter(iter).into()) + MutableBitmap::from_trusted_len_iter(iter).into() }, } } -pub fn take( +pub(super) unsafe fn take_unchecked( array: &StructArray, indices: &PrimitiveArray, -) -> PolarsResult { +) -> StructArray { let values: Vec> = array .values() .iter() - .map(|a| super::take(a.as_ref(), indices)) - .collect::>()?; - let validity = take_validity(array.validity(), indices)?; - Ok(StructArray::new( - array.data_type().clone(), - values, - validity, - )) + .map(|a| super::take_unchecked(a.as_ref(), indices)) + .collect(); + let validity = take_validity(array.validity(), indices); + StructArray::new(array.data_type().clone(), values, validity) } diff --git a/crates/polars-arrow/src/compute/take/utf8.rs b/crates/polars-arrow/src/compute/take/utf8.rs index 3f5f5877c12f..69806e0472ae 100644 --- a/crates/polars-arrow/src/compute/take/utf8.rs +++ b/crates/polars-arrow/src/compute/take/utf8.rs @@ -21,7 +21,7 @@ use crate::array::{Array, PrimitiveArray, Utf8Array}; use crate::offset::Offset; /// `take` implementation for utf8 arrays -pub fn take( +pub unsafe fn take_unchecked( values: &Utf8Array, indices: &PrimitiveArray, ) -> Utf8Array { @@ -39,48 +39,3 @@ pub fn take( }; unsafe { Utf8Array::::new_unchecked(data_type, offsets, values, validity) } } - -#[cfg(test)] -mod tests { - use super::*; - use crate::array::Int32Array; - - fn _all_cases() -> Vec<(Int32Array, Utf8Array, Utf8Array)> { - vec![ - ( - Int32Array::from(&[Some(1), Some(0)]), - Utf8Array::::from(vec![Some("one"), Some("two")]), - Utf8Array::::from(vec![Some("two"), Some("one")]), - ), - ( - Int32Array::from(&[Some(1), None]), - Utf8Array::::from(vec![Some("one"), Some("two")]), - Utf8Array::::from(vec![Some("two"), None]), - ), - ( - Int32Array::from(&[Some(1), Some(0)]), - Utf8Array::::from(vec![None, Some("two")]), - Utf8Array::::from(vec![Some("two"), None]), - ), - ( - Int32Array::from(&[Some(1), None, Some(0)]), - Utf8Array::::from(vec![None, Some("two")]), - Utf8Array::::from(vec![Some("two"), None, None]), - ), - ] - } - - #[test] - fn all_cases() { - let cases = _all_cases::(); - for (indices, input, expected) in cases { - let output = take(&input, &indices); - assert_eq!(expected, output); - } - let cases = _all_cases::(); - for (indices, input, expected) in cases { - let output = take(&input, &indices); - assert_eq!(expected, output); - } - } -} diff --git a/crates/polars-arrow/src/legacy/compute/take/mod.rs b/crates/polars-arrow/src/legacy/compute/take/mod.rs index f62cf97e57ab..cd3763dce117 100644 --- a/crates/polars-arrow/src/legacy/compute/take/mod.rs +++ b/crates/polars-arrow/src/legacy/compute/take/mod.rs @@ -51,8 +51,8 @@ pub unsafe fn take_unchecked(arr: &dyn Array, idx: &IdxArr) -> ArrayRef { // TODO! implement proper unchecked version #[cfg(feature = "compute")] _ => { - use crate::compute::take::take; - take(arr, idx).unwrap() + use crate::compute::take::take_unchecked; + take_unchecked(arr, idx) }, #[cfg(not(feature = "compute"))] _ => { diff --git a/crates/polars-arrow/src/legacy/kernels/concatenate.rs b/crates/polars-arrow/src/legacy/kernels/concatenate.rs index b90c40a74ec1..580358ce1c0b 100644 --- a/crates/polars-arrow/src/legacy/kernels/concatenate.rs +++ b/crates/polars-arrow/src/legacy/kernels/concatenate.rs @@ -26,7 +26,9 @@ pub fn concatenate_owned_unchecked(arrays: &[ArrayRef]) -> PolarsResult PolarsResult { let iter = SlicesIterator::new(mask.values()); let mut mutable = make_growable(&[array], false, iter.slots()); - iter.for_each(|(start, len)| mutable.extend(0, start, len)); + // SAFETY: + // we are in bounds + iter.for_each(|(start, len)| unsafe { mutable.extend(0, start, len) }); Ok(mutable.as_box()) }, }