Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

enforce that GdalError is Send #293

Merged
merged 3 commits into from Sep 2, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGES.md
Expand Up @@ -3,6 +3,7 @@
## Unreleased

- Add prebuild bindings for GDAL 3.5

- <https://github.com/georust/gdal/pull/277>

- **Breaking**: Add `gdal::vector::OwnedLayer`, `gdal::vector::LayerAccess` and `gdal::vector::layer::OwnedFeatureIterator`. This requires importing `gdal::vector::LayerAccess` for using most vector layer methods.
Expand Down Expand Up @@ -75,6 +76,10 @@

- <https://github.com/georust/gdal/pull/284>

- Test that `GdalError` is `Send`

- <https://github.com/georust/gdal/pull/293>

## 0.12

- Bump Rust edition to 2021
Expand Down
18 changes: 16 additions & 2 deletions src/errors.rs
Expand Up @@ -72,9 +72,9 @@ pub enum GdalError {
BadArgument(String),

#[cfg(all(major_ge_3, minor_ge_1))]
#[error("Unhandled type '{data_type:?}' on GDAL MD method {method_name}")]
#[error("Unhandled type '{data_type}' on GDAL MD method {method_name}")]
UnsupportedMdDataType {
data_type: crate::raster::ExtendedDataType,
data_type: crate::raster::ExtendedDataTypeClass,
method_name: &'static str,
},
}
Expand All @@ -99,3 +99,17 @@ impl From<CPLErr::Type> for CplErrType {
unsafe { std::mem::transmute(error_type) }
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_that_gdal_error_is_send() {
fn is_send<T: Send>() -> bool {
true
}

assert!(is_send::<GdalError>());
}
}
74 changes: 61 additions & 13 deletions src/raster/mdarray.rs
Expand Up @@ -9,21 +9,22 @@ use gdal_sys::{
GDALAttributeReadAsIntArray, GDALAttributeReadAsString, GDALAttributeReadAsStringArray,
GDALAttributeRelease, GDALDataType, GDALDimensionGetIndexingVariable, GDALDimensionGetName,
GDALDimensionGetSize, GDALDimensionHS, GDALDimensionRelease, GDALExtendedDataTypeClass,
GDALExtendedDataTypeGetClass, GDALExtendedDataTypeGetNumericDataType, GDALExtendedDataTypeH,
GDALExtendedDataTypeRelease, GDALGroupGetAttribute, GDALGroupGetGroupNames,
GDALGroupGetMDArrayNames, GDALGroupGetName, GDALGroupH, GDALGroupOpenGroup,
GDALGroupOpenMDArray, GDALGroupRelease, GDALMDArrayGetAttribute, GDALMDArrayGetDataType,
GDALMDArrayGetDimensionCount, GDALMDArrayGetDimensions, GDALMDArrayGetNoDataValueAsDouble,
GDALMDArrayGetSpatialRef, GDALMDArrayGetTotalElementsCount, GDALMDArrayGetUnit, GDALMDArrayH,
GDALMDArrayRelease, OSRDestroySpatialReference, VSIFree,
GDALExtendedDataTypeGetClass, GDALExtendedDataTypeGetName,
GDALExtendedDataTypeGetNumericDataType, GDALExtendedDataTypeH, GDALExtendedDataTypeRelease,
GDALGroupGetAttribute, GDALGroupGetGroupNames, GDALGroupGetMDArrayNames, GDALGroupGetName,
GDALGroupH, GDALGroupOpenGroup, GDALGroupOpenMDArray, GDALGroupRelease,
GDALMDArrayGetAttribute, GDALMDArrayGetDataType, GDALMDArrayGetDimensionCount,
GDALMDArrayGetDimensions, GDALMDArrayGetNoDataValueAsDouble, GDALMDArrayGetSpatialRef,
GDALMDArrayGetTotalElementsCount, GDALMDArrayGetUnit, GDALMDArrayH, GDALMDArrayRelease,
OSRDestroySpatialReference, VSIFree,
};
use libc::c_void;
use std::ffi::CString;
use std::os::raw::c_char;

#[cfg(feature = "ndarray")]
use ndarray::{ArrayD, IxDyn};
use std::fmt::Debug;
use std::fmt::{Debug, Display};

