@@ -25,6 +25,7 @@ use datafusion_common::cast::{
2525 as_string_array, as_string_view_array, as_struct_array, as_uint32_array,
2626} ;
2727
28+ use crate :: builder:: RasterBuilder ;
2829use crate :: traits:: { BandRef , Bands , NdBuffer , RasterRef } ;
2930use crate :: view_entries:: ViewEntry ;
3031use sedona_schema:: raster:: { band_indices, raster_indices, BandDataType } ;
@@ -138,6 +139,18 @@ impl<'a> BandRef for BandRefImpl<'a> {
138139 data_type : self . data_type ,
139140 } )
140141 }
142+
143+ /// Zero-copy override: share the source row's backing `Buffer` into the
144+ /// builder (refcount bump) instead of copying the visible bytes. OutDb
145+ /// bands have an empty data column by design.
146+ fn append_data_into ( & self , builder : & mut RasterBuilder ) -> Result < ( ) , ArrowError > {
147+ if self . is_indb ( ) {
148+ builder. append_band_data_from ( self . data_array , self . band_row )
149+ } else {
150+ builder. band_data_writer ( ) . append_value ( [ ] ) ;
151+ Ok ( ( ) )
152+ }
153+ }
141154}
142155
143156/// Arrow-backed implementation of RasterRef for a single raster row.
@@ -545,7 +558,7 @@ impl<'a> RasterStructArray<'a> {
545558mod tests {
546559 use super :: * ;
547560 use crate :: builder:: RasterBuilder ;
548- use crate :: traits:: { BandMetadata , RasterMetadata } ;
561+ use crate :: traits:: { BandMetadata , BandOverrides , RasterMetadata } ;
549562 use arrow_array:: { ArrayRef , ListArray , StructArray , UInt32Array } ;
550563 use arrow_buffer:: { OffsetBuffer , ScalarBuffer } ;
551564 use arrow_schema:: { DataType , Fields } ;
@@ -555,6 +568,122 @@ mod tests {
555568 use sedona_testing:: rasters:: generate_test_rasters;
556569 use std:: sync:: Arc ;
557570
571+ #[ test]
572+ fn copy_into_shares_buffer_zero_copy_and_overrides ( ) {
573+ // 16-byte InDb band (> inline threshold, so block-backed and shareable).
574+ let transform = [ 0.0 , 1.0 , 0.0 , 0.0 , 0.0 , -1.0 ] ;
575+ let mut ib = RasterBuilder :: new ( 1 ) ;
576+ ib. start_raster_nd ( & transform, & [ "x" ] , & [ 16 ] , None ) . unwrap ( ) ;
577+ ib. start_band_nd (
578+ Some ( "orig" ) ,
579+ & [ "x" ] ,
580+ & [ 16 ] ,
581+ BandDataType :: UInt8 ,
582+ None ,
583+ None ,
584+ None ,
585+ )
586+ . unwrap ( ) ;
587+ ib. band_data_writer ( )
588+ . append_value ( ( 0u8 ..16 ) . collect :: < Vec < u8 > > ( ) ) ;
589+ ib. finish_band ( ) . unwrap ( ) ;
590+ ib. finish_raster ( ) . unwrap ( ) ;
591+ let input_array = ib. finish ( ) . unwrap ( ) ;
592+ let input_rasters = RasterStructArray :: try_new ( & input_array) . unwrap ( ) ;
593+ let input_raster = input_rasters. get ( 0 ) . unwrap ( ) ;
594+ let input_band = input_raster. band ( 0 ) . unwrap ( ) ;
595+ let input_ptr = input_band. nd_buffer ( ) . unwrap ( ) . buffer . as_ptr ( ) ;
596+
597+ // copy_into with a name override; everything else inherited.
598+ let mut ob = RasterBuilder :: new ( 1 ) ;
599+ ob. start_raster_nd ( & transform, & [ "x" ] , & [ 16 ] , None ) . unwrap ( ) ;
600+ input_band
601+ . copy_into (
602+ & mut ob,
603+ BandOverrides {
604+ name : Some ( "derived" ) ,
605+ ..Default :: default ( )
606+ } ,
607+ )
608+ . unwrap ( ) ;
609+ ob. finish_band ( ) . unwrap ( ) ;
610+ ob. finish_raster ( ) . unwrap ( ) ;
611+ let out_array = ob. finish ( ) . unwrap ( ) ;
612+ let out_rasters = RasterStructArray :: try_new ( & out_array) . unwrap ( ) ;
613+ let out_raster = out_rasters. get ( 0 ) . unwrap ( ) ;
614+ let out_band = out_raster. band ( 0 ) . unwrap ( ) ;
615+
616+ // Zero-copy: the derived band references the same backing bytes.
617+ assert_eq ! (
618+ input_ptr,
619+ out_band. nd_buffer( ) . unwrap( ) . buffer. as_ptr( ) ,
620+ "copy_into must share the source buffer, not copy it"
621+ ) ;
622+ assert_eq ! (
623+ out_band. nd_buffer( ) . unwrap( ) . as_contiguous( ) . unwrap( ) ,
624+ ( 0u8 ..16 ) . collect:: <Vec <u8 >>( ) . as_slice( )
625+ ) ;
626+ // Name overridden; dim names + data type inherited from the source.
627+ assert_eq ! ( out_raster. band_name( 0 ) , Some ( "derived" ) ) ;
628+ assert_eq ! ( out_band. dim_names( ) , vec![ "x" ] ) ;
629+ assert_eq ! ( out_band. data_type( ) , BandDataType :: UInt8 ) ;
630+ }
631+
632+ #[ test]
633+ fn copy_into_with_identity_override_view_succeeds ( ) {
634+ // An explicit identity override composes back to the identity, so it is
635+ // accepted and behaves exactly like the inherited (None) case — this
636+ // exercises the new `BandOverrides::view` path end to end.
637+ let transform = [ 0.0 , 1.0 , 0.0 , 0.0 , 0.0 , -1.0 ] ;
638+ let mut ib = RasterBuilder :: new ( 1 ) ;
639+ ib. start_raster_nd ( & transform, & [ "x" ] , & [ 4 ] , None ) . unwrap ( ) ;
640+ ib. start_band_nd (
641+ Some ( "orig" ) ,
642+ & [ "x" ] ,
643+ & [ 4 ] ,
644+ BandDataType :: UInt8 ,
645+ None ,
646+ None ,
647+ None ,
648+ )
649+ . unwrap ( ) ;
650+ ib. band_data_writer ( ) . append_value ( vec ! [ 1u8 , 2 , 3 , 4 ] ) ;
651+ ib. finish_band ( ) . unwrap ( ) ;
652+ ib. finish_raster ( ) . unwrap ( ) ;
653+ let in_array = ib. finish ( ) . unwrap ( ) ;
654+ let in_rasters = RasterStructArray :: try_new ( & in_array) . unwrap ( ) ;
655+ let in_raster = in_rasters. get ( 0 ) . unwrap ( ) ;
656+ let in_band = in_raster. band ( 0 ) . unwrap ( ) ;
657+
658+ let identity = [ ViewEntry {
659+ source_axis : 0 ,
660+ start : 0 ,
661+ step : 1 ,
662+ steps : 4 ,
663+ } ] ;
664+ let mut ob = RasterBuilder :: new ( 1 ) ;
665+ ob. start_raster_nd ( & transform, & [ "x" ] , & [ 4 ] , None ) . unwrap ( ) ;
666+ in_band
667+ . copy_into (
668+ & mut ob,
669+ BandOverrides {
670+ view : Some ( & identity) ,
671+ ..Default :: default ( )
672+ } ,
673+ )
674+ . unwrap ( ) ;
675+ ob. finish_band ( ) . unwrap ( ) ;
676+ ob. finish_raster ( ) . unwrap ( ) ;
677+ let out_array = ob. finish ( ) . unwrap ( ) ;
678+ let out_rasters = RasterStructArray :: try_new ( & out_array) . unwrap ( ) ;
679+ let out_raster = out_rasters. get ( 0 ) . unwrap ( ) ;
680+ let out_band = out_raster. band ( 0 ) . unwrap ( ) ;
681+ assert_eq ! (
682+ out_band. nd_buffer( ) . unwrap( ) . as_contiguous( ) . unwrap( ) ,
683+ & [ 1u8 , 2 , 3 , 4 ]
684+ ) ;
685+ }
686+
558687 #[ test]
559688 fn test_array_basic_functionality ( ) {
560689 // Create a simple raster for testing using the correct API
0 commit comments