Skip to content

Commit ffc15ec

Browse files
committed
feat(rust/sedona-raster): trinary Override for BandOverrides; copy_into stops composing views
Replace the all-Option BandOverrides fields with a trinary Override<T> (Keep/Clear/Set) for the clearable fields (name, nodata, outdb_uri, outdb_format, view); dim_names stays Option because a band always has dim names, so there is no absent state for Clear to express. copy_into now resolves each field by matching on the Override and never composes the view: Keep inherits the source view, Clear resets to the canonical identity view, and Set uses the given view verbatim. Callers that want the old compose behaviour pass Set(&source.view().compose(&next)?). RasterBuilder::with_view adopts this model: it composes the supplied delta onto the input's own view itself and passes the absolute result as Override::Set, inheriting nodata and the outdb hints from the input via Override::Keep (a None override maps to Keep, an explicit value to Set). This keeps both the source-nodata inheritance and the compose-time bound against the parent's visible window that copy_into used to provide.
1 parent 5c1eada commit ffc15ec

3 files changed

Lines changed: 247 additions & 73 deletions

File tree

rust/sedona-raster/src/array.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -819,7 +819,7 @@ impl<'a> RasterStructArray<'a> {
819819
mod tests {
820820
use super::*;
821821
use crate::builder::{RasterBuilder, StartBandArgs};
822-
use crate::traits::BandOverrides;
822+
use crate::traits::{BandOverrides, Override};
823823
use arrow_array::{ArrayRef, ListArray, StructArray, UInt32Array};
824824
use arrow_buffer::{NullBuffer, OffsetBuffer, ScalarBuffer};
825825
use arrow_schema::{DataType, Field, Fields};
@@ -888,7 +888,7 @@ mod tests {
888888
.copy_into(
889889
&mut ob,
890890
BandOverrides {
891-
name: Some("derived"),
891+
name: Override::Set("derived"),
892892
..Default::default()
893893
},
894894
)
@@ -918,9 +918,9 @@ mod tests {
918918

919919
#[test]
920920
fn copy_into_with_identity_override_view_succeeds() {
921-
// An explicit identity override composes back to the identity, so it is
922-
// accepted and behaves exactly like the inherited (None) case — this
923-
// exercises the new `BandOverrides::view` path end to end.
921+
// An explicit identity `Set` override is the identity view, so it is
922+
// accepted and behaves exactly like the inherited (`Keep`) case — this
923+
// exercises the `BandOverrides::view` `Set` path end to end.
924924
let transform = [0.0, 1.0, 0.0, 0.0, 0.0, -1.0];
925925
let mut ib = RasterBuilder::new(1);
926926
ib.start_raster_nd(&transform, &["x"], &[4], None).unwrap();
@@ -949,7 +949,7 @@ mod tests {
949949
.copy_into(
950950
&mut ob,
951951
BandOverrides {
952-
view: Some(&identity),
952+
view: Override::Set(&identity),
953953
..Default::default()
954954
},
955955
)

rust/sedona-raster/src/builder.rs

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ use sedona_schema::raster::{BandDataType, RasterSchema};
2727

2828
use crate::band_builder::{BandArrayBuilder, BandWriter};
2929
use crate::error::RasterError;
30-
use crate::traits::{BandOverrides, BandRef, RasterRef};
31-
use crate::view_entries::ViewEntry;
30+
use crate::traits::{BandOverrides, BandRef, Override, RasterRef};
31+
use crate::view_entries::{ViewEntries, ViewEntry};
3232

3333
/// Raster-level metadata overrides for [`RasterBuilder::start_raster_from`] and
3434
/// [`RasterBuilder::copy_raster_from`]. A `None` field inherits the source
@@ -394,22 +394,27 @@ impl RasterBuilder {
394394
outdb_uri,
395395
outdb_format,
396396
} = args;
397-
// Delegate to `copy_into`, which composes `view` (a delta over the
398-
// input's visible axes) onto the input's own view, carries the source
399-
// bytes over, and inherits every field left unset here from the input
400-
// via `.or_else(|| input.<field>())` — including `nodata`, which the
401-
// earlier hand-rolled implementation forwarded verbatim and thereby
402-
// dropped. `dim_names` and `view` are always supplied by this call, so
403-
// they pass through as explicit overrides.
397+
// `copy_into` never composes the view, so compose the delta here:
398+
// `view` addresses `input`'s *visible* axes, and composing it onto
399+
// `input.view()` yields the absolute source-space view that `copy_into`
400+
// persists verbatim (`Override::Set`). `compose` also bounds the delta
401+
// against the parent's visible window, so a slice can't re-expose bytes
402+
// the input had already sliced away.
403+
let composed =
404+
ViewEntries::new(input.view().to_vec()).compose(&ViewEntries::new(view.to_vec()))?;
405+
// Everything the caller leaves unset inherits from the source via
406+
// `Override::Keep`, including `nodata` — the source's sentinel must
407+
// carry over rather than being dropped. An explicit caller value
408+
// becomes `Override::Set`.
404409
input.copy_into(
405410
self,
406411
BandOverrides {
407-
name,
412+
name: name.map_or(Override::Keep, Override::Set),
408413
dim_names: Some(dim_names),
409-
nodata,
410-
outdb_uri,
411-
outdb_format,
412-
view: Some(view),
414+
nodata: nodata.map_or(Override::Keep, Override::Set),
415+
outdb_uri: outdb_uri.map_or(Override::Keep, Override::Set),
416+
outdb_format: outdb_format.map_or(Override::Keep, Override::Set),
417+
view: Override::Set(composed.as_slice()),
413418
},
414419
)
415420
}

0 commit comments

Comments
 (0)