@@ -9,12 +9,10 @@ use lending_iterator::gat;
99use lending_iterator:: prelude:: Item ;
1010#[ gat( Item ) ]
1111use lending_iterator:: prelude:: LendingIterator ;
12- use vortex_array:: builders:: UninitRange ;
1312use vortex_buffer:: ByteBuffer ;
1413use vortex_dtype:: PhysicalPType ;
1514
1615use crate :: BitPackedArray ;
17- use crate :: bitpacking:: bitpack_decompress:: BitPackingStrategy ;
1816
1917const CHUNK_SIZE : usize = 1024 ;
2018
@@ -28,6 +26,24 @@ pub trait UnpackStrategy<T: PhysicalPType> {
2826 unsafe fn unpack_chunk ( & self , bit_width : usize , chunk : & [ T :: Physical ] , dst : & mut [ T :: Physical ] ) ;
2927}
3028
29+ /// BitPacking strategy - uses plain bitpacking without reference value
30+ pub struct BitPackingStrategy ;
31+
32+ impl < T : PhysicalPType < Physical : BitPacking > > UnpackStrategy < T > for BitPackingStrategy {
33+ #[ inline( always) ]
34+ unsafe fn unpack_chunk (
35+ & self ,
36+ bit_width : usize ,
37+ chunk : & [ T :: Physical ] ,
38+ dst : & mut [ T :: Physical ] ,
39+ ) {
40+ // SAFETY: Caller must ensure [`BitPacking::unchecked_unpack`] safety requirements hold.
41+ unsafe {
42+ BitPacking :: unchecked_unpack ( bit_width, chunk, dst) ;
43+ }
44+ }
45+ }
46+
3147/// Accessor to unpacked chunks of bitpacked arrays
3248///
3349/// The usual pattern of usage should follow
@@ -159,29 +175,38 @@ impl<T: PhysicalPType, S: UnpackStrategy<T>> UnpackedChunks<T, S> {
159175
160176 /// Decode all chunks (initial, full, and trailer) into the output range.
161177 /// This consolidates the logic for handling all three chunk types in one place.
162- pub fn decode_into ( & mut self , output : & mut UninitRange < T > ) {
178+ pub fn decode_into ( & mut self , output : & mut [ MaybeUninit < T > ] ) {
163179 let mut local_idx = 0 ;
164180
165181 // Handle initial partial chunk if present
166182 if let Some ( initial) = self . initial ( ) {
167- output. copy_from_slice ( 0 , initial) ;
168183 local_idx = initial. len ( ) ;
184+
185+ // TODO(connor): use `maybe_uninit_write_slice` feature when it gets stabilized.
186+ // https://github.com/rust-lang/rust/issues/79995
187+ // SAFETY: &[T] and &[MaybeUninit<T>] have the same layout.
188+ let init_initial: & [ MaybeUninit < T > ] = unsafe { mem:: transmute ( initial) } ;
189+ output[ ..local_idx] . copy_from_slice ( init_initial) ;
169190 }
170191
171192 // Handle full chunks
172193 local_idx = self . decode_full_chunks_into_at ( output, local_idx) ;
173194
174195 // Handle trailing partial chunk if present
175196 if let Some ( trailer) = self . trailer ( ) {
176- output. copy_from_slice ( local_idx, trailer) ;
197+ // TODO(connor): use `maybe_uninit_write_slice` feature when it gets stabilized.
198+ // https://github.com/rust-lang/rust/issues/79995
199+ // SAFETY: &[T] and &[MaybeUninit<T>] have the same layout.
200+ let init_trailer: & [ MaybeUninit < T > ] = unsafe { mem:: transmute ( trailer) } ;
201+ output[ local_idx..] [ ..init_trailer. len ( ) ] . copy_from_slice ( init_trailer) ;
177202 }
178203 }
179204
180205 /// Unpack full chunks into output range starting at the given index.
181206 /// Returns the next local index to write to.
182207 fn decode_full_chunks_into_at (
183208 & mut self ,
184- output : & mut UninitRange < T > ,
209+ output : & mut [ MaybeUninit < T > ] ,
185210 start_idx : usize ,
186211 ) -> usize {
187212 // If there's only one chunk it has been handled already by `initial` method
@@ -204,8 +229,7 @@ impl<T: PhysicalPType, S: UnpackStrategy<T>> UnpackedChunks<T, S> {
204229 let chunk = & packed_slice[ i * elems_per_chunk..] [ ..elems_per_chunk] ;
205230
206231 unsafe {
207- // SAFETY: We're about to initialize CHUNK_SIZE elements at local_idx.
208- let uninit_dst = output. slice_uninit_mut ( local_idx, CHUNK_SIZE ) ;
232+ let uninit_dst = & mut output[ local_idx..local_idx + CHUNK_SIZE ] ;
209233 // SAFETY: &[T] and &[MaybeUninit<T>] have the same layout
210234 let dst: & mut [ T :: Physical ] = mem:: transmute ( uninit_dst) ;
211235 self . strategy . unpack_chunk ( self . bit_width , chunk, dst) ;
0 commit comments