/// Represent an MDArray in a Group
///
Expand Down Expand Up @@ -225,13 +226,13 @@ impl<'a> MDArray<'a> {
/// Read `MDArray` as one-dimensional string array
pub fn read_as_string_array(&self) -> Result<Vec<String>> {
let data_type = self.datatype();
if data_type.class() != GDALExtendedDataTypeClass::GEDTC_STRING {
if !data_type.class().is_string() {
// We have to check that the data type is string.
// Only then, GDAL returns an array of string pointers.
// Otherwise, we will dereference these string pointers and get a segfault.

return Err(GdalError::UnsupportedMdDataType {
data_type,
data_type: data_type.class(),
method_name: "GDALMDArrayRead (string)",
});
}
Expand Down Expand Up @@ -499,6 +500,48 @@ impl Drop for ExtendedDataType {
}
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ExtendedDataTypeClass {
Compound = GDALExtendedDataTypeClass::GEDTC_COMPOUND as isize,
Numeric = GDALExtendedDataTypeClass::GEDTC_NUMERIC as isize,
String = GDALExtendedDataTypeClass::GEDTC_STRING as isize,
}

impl ExtendedDataTypeClass {
pub fn is_string(&self) -> bool {
matches!(self, ExtendedDataTypeClass::String)
}

pub fn is_numeric(&self) -> bool {
matches!(self, ExtendedDataTypeClass::Numeric)
}

pub fn is_compound(&self) -> bool {
matches!(self, ExtendedDataTypeClass::Compound)
}
}

impl From<GDALExtendedDataTypeClass::Type> for ExtendedDataTypeClass {
fn from(class: GDALExtendedDataTypeClass::Type) -> Self {
match class {
GDALExtendedDataTypeClass::GEDTC_COMPOUND => ExtendedDataTypeClass::Compound,
GDALExtendedDataTypeClass::GEDTC_NUMERIC => ExtendedDataTypeClass::Numeric,
GDALExtendedDataTypeClass::GEDTC_STRING => ExtendedDataTypeClass::String,
_ => panic!("Unknown ExtendedDataTypeClass {class}"),
}
}
}

impl Display for ExtendedDataTypeClass {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ExtendedDataTypeClass::Compound => write!(f, "Compound"),
ExtendedDataTypeClass::Numeric => write!(f, "Numeric"),
ExtendedDataTypeClass::String => write!(f, "String"),
}
}
}

impl ExtendedDataType {
/// Create an `ExtendedDataTypeNumeric` from a wrapped C pointer
///
Expand All @@ -509,14 +552,18 @@ impl ExtendedDataType {
}

/// The result is only valid if the data type is numeric
pub fn class(&self) -> GDALExtendedDataTypeClass::Type {
unsafe { GDALExtendedDataTypeGetClass(self.c_data_type) }
pub fn class(&self) -> ExtendedDataTypeClass {
unsafe { GDALExtendedDataTypeGetClass(self.c_data_type) }.into()
}

/// The result is only valid if the data type is numeric
pub fn numeric_datatype(&self) -> GDALDataType::Type {
unsafe { GDALExtendedDataTypeGetNumericDataType(self.c_data_type) }
}

pub fn name(&self) -> String {
_string(unsafe { GDALExtendedDataTypeGetName(self.c_data_type) })
}
}

// Wrapper for `GDALAttribute`
Expand Down Expand Up @@ -802,8 +849,9 @@ mod tests {

let datatype = md_array.datatype();

assert_eq!(datatype.class(), GDALExtendedDataTypeClass::GEDTC_NUMERIC);
assert_eq!(datatype.class(), ExtendedDataTypeClass::Numeric);
assert_eq!(datatype.numeric_datatype(), GDALDataType::GDT_Byte);
assert_eq!(datatype.name(), "");
}

#[test]
Expand Down
2 changes: 1 addition & 1 deletion src/raster/mod.rs
Expand Up @@ -8,7 +8,7 @@ mod types;
mod warp;

#[cfg(all(major_ge_3, minor_ge_1))]
pub use mdarray::{ExtendedDataType, Group, MDArray};
pub use mdarray::{ExtendedDataType, ExtendedDataTypeClass, Group, MDArray};
pub use rasterband::{
Buffer, ByteBuffer, CmykEntry, ColorEntry, ColorInterpretation, ColorTable, GrayEntry,
HlsEntry, PaletteInterpretation, RasterBand, ResampleAlg, RgbaEntry,
Expand Down