@@ -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,30 @@ 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+ ///
194+ /// # Safety
195+ /// The `array` returned should have it's `DType` and len checked
196+ /// (optionally it should have its stats propagated from `this`).
197+ unsafe fn execute_unchecked (
198+ & self ,
199+ this : ArrayRef ,
200+ ctx : & mut ExecutionCtx ,
201+ ) -> VortexResult < ExecutionResult > ;
202+
160203 /// Attempt to execute the parent of this array.
161204 fn execute_parent (
162205 & self ,
@@ -203,6 +246,10 @@ impl<V: VTable> DynArray for ArrayInner<V> {
203246 self
204247 }
205248
249+ fn as_any_mut ( & mut self ) -> & mut dyn Any {
250+ self
251+ }
252+
206253 fn into_any_arc ( self : std:: sync:: Arc < Self > ) -> std:: sync:: Arc < dyn Any + Send + Sync > {
207254 self
208255 }
@@ -387,6 +434,26 @@ impl<V: VTable> DynArray for ArrayInner<V> {
387434 . into_array ( ) )
388435 }
389436
437+ unsafe fn with_slots_unchecked (
438+ & self ,
439+ this : & ArrayRef ,
440+ slots : Vec < Option < ArrayRef > > ,
441+ ) -> ArrayRef {
442+ // SAFETY: we intentionally skip `V::validate` here. Caller guarantees that the resulting
443+ // array is either repaired or not externally observed.
444+ let inner = unsafe {
445+ ArrayInner :: < V > :: from_data_unchecked (
446+ self . vtable . clone ( ) ,
447+ this. dtype ( ) . clone ( ) ,
448+ self . len ,
449+ self . data . clone ( ) ,
450+ slots,
451+ self . stats . clone ( ) ,
452+ )
453+ } ;
454+ ArrayRef :: from_inner ( std:: sync:: Arc :: new ( inner) )
455+ }
456+
390457 fn reduce ( & self , this : & ArrayRef ) -> VortexResult < Option < ArrayRef > > {
391458 let view = unsafe { ArrayView :: new_unchecked ( this, & self . data ) } ;
392459 let Some ( reduced) = V :: reduce ( view) ? else {
@@ -437,12 +504,8 @@ impl<V: VTable> DynArray for ArrayInner<V> {
437504 fn execute ( & self , this : ArrayRef , ctx : & mut ExecutionCtx ) -> VortexResult < ExecutionResult > {
438505 let len = this. len ( ) ;
439506 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) ?;
507+ let stats = this. statistics ( ) . to_array_stats ( ) ;
508+ let result = self . execute_unchecked ( this, ctx) ?;
446509
447510 if matches ! ( result. step( ) , ExecutionStep :: Done ) {
448511 if cfg ! ( debug_assertions) {
@@ -458,12 +521,26 @@ impl<V: VTable> DynArray for ArrayInner<V> {
458521 ) ;
459522 }
460523
461- result. array ( ) . statistics ( ) . set_iter ( stats. into_iter ( ) ) ;
524+ result
525+ . array ( )
526+ . statistics ( )
527+ . set_iter ( crate :: stats:: StatsSet :: from ( stats) . into_iter ( ) ) ;
462528 }
463529
464530 Ok ( result)
465531 }
466532
533+ fn execute_unchecked (
534+ & self ,
535+ this : ArrayRef ,
536+ ctx : & mut ExecutionCtx ,
537+ ) -> VortexResult < ExecutionResult > {
538+ let typed = Array :: < V > :: try_from_array_ref ( this)
539+ . map_err ( |_| vortex_err ! ( "Failed to downcast array for execute" ) )
540+ . vortex_expect ( "Failed to downcast array for execute" ) ;
541+ V :: execute ( typed, ctx)
542+ }
543+
467544 fn execute_parent (
468545 & self ,
469546 this : & ArrayRef ,
0 commit comments