diff --git a/rust/geoarrow/src/io/flatgeobuf/reader/async.rs b/rust/geoarrow/src/io/flatgeobuf/reader/async.rs index 71434433..ac4733d4 100644 --- a/rust/geoarrow/src/io/flatgeobuf/reader/async.rs +++ b/rust/geoarrow/src/io/flatgeobuf/reader/async.rs @@ -16,6 +16,7 @@ use crate::io::geozero::array::MixedGeometryStreamBuilder; use crate::io::geozero::table::{GeoTableBuilder, GeoTableBuilderOptions}; use crate::table::Table; +/// Read a FlatGeobuf file to a Table asynchronously from object storage. pub async fn read_flatgeobuf_async( reader: Arc, location: Path, diff --git a/rust/geoarrow/src/io/geos/array/binary.rs b/rust/geoarrow/src/io/geos/array/binary.rs index 8f77d21f..8b8efe1f 100644 --- a/rust/geoarrow/src/io/geos/array/binary.rs +++ b/rust/geoarrow/src/io/geos/array/binary.rs @@ -6,7 +6,8 @@ use crate::array::WKBArray; use crate::error::Result; impl WKBArray { - pub fn from_geos(value: Vec>) -> Result { + #[allow(dead_code)] + pub(crate) fn from_geos(value: Vec>) -> Result { let mut builder = GenericBinaryBuilder::new(); for maybe_geom in value { if let Some(geom) = maybe_geom { diff --git a/rust/geoarrow/src/io/geos/array/linestring.rs b/rust/geoarrow/src/io/geos/array/linestring.rs index 9a2e899c..994b75f5 100644 --- a/rust/geoarrow/src/io/geos/array/linestring.rs +++ b/rust/geoarrow/src/io/geos/array/linestring.rs @@ -4,7 +4,8 @@ use crate::error::Result; use crate::io::geos::scalar::GEOSLineString; impl LineStringBuilder { - pub fn from_geos(value: Vec>, dim: Dimension) -> Result { + #[allow(dead_code)] + pub(crate) fn from_geos(value: Vec>, dim: Dimension) -> Result { // TODO: don't use new_unchecked let geos_objects: Vec> = value .into_iter() @@ -15,7 +16,8 @@ impl LineStringBuilder { } impl LineStringArray { - pub fn from_geos(value: Vec>, dim: Dimension) -> Result { + #[allow(dead_code)] + pub(crate) fn from_geos(value: Vec>, dim: Dimension) -> Result { let mutable_arr = LineStringBuilder::from_geos(value, dim)?; Ok(mutable_arr.into()) } diff --git a/rust/geoarrow/src/io/geos/array/multilinestring.rs b/rust/geoarrow/src/io/geos/array/multilinestring.rs index d5eda1a8..939f8be2 100644 --- a/rust/geoarrow/src/io/geos/array/multilinestring.rs +++ b/rust/geoarrow/src/io/geos/array/multilinestring.rs @@ -4,7 +4,8 @@ use crate::error::Result; use crate::io::geos::scalar::GEOSMultiLineString; impl MultiLineStringBuilder { - pub fn from_geos(value: Vec>, dim: Dimension) -> Result { + #[allow(dead_code)] + pub(crate) fn from_geos(value: Vec>, dim: Dimension) -> Result { // TODO: don't use new_unchecked let geos_objects: Vec> = value .into_iter() @@ -15,7 +16,8 @@ impl MultiLineStringBuilder { } impl MultiLineStringArray { - pub fn from_geos(value: Vec>, dim: Dimension) -> Result { + #[allow(dead_code)] + pub(crate) fn from_geos(value: Vec>, dim: Dimension) -> Result { let mutable_arr = MultiLineStringBuilder::from_geos(value, dim)?; Ok(mutable_arr.into()) } diff --git a/rust/geoarrow/src/io/geos/array/multipoint.rs b/rust/geoarrow/src/io/geos/array/multipoint.rs index 58a7ad4a..f2f2ffc5 100644 --- a/rust/geoarrow/src/io/geos/array/multipoint.rs +++ b/rust/geoarrow/src/io/geos/array/multipoint.rs @@ -4,7 +4,8 @@ use crate::error::Result; use crate::io::geos::scalar::GEOSMultiPoint; impl MultiPointBuilder { - pub fn from_geos(value: Vec>, dim: Dimension) -> Result { + #[allow(dead_code)] + pub(crate) fn from_geos(value: Vec>, dim: Dimension) -> Result { // TODO: don't use new_unchecked let geos_objects: Vec> = value .into_iter() @@ -15,7 +16,8 @@ impl MultiPointBuilder { } impl MultiPointArray { - pub fn from_geos(value: Vec>, dim: Dimension) -> Result { + #[allow(dead_code)] + pub(crate) fn from_geos(value: Vec>, dim: Dimension) -> Result { let mutable_arr = MultiPointBuilder::from_geos(value, dim)?; Ok(mutable_arr.into()) } diff --git a/rust/geoarrow/src/io/geos/array/multipolygon.rs b/rust/geoarrow/src/io/geos/array/multipolygon.rs index 5ddd91a4..3364a7b3 100644 --- a/rust/geoarrow/src/io/geos/array/multipolygon.rs +++ b/rust/geoarrow/src/io/geos/array/multipolygon.rs @@ -4,7 +4,8 @@ use crate::error::Result; use crate::io::geos::scalar::GEOSMultiPolygon; impl MultiPolygonBuilder { - pub fn from_geos(value: Vec>, dim: Dimension) -> Result { + #[allow(dead_code)] + pub(crate) fn from_geos(value: Vec>, dim: Dimension) -> Result { // TODO: don't use new_unchecked let geos_objects: Vec> = value .into_iter() @@ -15,7 +16,8 @@ impl MultiPolygonBuilder { } impl MultiPolygonArray { - pub fn from_geos(value: Vec>, dim: Dimension) -> Result { + #[allow(dead_code)] + pub(crate) fn from_geos(value: Vec>, dim: Dimension) -> Result { let mutable_arr = MultiPolygonBuilder::from_geos(value, dim)?; Ok(mutable_arr.into()) } diff --git a/rust/geoarrow/src/io/geos/array/point.rs b/rust/geoarrow/src/io/geos/array/point.rs index d70558e2..bd6775e7 100644 --- a/rust/geoarrow/src/io/geos/array/point.rs +++ b/rust/geoarrow/src/io/geos/array/point.rs @@ -4,7 +4,8 @@ use crate::error::Result; use crate::io::geos::scalar::GEOSPoint; impl PointBuilder { - pub fn from_geos(value: Vec>, dim: Dimension) -> Result { + #[allow(dead_code)] + pub(crate) fn from_geos(value: Vec>, dim: Dimension) -> Result { // TODO: don't use new_unchecked let geos_linestring_objects: Vec> = value .into_iter() @@ -15,7 +16,8 @@ impl PointBuilder { } impl PointArray { - pub fn from_geos(value: Vec>, dim: Dimension) -> Result { + #[allow(dead_code)] + pub(crate) fn from_geos(value: Vec>, dim: Dimension) -> Result { let mutable_arr = PointBuilder::from_geos(value, dim)?; Ok(mutable_arr.into()) } diff --git a/rust/geoarrow/src/io/geos/array/polygon.rs b/rust/geoarrow/src/io/geos/array/polygon.rs index afc83b6d..2b1079a2 100644 --- a/rust/geoarrow/src/io/geos/array/polygon.rs +++ b/rust/geoarrow/src/io/geos/array/polygon.rs @@ -4,7 +4,8 @@ use crate::error::Result; use crate::io::geos::scalar::GEOSPolygon; impl PolygonBuilder { - pub fn from_geos(value: Vec>, dim: Dimension) -> Result { + #[allow(dead_code)] + pub(crate) fn from_geos(value: Vec>, dim: Dimension) -> Result { // TODO: don't use new_unchecked let geos_objects: Vec> = value .into_iter() @@ -16,7 +17,8 @@ impl PolygonBuilder { } impl PolygonArray { - pub fn from_geos(value: Vec>, dim: Dimension) -> Result { + #[allow(dead_code)] + pub(crate) fn from_geos(value: Vec>, dim: Dimension) -> Result { let mutable_arr = PolygonBuilder::from_geos(value, dim)?; Ok(mutable_arr.into()) } diff --git a/rust/geoarrow/src/io/geos/scalar/linestring.rs b/rust/geoarrow/src/io/geos/scalar/linestring.rs index 5ef8897f..0c8b49e1 100644 --- a/rust/geoarrow/src/io/geos/scalar/linestring.rs +++ b/rust/geoarrow/src/io/geos/scalar/linestring.rs @@ -18,7 +18,9 @@ impl<'a> TryFrom<&'a LineString<'_>> for geos::Geometry { } impl LineString<'_> { - pub fn to_geos_linear_ring(&self) -> std::result::Result { + /// Convert to a GEOS LinearRing + #[allow(dead_code)] + pub(crate) fn to_geos_linear_ring(&self) -> std::result::Result { let (start, end) = self.geom_offsets.start_end(self.geom_index); let sliced_coords = self.coords.clone().slice(start, end - start); diff --git a/rust/geoarrow/src/io/geozero/scalar/geometry.rs b/rust/geoarrow/src/io/geozero/scalar/geometry.rs index 60e9b3ed..a34f89df 100644 --- a/rust/geoarrow/src/io/geozero/scalar/geometry.rs +++ b/rust/geoarrow/src/io/geozero/scalar/geometry.rs @@ -45,7 +45,9 @@ impl GeozeroGeometry for Geometry<'_> { } } +/// Convert a geozero scalar data source to an [OwnedGeometry]. pub trait ToGeometry { + /// Convert a geozero scalar data source to an [OwnedGeometry]. fn to_geometry(&self, dim: Dimension) -> geozero::error::Result; } diff --git a/rust/geoarrow/src/io/postgis/reader.rs b/rust/geoarrow/src/io/postgis/reader.rs index 9cd20982..d04634e2 100644 --- a/rust/geoarrow/src/io/postgis/reader.rs +++ b/rust/geoarrow/src/io/postgis/reader.rs @@ -167,6 +167,7 @@ impl GeoTableBuilder { } } +/// Execute a SQL string against a PostGIS database, returning the result as an Arrow table. pub async fn read_postgis<'c, E: Executor<'c, Database = Postgres>>( executor: E, sql: &str, diff --git a/rust/geoarrow/src/io/shapefile/reader.rs b/rust/geoarrow/src/io/shapefile/reader.rs index 1aa5174a..53f20aab 100644 --- a/rust/geoarrow/src/io/shapefile/reader.rs +++ b/rust/geoarrow/src/io/shapefile/reader.rs @@ -33,6 +33,7 @@ pub struct ShapefileReaderOptions { // TODO: // stretch goal: return a record batch reader. +/// Read a Shapefile into a [Table]. pub fn read_shapefile( shp_reader: T, dbf_reader: T, diff --git a/rust/geoarrow/src/io/wkb/api.rs b/rust/geoarrow/src/io/wkb/api.rs index a7691e86..ea8d7c13 100644 --- a/rust/geoarrow/src/io/wkb/api.rs +++ b/rust/geoarrow/src/io/wkb/api.rs @@ -18,8 +18,10 @@ use arrow_array::OffsetSizeTrait; /// determine the exact buffer sizes, then making a single set of allocations and filling those new /// arrays with the WKB coordinate values. pub trait FromWKB: Sized { + /// The input array type. Either [`WKBArray`] or [`ChunkedWKBArray`] type Input; + /// Parse the WKB input. fn from_wkb( arr: &Self::Input, coord_type: CoordType, @@ -100,6 +102,20 @@ impl FromWKB for GeometryCollectionArray { } } +impl FromWKB for GeometryArray { + type Input = WKBArray; + + fn from_wkb( + arr: &WKBArray, + coord_type: CoordType, + _dim: Dimension, + ) -> Result { + let wkb_objects: Vec>> = arr.iter().collect(); + let builder = GeometryBuilder::from_wkb(&wkb_objects, coord_type, arr.metadata(), true)?; + Ok(builder.finish()) + } +} + impl FromWKB for Arc { type Input = WKBArray; @@ -108,15 +124,7 @@ impl FromWKB for Arc { coord_type: CoordType, dim: Dimension, ) -> Result { - let wkb_objects: Vec>> = arr.iter().collect(); - let builder = GeometryCollectionBuilder::from_wkb( - &wkb_objects, - dim, - coord_type, - arr.metadata(), - true, - )?; - builder.finish().downcast() + Ok(Arc::new(GeometryArray::from_wkb(arr, coord_type, dim)?)) } } @@ -175,15 +183,17 @@ impl FromWKB for Arc { /// /// This supports either ISO or EWKB-flavored data. /// -/// Does not downcast automatically +/// The returned array is guaranteed to have exactly the type of `target_type`. +/// +/// `NativeType::Rect` is currently not allowed. pub fn from_wkb( arr: &WKBArray, - target_geo_data_type: NativeType, + target_type: NativeType, prefer_multi: bool, ) -> Result> { use NativeType::*; let wkb_objects: Vec>> = arr.iter().collect(); - match target_geo_data_type { + match target_type { Point(coord_type, dim) => { let builder = PointBuilder::from_wkb(&wkb_objects, dim, coord_type, arr.metadata())?; Ok(Arc::new(builder.finish())) @@ -224,7 +234,7 @@ pub fn from_wkb( } Rect(_) => Err(GeoArrowError::General(format!( "Unexpected data type {:?}", - target_geo_data_type, + target_type, ))), Geometry(coord_type) => { let builder = @@ -240,8 +250,10 @@ pub fn from_wkb( /// determine the exact buffer sizes, then making a single set of allocations and filling those new /// arrays with the WKB coordinate values. pub trait ToWKB: Sized { + /// The output type, either [WKBArray] or [ChunkedWKBArray] type Output; + /// Encode as WKB fn to_wkb(&self) -> Self::Output; } @@ -259,8 +271,7 @@ impl ToWKB for &dyn NativeArray { MultiLineString(_, _) => self.as_multi_line_string().into(), MultiPolygon(_, _) => self.as_multi_polygon().into(), GeometryCollection(_, _) => self.as_geometry_collection().into(), - - Rect(_) => todo!(), + Rect(_) => self.as_rect().into(), Geometry(_) => self.as_geometry().into(), } } @@ -308,7 +319,7 @@ pub fn to_wkb(arr: &dyn NativeArray) -> WKBArray { MultiLineString(_, _) => arr.as_multi_line_string().into(), MultiPolygon(_, _) => arr.as_multi_polygon().into(), GeometryCollection(_, _) => arr.as_geometry_collection().into(), - Rect(_) => todo!(), + Rect(_) => arr.as_rect().into(), Geometry(_) => arr.as_geometry().into(), } } diff --git a/rust/geoarrow/src/io/wkb/writer/mod.rs b/rust/geoarrow/src/io/wkb/writer/mod.rs index cb6e07c1..858b31c5 100644 --- a/rust/geoarrow/src/io/wkb/writer/mod.rs +++ b/rust/geoarrow/src/io/wkb/writer/mod.rs @@ -6,3 +6,4 @@ mod multipoint; mod multipolygon; mod point; mod polygon; +mod rect; diff --git a/rust/geoarrow/src/io/wkb/writer/rect.rs b/rust/geoarrow/src/io/wkb/writer/rect.rs new file mode 100644 index 00000000..f16ad8e2 --- /dev/null +++ b/rust/geoarrow/src/io/wkb/writer/rect.rs @@ -0,0 +1,42 @@ +use crate::array::offset_builder::OffsetsBuilder; +use crate::array::{RectArray, WKBArray}; +use crate::trait_::ArrayAccessor; +use crate::ArrayBase; +use arrow_array::{GenericBinaryArray, OffsetSizeTrait}; +use arrow_buffer::Buffer; +use std::io::Cursor; +use wkb::writer::{rect_wkb_size, write_rect}; +use wkb::Endianness; + +impl From<&RectArray> for WKBArray { + fn from(value: &RectArray) -> Self { + let mut offsets: OffsetsBuilder = OffsetsBuilder::with_capacity(value.len()); + + // First pass: calculate binary array offsets + for maybe_geom in value.iter() { + if let Some(geom) = maybe_geom { + offsets.try_push_usize(rect_wkb_size(&geom)).unwrap(); + } else { + offsets.extend_constant(1); + } + } + + let values = { + let values = Vec::with_capacity(offsets.last().to_usize().unwrap()); + let mut writer = Cursor::new(values); + + for geom in value.iter().flatten() { + write_rect(&mut writer, &geom, Endianness::LittleEndian).unwrap(); + } + + writer.into_inner() + }; + + let binary_arr = GenericBinaryArray::new( + offsets.into(), + Buffer::from_vec(values), + value.nulls().cloned(), + ); + WKBArray::new(binary_arr, value.metadata()) + } +}