@@ -56,6 +56,9 @@ pub(crate) trait DynArray: 'static + private::Sealed + Send + Sync + Debug {
5656 /// Returns the array as a reference to a generic [`Any`] trait object.
5757 fn as_any ( & self ) -> & dyn Any ;
5858
59+ /// Returns the array as a mutable reference to a generic [`Any`] trait object.
60+ fn as_any_mut ( & mut self ) -> & mut dyn Any ;
61+
5962 /// Converts an owned array allocation into an owned [`Any`] allocation for downcasting.
6063 fn into_any_arc ( self : std:: sync:: Arc < Self > ) -> std:: sync:: Arc < dyn Any + Send + Sync > ;
6164
@@ -143,6 +146,24 @@ pub(crate) trait DynArray: 'static + private::Sealed + Send + Sync + Debug {
143146 /// Returns a new array with the given slots.
144147 fn with_slots ( & self , this : ArrayRef , slots : Vec < Option < ArrayRef > > ) -> VortexResult < ArrayRef > ;
145148
149+ /// Returns a new array with the given slots, bypassing encoding-level validation.
150+ ///
151+ /// Used by the executor to temporarily carry an array that has had one of its child slots
152+ /// taken out (leaving `None`) without panicking `V::validate`. The caller must ensure the
153+ /// missing slot is filled back in (via `put_slot_unchecked`) or driven to completion by the
154+ /// builder path before the array becomes externally observable.
155+ ///
156+ /// # Safety
157+ ///
158+ /// The array returned may have slots whose content does not match the encoding's normal
159+ /// invariants. Callers must re-establish those invariants before handing the array to
160+ /// anything outside the executor.
161+ unsafe fn with_slots_unchecked (
162+ & self ,
163+ this : & ArrayRef ,
164+ slots : Vec < Option < ArrayRef > > ,
165+ ) -> ArrayRef ;
166+
146167 /// Attempt to reduce the array to a simpler representation.
147168 fn reduce ( & self , this : & ArrayRef ) -> VortexResult < Option < ArrayRef > > ;
148169
@@ -155,8 +176,26 @@ pub(crate) trait DynArray: 'static + private::Sealed + Send + Sync + Debug {
155176 ) -> VortexResult < Option < ArrayRef > > ;
156177
157178 /// Execute the array by taking a single encoding-specific execution step.
179+ ///
180+ /// This is the checked entry point. If the encoding reports
181+ /// [`ExecutionStep::Done`](crate::ExecutionStep::Done), implementations must validate that the
182+ /// returned array preserves this array's logical `len` and `dtype`, and must transfer this
183+ /// array's statistics to the returned array.
158184 fn execute ( & self , this : ArrayRef , ctx : & mut ExecutionCtx ) -> VortexResult < ExecutionResult > ;
159185
186+ /// Execute the array by taking a single encoding-specific execution step without applying
187+ /// `Done`-result postconditions.
188+ ///
189+ /// This exists for the iterative executor, which may call into `execute` on suspended
190+ /// executor-private arrays whose slots temporarily contain `None`. In that mode the executor
191+ /// itself is responsible for deciding when a `Done` result represents a real logical array,
192+ /// enforcing any `len`/`dtype` invariants, and transferring statistics.
193+ fn execute_unchecked (
194+ & self ,
195+ this : ArrayRef ,
196+ ctx : & mut ExecutionCtx ,
197+ ) -> VortexResult < ExecutionResult > ;
198+
160199 /// Attempt to execute the parent of this array.
161200 fn execute_parent (
162201 & self ,
@@ -203,6 +242,10 @@ impl<V: VTable> DynArray for ArrayInner<V> {
203242 self
204243 }
205244
245+ fn as_any_mut ( & mut self ) -> & mut dyn Any {
246+ self
247+ }
248+
206249 fn into_any_arc ( self : std:: sync:: Arc < Self > ) -> std:: sync:: Arc < dyn Any + Send + Sync > {
207250 self
208251 }
@@ -387,6 +430,26 @@ impl<V: VTable> DynArray for ArrayInner<V> {
387430 . into_array ( ) )
388431 }
389432
433+ unsafe fn with_slots_unchecked (
434+ & self ,
435+ this : & ArrayRef ,
436+ slots : Vec < Option < ArrayRef > > ,
437+ ) -> ArrayRef {
438+ // SAFETY: we intentionally skip `V::validate` here. Caller guarantees that the resulting
439+ // array is either repaired or not externally observed.
440+ let inner = unsafe {
441+ ArrayInner :: < V > :: from_data_unchecked (
442+ self . vtable . clone ( ) ,
443+ this. dtype ( ) . clone ( ) ,
444+ self . len ,
445+ self . data . clone ( ) ,
446+ slots,
447+ self . stats . clone ( ) ,
448+ )
449+ } ;
450+ ArrayRef :: from_inner ( std:: sync:: Arc :: new ( inner) )
451+ }
452+
390453 fn reduce ( & self , this : & ArrayRef ) -> VortexResult < Option < ArrayRef > > {
391454 let view = unsafe { ArrayView :: new_unchecked ( this, & self . data ) } ;
392455 let Some ( reduced) = V :: reduce ( view) ? else {
@@ -437,12 +500,8 @@ impl<V: VTable> DynArray for ArrayInner<V> {
437500 fn execute ( & self , this : ArrayRef , ctx : & mut ExecutionCtx ) -> VortexResult < ExecutionResult > {
438501 let len = this. len ( ) ;
439502 let dtype = this. dtype ( ) . clone ( ) ;
440- let stats = this. statistics ( ) . to_owned ( ) ;
441-
442- let typed = Array :: < V > :: try_from_array_ref ( this)
443- . map_err ( |_| vortex_err ! ( "Failed to downcast array for execute" ) )
444- . vortex_expect ( "Failed to downcast array for execute" ) ;
445- let result = V :: execute ( typed, ctx) ?;
503+ let stats = this. statistics ( ) . to_array_stats ( ) ;
504+ let result = self . execute_unchecked ( this, ctx) ?;
446505
447506 if matches ! ( result. step( ) , ExecutionStep :: Done ) {
448507 if cfg ! ( debug_assertions) {
@@ -458,12 +517,26 @@ impl<V: VTable> DynArray for ArrayInner<V> {
458517 ) ;
459518 }
460519
461- result. array ( ) . statistics ( ) . set_iter ( stats. into_iter ( ) ) ;
520+ result
521+ . array ( )
522+ . statistics ( )
523+ . set_iter ( crate :: stats:: StatsSet :: from ( stats) . into_iter ( ) ) ;
462524 }
463525
464526 Ok ( result)
465527 }
466528
529+ fn execute_unchecked (
530+ & self ,
531+ this : ArrayRef ,
532+ ctx : & mut ExecutionCtx ,
533+ ) -> VortexResult < ExecutionResult > {
534+ let typed = Array :: < V > :: try_from_array_ref ( this)
535+ . map_err ( |_| vortex_err ! ( "Failed to downcast array for execute" ) )
536+ . vortex_expect ( "Failed to downcast array for execute" ) ;
537+ V :: execute ( typed, ctx)
538+ }
539+
467540 fn execute_parent (
468541 & self ,
469542 this : & ArrayRef ,
0 commit comments