feat(sedona-gdal): add convenience facade and mem builder#697
feat(sedona-gdal): add convenience facade and mem builder#697Kontinuation wants to merge 13 commits intoapache:mainfrom
Conversation
e7e3be7 to
98cbbd2
Compare
4008bc8 to
006695f
Compare
006695f to
43b3ba5
Compare
There was a problem hiding this comment.
Pull request overview
This PR introduces a higher-level ergonomics layer for sedona-gdal by adding a Gdal facade and a fluent MEM dataset builder, while keeping the lower-level API available for explicit use.
Changes:
- Add
Gdalhigh-level facade wrapping&'static GdalApito reduce explicitapiplumbing at call sites. - Add
MemDatasetBuilderfor constructing MEM datasets (including zero-copy band attachment plus optional geotransform/projection/nodata). - Export
call_gdal_api!as a macro and addwith_global_gdalconvenience entry point.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| c/sedona-gdal/src/mem.rs | New MEM dataset builder and MEM dataset creation helper + tests. |
| c/sedona-gdal/src/lib.rs | Exposes the new gdal and mem modules publicly. |
| c/sedona-gdal/src/global.rs | Adds with_global_gdal convenience wrapper around the global API handle. |
| c/sedona-gdal/src/gdal.rs | New Gdal facade providing ergonomic wrappers for common operations. |
| c/sedona-gdal/src/gdal_api.rs | Exports call_gdal_api! macro (now public/root-exported). |
Comments suppressed due to low confidence (1)
c/sedona-gdal/src/gdal_api.rs:48
call_gdal_apiis now marked#[macro_export], which makes it part of the public API and exports it at the crate root. However, the macro expands to$api.inner.$func, andinnerispub(crate), so downstream crates cannot actually use the exported macro (privacy check will fail). Consider removing#[macro_export]and keeping it crate-internal (the existingpub(crate) use call_gdal_api;already enables use across this crate without widening the public surface).
#[macro_export]
macro_rules! call_gdal_api {
($api:expr, $func:ident $(, $arg:expr)*) => {
if let Some(func) = $api.inner.$func {
func($($arg),*)
} else {
panic!("{} function not available", stringify!($func))
}
};
}
pub(crate) use call_gdal_api;
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
paleolimbot
left a comment
There was a problem hiding this comment.
A few optional things that may be worth considering. Thank you!
| /// Add a zero-copy band with custom offsets and optional nodata. | ||
| /// | ||
| /// # Safety | ||
| /// | ||
| /// The caller must ensure `data_ptr` points to a valid buffer of sufficient size | ||
| /// for the given dimensions and offsets, is properly aligned for `data_type`, and | ||
| /// outlives the built [`Dataset`]. | ||
| pub unsafe fn add_band_with_options( | ||
| mut self, | ||
| data_type: GdalDataType, | ||
| data_ptr: *mut u8, | ||
| pixel_offset: Option<i64>, | ||
| line_offset: Option<i64>, | ||
| nodata: Option<Nodata>, | ||
| ) -> Self { | ||
| self.bands.push(MemBand { | ||
| data_type, | ||
| data_ptr, | ||
| pixel_offset, | ||
| line_offset, | ||
| nodata, | ||
| }); | ||
| self | ||
| } |
| /// Fetch GDAL version information for a standard request key. | ||
| pub fn version_info(&self, request: &str) -> String { |
There was a problem hiding this comment.
These are all a bit light on the documentation (maybe they could link to the underlying implementation's docs which I seem to remember have a bit more depth?). Also OK to defer since this is mostly intended to be for internal usage.
| /// High-level convenience wrapper around [`GdalApi`]. | ||
| /// | ||
| /// Stores a `&'static GdalApi` reference and provides ergonomic methods that | ||
| /// delegate to the various constructors and free functions in the crate. | ||
| pub struct Gdal { | ||
| api: &'static GdalApi, | ||
| } | ||
|
|
||
| impl Gdal { |
There was a problem hiding this comment.
I do like the idea of a high-level object that dishes out other safe high-level objects, although putting it all here involves repeating some documentation (or omitting it) and I'm not sure it's needed given that the constructors it refers to are pub anyway. Reexporting the structs or functions that are part of the intended external API might be another way to expose the API without loosing the docs?
| /// Set the dataset projection definition string. | ||
| pub fn projection(mut self, wkt: impl Into<String>) -> Self { | ||
| self.projection = Some(wkt.into()); |
There was a problem hiding this comment.
Is this actually WKT or can this by anything? (It may be less error prone to accept anything or an explicit spatialref object)
| /// `data_ptr` must point to valid mutable band data that outlives this dataset. | ||
| pub unsafe fn add_band_with_data( | ||
| &self, | ||
| data_type: RustGdalDataType, | ||
| data_ptr: *const u8, | ||
| data_ptr: *mut u8, |
There was a problem hiding this comment.
Is this actually required to be mutable? (This seems like a strange constraint, and also one that will result in it not being particularly useful to us)
| pub unsafe fn add_band(self, data_type: GdalDataType, data_ptr: *mut u8) -> Self { | ||
| self.add_band_with_options(data_type, data_ptr, None, None, None) | ||
| } |
There was a problem hiding this comment.
Are you sure the data pointer has to be mutable? (This would preclude backing a GDAL mem dataset with Arrow data?)
Summary
Gdalfacade andwith_global_gdalconvenience entry pointDepends on #698.
Testing
cargo test -p sedona-gdalcargo clippy -p sedona-gdal -- -D warnings