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

Serde deserialize support for GDAL #116

Open
eg-novelt opened this issue Nov 8, 2020 · 1 comment
Open

Serde deserialize support for GDAL #116

eg-novelt opened this issue Nov 8, 2020 · 1 comment

Comments

@eg-novelt
Copy link

Hello guys,

Not sure an issue is the best way to ask this, so let me know if it should be somewhere else.

Basically for some context I've been using this library quite a bit and I do want to give something back. I've made small additions to the API but I think the most interesting part is adding some serde deserialization support.

How it works is I can have an object like this

#[derive(Deserialize, Debug)]
struct StronglyTypedObject {
    #[serde(rename="FieldNameInOGR")]
    global_id: String,
    some_count: u16,
    some_code: String,

    // This means the OGR layer has a field named Shape_Area
    #[serde(rename="Shape_Area")]
    shape_area: f32,
}

And I can deserialize like so

let mut ds = Dataset::open_from_str("/path/to/an/esri_yuck.gdb")?;
//let layer = ds.layer_by_sql("SELECT field1, field2, field4 FROM my_layer_name")?;
let layer = ds.layer_by_name("my_layer_name")?;

let gd = GdalStructDeserializerContext::new::<StronglyTypedObject>(layer.defn());
let my_obj: StronglyTypedObject = gd.to_struct(&layer.features().next().unwrap())?;

The reason for the context is that it will read the fields in the generic object and store the corresponding field indexes in order. It works similiar to bincode.

I also made a 2nd deserializer that can deserialize to Vec<String>, Vec<FieldValue>, HashMap<String, String>, and HashMap<String, FieldValue>. The maps keys are the field name, and the vector indexes are the field indexes.

FYI FieldValue is in this repo that is an enum that acts as a union to store strongly typed data.

So basically the question is -- Is there interest for a PR?

It would work like the other libraries where you can add a feature serde to the package and it will add this support.

I attached the raw code in case you would prefer looking at source. It has not been cleaned up, but should be more or less working. I'm currently working on making sure Option works as well (check Gdal for null fields) as being able to deserialize the FID. Another idea is integrating with the rust geo library https://github.com/georust/geo to be able to deserialize directly into a rust shape object.

I'm not sure I did things the best way. I hardcoded the FieldValue variant indexes for example, which isn't super clean. I'm not sure if this idea of a context was good. And how I kept state in the deserializer. Said another way, design comments welcome !

Anyway, it is still cool to get typed objects directly from Gdal.

Also I used this trick to get the field names of the struct from serde-rs/serde#1110.

gdal_serde.zip

@eg-novelt eg-novelt changed the title Serde deserialize support Serde deserialize support for GDAL Nov 8, 2020
@eg-novelt
Copy link
Author

eg-novelt commented Nov 8, 2020

gdal_struct_deserializer.rs.txt

An updated version that doesn't use deserialize_any and supports Option + FID + error handling when types don't fit, note this depends on some extra methods in feature

    pub fn is_field_set_and_not_null(&self, field_id: i32) -> bool {
        let rv = unsafe { gdal_sys::OGR_F_IsFieldSetAndNotNull(self.c_feature, field_id)};

        return rv != 0;
    }
    pub fn get_field_as_string(&self, field_id: i32) -> String {
        let rv = unsafe { gdal_sys::OGR_F_GetFieldAsString(self.c_feature, field_id) };
        _string(rv)
    }
    pub fn get_field_as_int(&self, field_id: i32) -> i32 {
        let rv = unsafe { gdal_sys::OGR_F_GetFieldAsInteger(self.c_feature, field_id) };
        rv
    }
    pub fn get_field_as_int64(&self, field_id: i32) -> i64 {
        let rv = unsafe { gdal_sys::OGR_F_GetFieldAsInteger64(self.c_feature, field_id) };
        rv
    }
    pub fn get_field_as_real(&self, field_id: i32) -> f64 {
        let rv = unsafe { gdal_sys::OGR_F_GetFieldAsDouble(self.c_feature, field_id) };
        rv
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant