@@ -579,19 +579,22 @@ impl ArrayRef {
579579 }
580580 #[ cfg( feature = "table-display" ) ]
581581 DisplayOptions :: TableDisplay => {
582+ use vortex_mask:: Mask ;
583+
584+ use crate :: arrays:: StructArray ;
582585 use crate :: arrays:: struct_:: StructArrayExt ;
583- #[ expect( deprecated) ]
584- use crate :: canonical:: ToCanonical as _;
585586 use crate :: dtype:: DType ;
586587
587588 let mut builder = tabled:: builder:: Builder :: default ( ) ;
589+ // Reuse a single execution context across all per-row accesses below.
590+ let mut ctx = LEGACY_SESSION . create_execution_ctx ( ) ;
588591
589592 // Special logic for struct arrays.
590593 let DType :: Struct ( sf, _) = self . dtype ( ) else {
591594 // For non-struct arrays, simply display a single column table without header.
592595 for row_idx in 0 ..self . len ( ) {
593596 let value = self
594- . execute_scalar ( row_idx, & mut LEGACY_SESSION . create_execution_ctx ( ) )
597+ . execute_scalar ( row_idx, & mut ctx )
595598 . map_or_else ( |e| format ! ( "<error: {e}>" ) , |s| s. to_string ( ) ) ;
596599 builder. push_record ( [ value] ) ;
597600 }
@@ -602,22 +605,27 @@ impl ArrayRef {
602605 return write ! ( f, "{table}" ) ;
603606 } ;
604607
605- #[ expect( deprecated) ]
606- let struct_ = self . to_struct ( ) ;
608+ let struct_ = match self . clone ( ) . execute :: < StructArray > ( & mut ctx) {
609+ Ok ( struct_) => struct_,
610+ Err ( e) => return write ! ( f, "<error: {e}>" ) ,
611+ } ;
607612 builder. push_record ( sf. names ( ) . iter ( ) . map ( |name| name. to_string ( ) ) ) ;
608613
614+ // Resolve validity to a mask once instead of probing it per row.
615+ let validity = self
616+ . validity ( )
617+ . and_then ( |v| v. execute_mask ( self . len ( ) , & mut ctx) )
618+ . unwrap_or_else ( |_| Mask :: new_false ( self . len ( ) ) ) ;
619+
609620 for row_idx in 0 ..self . len ( ) {
610- if !self
611- . is_valid ( row_idx, & mut LEGACY_SESSION . create_execution_ctx ( ) )
612- . unwrap_or ( false )
613- {
621+ if !validity. value ( row_idx) {
614622 let null_row = vec ! [ "null" . to_string( ) ; sf. names( ) . len( ) ] ;
615623 builder. push_record ( null_row) ;
616624 } else {
617- let mut row = Vec :: new ( ) ;
625+ let mut row = Vec :: with_capacity ( struct_ . struct_fields ( ) . nfields ( ) ) ;
618626 for field_array in StructArrayExt :: iter_unmasked_fields ( & struct_) {
619627 let value = field_array
620- . execute_scalar ( row_idx, & mut LEGACY_SESSION . create_execution_ctx ( ) )
628+ . execute_scalar ( row_idx, & mut ctx )
621629 . map_or_else ( |e| format ! ( "<error: {e}>" ) , |s| s. to_string ( ) ) ;
622630 row. push ( value) ;
623631 }
@@ -634,10 +642,7 @@ impl ArrayRef {
634642 }
635643
636644 for row_idx in 0 ..self . len ( ) {
637- if !self
638- . is_valid ( row_idx, & mut LEGACY_SESSION . create_execution_ctx ( ) )
639- . unwrap_or ( false )
640- {
645+ if !validity. value ( row_idx) {
641646 table. modify (
642647 ( 1 + row_idx, 0 ) ,
643648 tabled:: settings:: Span :: column ( sf. names ( ) . len ( ) as isize ) ,
0 commit comments