use std::sync::Arc;
use crate::array::*;
use crate::scalar::*;
use geoarrow::io::geozero::ToGeometryArray;
use geoarrow::scalar::GeometryScalar;
use geozero::geojson::GeoJsonString;
use pyo3::exceptions::PyValueError;
use pyo3::prelude::*;
use pyo3::types::{PyDict, PyTuple};
use pyo3::{intern, PyAny, PyResult};
impl<'a> FromPyObject<'a> for PyGeometry {
fn extract_bound(ob: &Bound<'a, PyAny>) -> PyResult<Self> {
let py = ob.py();
if let Ok(geo_arr) = ob.extract::<PyNativeArray>() {
let scalar = GeometryScalar::try_new(geo_arr.0.into_inner()).unwrap();
Ok(PyGeometry::new(scalar))
} else if ob.hasattr(intern!(py, "__geo_interface__"))? {
let json_string = call_geo_interface(py, ob)?;
let reader = GeoJsonString(json_string);
let arr = reader
.to_geometry_array()
.map_err(|err| PyValueError::new_err(err.to_string()))?;
Ok(Self(
GeometryScalar::try_new(Arc::new(arr))
.map_err(|err| PyValueError::new_err(err.to_string()))?,
))
} else {
Err(PyValueError::new_err(
"Expected input to have __arrow_c_array__ or __geo_interface__ dunder methods",
))
}
}
}
fn call_geo_interface(py: Python, ob: &Bound<PyAny>) -> PyResult<String> {
let py_obj = ob.getattr("__geo_interface__")?;
let json_mod = py.import(intern!(py, "json"))?;
let args = (py_obj,);
let separators = PyTuple::new(py, vec![',', ':'])?;
let kwargs = PyDict::new(py);
kwargs.set_item("separators", separators)?;
let json_dumped = json_mod.call_method(intern!(py, "dumps"), args, Some(&kwargs))?;
json_dumped.extract()
}