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

Avoid panics in GEOS geometry construction #217

Merged
merged 8 commits into from
Nov 4, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
*.DS_Store
.idea

# Generated by Cargo
# will have compiled files and executables
Expand Down
2 changes: 1 addition & 1 deletion src/array/geometrycollection/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ impl<'a, O: OffsetSizeTrait> GeometryArrayTrait<'a> for GeometryCollectionArray<
/// This operation is `O(1)` as it amounts to increase two ref counts.
/// # Examples
/// ```
/// use arrow2::array::PrimitiveArray;
/// use arrow::array::PrimitiveArray;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just finished a migration from arrow2 to arrow-rs and the docstrings haven't been updated yet (not that they were accurate before either; they were copied from arrow2). Could you revert these specific changes to make it clear that these docstring examples don't work?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure.

Copy link
Member

@kylebarron kylebarron Nov 3, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, there's a whole bunch of these docstrings that need to be updated, so ideally we'll be intentional about fixing them in some sort of dedicated PR, ideally restoring doctest = true as well

geoarrow-rs/Cargo.toml

Lines 58 to 60 in 29930b0

[lib]
# TODO: fix docstrings
doctest = false

///
/// let array = PrimitiveArray::from_vec(vec![1, 2, 3]);
/// assert_eq!(format!("{:?}", array), "Int32[1, 2, 3]");
Expand Down
4 changes: 2 additions & 2 deletions src/array/linestring/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ impl<'a, O: OffsetSizeTrait> GeometryArrayTrait<'a> for LineStringArray<O> {
"ARROW:extension:name".to_string(),
"geoarrow.linestring".to_string(),
);
Arc::new(Field::new("", self.storage_type(), true).with_metadata(field_metadata))
Arc::new(Field::new("geometry", self.storage_type(), true).with_metadata(field_metadata))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm reluctant to call this "geometry" because we don't know the actual name of the field referring to the data in this column (and e.g. there could be two geometry columns in one table). I might switch this to return the field metadata directly instead of a full FieldRef (ref #218)

}

fn into_arrow(self) -> Self::ArrowArray {
Expand Down Expand Up @@ -180,7 +180,7 @@ impl<'a, O: OffsetSizeTrait> GeometryArrayTrait<'a> for LineStringArray<O> {
/// This operation is `O(1)` as it amounts to increase two ref counts.
/// # Examples
/// ```
/// use arrow2::array::PrimitiveArray;
/// use arrow::array::PrimitiveArray;
///
/// let array = PrimitiveArray::from_vec(vec![1, 2, 3]);
/// assert_eq!(format!("{:?}", array), "Int32[1, 2, 3]");
Expand Down
1 change: 0 additions & 1 deletion src/array/mixed/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@ pub struct MixedGeometryArray<O: OffsetSizeTrait> {
slice_offset: usize,
}

// TODO: rename to "GeometryType"?
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum GeometryType {
Point = 0,
Expand Down
2 changes: 1 addition & 1 deletion src/array/multipoint/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ impl<'a, O: OffsetSizeTrait> GeometryArrayTrait<'a> for MultiPointArray<O> {
/// This operation is `O(1)` as it amounts to increase two ref counts.
/// # Examples
/// ```
/// use arrow2::array::PrimitiveArray;
/// use arrow::array::PrimitiveArray;
///
/// let array = PrimitiveArray::from_vec(vec![1, 2, 3]);
/// assert_eq!(format!("{:?}", array), "Int32[1, 2, 3]");
Expand Down
3 changes: 1 addition & 2 deletions src/io/geos/array/linestring.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,9 @@ impl<'a, O: OffsetSizeTrait> TryFrom<Vec<Option<geos::Geometry<'a>>>>

fn try_from(value: Vec<Option<geos::Geometry<'a>>>) -> std::result::Result<Self, Self::Error> {
let length = value.len();
// TODO: don't use new_unchecked
let geos_linestring_objects: Vec<Option<GEOSLineString>> = value
.into_iter()
.map(|geom| geom.map(GEOSLineString::new_unchecked))
.map(|geom| geom.map(|geom| GEOSLineString::try_new(geom)?))
.collect();
let (coord_capacity, geom_capacity) = first_pass(
geos_linestring_objects.iter().map(|item| item.as_ref()),
Expand Down
3 changes: 1 addition & 2 deletions src/io/geos/array/multilinestring.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,9 @@ impl<O: OffsetSizeTrait> TryFrom<Vec<Option<geos::Geometry<'_>>>>

fn try_from(value: Vec<Option<geos::Geometry<'_>>>) -> Result<Self> {
let length = value.len();
// TODO: don't use new_unchecked
let geos_objects: Vec<Option<GEOSMultiLineString>> = value
.into_iter()
.map(|geom| geom.map(GEOSMultiLineString::new_unchecked))
.map(|geom| geom.map(|geom| GEOSMultiLineString::try_new(geom)?))
.collect();

let (coord_capacity, ring_capacity, geom_capacity) = first_pass(&geos_objects, length);
Expand Down
3 changes: 1 addition & 2 deletions src/io/geos/array/multipoint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,9 @@ impl<'a, O: OffsetSizeTrait> TryFrom<Vec<Option<geos::Geometry<'a>>>>

fn try_from(value: Vec<Option<geos::Geometry<'a>>>) -> std::result::Result<Self, Self::Error> {
let length = value.len();
// TODO: don't use new_unchecked
let geos_objects: Vec<Option<GEOSMultiPoint>> = value
.into_iter()
.map(|geom| geom.map(GEOSMultiPoint::new_unchecked))
.map(|geom| geom.map(|geom| GEOSMultiPoint::try_new(geom)?))
.collect();
let (coord_capacity, geom_capacity) = first_pass(&geos_objects, length);
Ok(second_pass(
Expand Down
3 changes: 1 addition & 2 deletions src/io/geos/array/multipolygon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,10 +188,9 @@ impl<O: OffsetSizeTrait> TryFrom<Vec<Option<geos::Geometry<'_>>>> for MutableMul

fn try_from(value: Vec<Option<geos::Geometry<'_>>>) -> Result<Self> {
let length = value.len();
// TODO: don't use new_unchecked
let geos_objects: Vec<Option<GEOSMultiPolygon>> = value
.into_iter()
.map(|geom| geom.map(GEOSMultiPolygon::new_unchecked))
.map(|geom| geom.map(|geom| GEOSMultiPolygon::try_new(geom)?))
.collect();

let (coord_capacity, ring_capacity, polygon_capacity, geom_capacity) =
Expand Down
3 changes: 1 addition & 2 deletions src/io/geos/array/point.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,9 @@ impl<'a> TryFrom<Vec<Option<geos::Geometry<'a>>>> for MutablePointArray {

fn try_from(value: Vec<Option<geos::Geometry<'a>>>) -> std::result::Result<Self, Self::Error> {
let length = value.len();
// TODO: don't use new_unchecked
let geos_linestring_objects: Vec<Option<GEOSPoint>> = value
.into_iter()
.map(|geom| geom.map(GEOSPoint::new_unchecked))
.map(|geom| geom.map(|geom| GEOSPoint::try_new(geom)?))
.collect();
Ok(from_nullable_coords(
geos_linestring_objects.iter().map(|item| item.as_ref()),
Expand Down
6 changes: 2 additions & 4 deletions src/io/geos/array/polygon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,10 +116,9 @@ impl<O: OffsetSizeTrait> TryFrom<Vec<Option<geos::Geometry<'_>>>> for MutablePol

fn try_from(value: Vec<Option<geos::Geometry<'_>>>) -> Result<Self> {
let length = value.len();
// TODO: don't use new_unchecked
let geos_objects: Vec<Option<GEOSPolygon>> = value
.into_iter()
.map(|geom| geom.map(GEOSPolygon::new_unchecked))
.map(|geom| geom.map(|geom| GEOSPolygon::try_new(geom)?))
.collect();

let (coord_capacity, ring_capacity, geom_capacity) = first_pass(&geos_objects, length);
Expand Down Expand Up @@ -151,10 +150,9 @@ impl<'a, O: OffsetSizeTrait> TryFrom<bumpalo::collections::Vec<'a, Option<geos::

// TODO: avoid creating GEOSPolygon objects at all?
let length = value.len();
// TODO: don't use new_unchecked
let geos_objects: bumpalo::collections::Vec<'_, Option<GEOSPolygon>> = value
.into_iter()
.map(|geom| geom.map(GEOSPolygon::new_unchecked))
.map(|geom| geom.map(|geom| GEOSPolygon::try_new(geom)?))
.collect_in(&bump);

let (coord_capacity, ring_capacity, geom_capacity) = first_pass(&geos_objects, length);
Expand Down
13 changes: 8 additions & 5 deletions src/io/geos/scalar/linearring.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::error::Result;
use crate::error::{GeoArrowError, Result};
use geos::{Geom, GeometryTypes};

pub struct GEOSConstLinearRing<'a, 'b>(pub(crate) geos::ConstGeometry<'a, 'b>);
Expand All @@ -10,10 +10,13 @@ impl<'a, 'b> GEOSConstLinearRing<'a, 'b> {

#[allow(dead_code)]
pub fn try_new(geom: geos::ConstGeometry<'a, 'b>) -> Result<Self> {
// TODO: make Err
assert!(matches!(geom.geometry_type(), GeometryTypes::LinearRing));

Ok(Self(geom))
if matches!(geom.geometry_type(), GeometryTypes::LinearRing) {
Ok(Self(geom))
} else {
Err(GeoArrowError::General(
"Geometry type must be linear ring".to_string(),
))
}
}

pub fn num_coords(&self) -> usize {
Expand Down
26 changes: 14 additions & 12 deletions src/io/geos/scalar/linestring.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,14 @@ impl<'b, O: OffsetSizeTrait> LineString<'_, O> {
pub struct GEOSLineString<'a>(geos::Geometry<'a>);

impl<'a> GEOSLineString<'a> {
pub fn new_unchecked(geom: geos::Geometry<'a>) -> Self {
Self(geom)
}

pub fn try_new(geom: geos::Geometry<'a>) -> Result<Self> {
// TODO: make Err
assert!(matches!(geom.geometry_type(), GeometryTypes::LineString));

Ok(Self(geom))
if matches!(geom.geometry_type(), GeometryTypes::LineString) {
Ok(Self(geom))
} else {
Err(GeoArrowError::General(
"Geometry type must be line string".to_string(),
))
}
}
}

Expand Down Expand Up @@ -114,10 +113,13 @@ impl<'a, 'b> GEOSConstLineString<'a, 'b> {

#[allow(dead_code)]
pub fn try_new(geom: geos::ConstGeometry<'a, 'b>) -> Result<Self> {
// TODO: make Err
assert!(matches!(geom.geometry_type(), GeometryTypes::LineString));

Ok(Self(geom))
if matches!(geom.geometry_type(), GeometryTypes::LineString) {
Ok(Self(geom))
} else {
Err(GeoArrowError::General(
"Geometry type must be line string".to_string(),
))
}
}
}

Expand Down
19 changes: 7 additions & 12 deletions src/io/geos/scalar/multilinestring.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,14 @@ impl<'a, 'b, O: OffsetSizeTrait> TryFrom<&'a MultiLineString<'_, O>> for geos::G
pub struct GEOSMultiLineString<'a>(pub(crate) geos::Geometry<'a>);

impl<'a> GEOSMultiLineString<'a> {
pub fn new_unchecked(geom: geos::Geometry<'a>) -> Self {
Self(geom)
}

#[allow(dead_code)]
pub fn try_new(geom: geos::Geometry<'a>) -> Result<Self> {
// TODO: make Err
assert!(matches!(
geom.geometry_type(),
GeometryTypes::MultiLineString
));

Ok(Self(geom))
if matches!(geom.geometry_type(), GeometryTypes::MultiLineString) {
Ok(Self(geom))
} else {
Err(GeoArrowError::General(
"Geometry type must be multi line string".to_string(),
))
}
}

pub fn num_lines(&self) -> usize {
Expand Down
16 changes: 7 additions & 9 deletions src/io/geos/scalar/multipoint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,14 @@ impl<'a, 'b, O: OffsetSizeTrait> TryFrom<&'a MultiPoint<'_, O>> for geos::Geomet
pub struct GEOSMultiPoint<'a>(pub(crate) geos::Geometry<'a>);

impl<'a> GEOSMultiPoint<'a> {
pub fn new_unchecked(geom: geos::Geometry<'a>) -> Self {
Self(geom)
}

#[allow(dead_code)]
pub fn try_new(geom: geos::Geometry<'a>) -> Result<Self> {
// TODO: make Err
assert!(matches!(geom.geometry_type(), GeometryTypes::MultiPoint));

Ok(Self(geom))
if matches!(geom.geometry_type(), GeometryTypes::MultiPoint) {
Ok(Self(geom))
} else {
Err(GeoArrowError::General(
"Geometry type must be multi point".to_string(),
))
}
}

pub fn num_points(&self) -> usize {
Expand Down
16 changes: 7 additions & 9 deletions src/io/geos/scalar/multipolygon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,14 @@ impl<'a, 'b, O: OffsetSizeTrait> TryFrom<&'a MultiPolygon<'_, O>> for geos::Geom
pub struct GEOSMultiPolygon<'a>(pub(crate) geos::Geometry<'a>);

impl<'a> GEOSMultiPolygon<'a> {
pub fn new_unchecked(geom: geos::Geometry<'a>) -> Self {
Self(geom)
}

#[allow(dead_code)]
pub fn try_new(geom: geos::Geometry<'a>) -> Result<Self> {
// TODO: make Err
assert!(matches!(geom.geometry_type(), GeometryTypes::MultiPolygon));

Ok(Self(geom))
if matches!(geom.geometry_type(), GeometryTypes::MultiPolygon) {
Ok(Self(geom))
} else {
Err(GeoArrowError::General(
"Geometry type must be multi polygon".to_string(),
))
}
}

pub fn num_polygons(&self) -> usize {
Expand Down
22 changes: 14 additions & 8 deletions src/io/geos/scalar/point.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,13 @@ impl<'a> GEOSPoint<'a> {
}

pub fn try_new(geom: geos::Geometry<'a>) -> Result<Self> {
// TODO: make Err
assert!(matches!(geom.geometry_type(), GeometryTypes::Point));

Ok(Self(geom))
if matches!(geom.geometry_type(), GeometryTypes::Point) {
Ok(Self(geom))
} else {
Err(GeoArrowError::General(
"Geometry type must be point".to_string(),
))
}
}
}

Expand Down Expand Up @@ -96,10 +99,13 @@ impl<'a, 'b> GEOSConstPoint<'a, 'b> {
}

pub fn try_new(geom: &'a geos::ConstGeometry<'a, 'b>) -> Result<Self> {
// TODO: make Err
assert!(matches!(geom.geometry_type(), GeometryTypes::Point));

Ok(Self(geom))
if matches!(geom.geometry_type(), GeometryTypes::Point) {
Ok(Self(geom))
} else {
Err(GeoArrowError::General(
"Geometry type must be point".to_string(),
))
}
}
}

Expand Down
27 changes: 14 additions & 13 deletions src/io/geos/scalar/polygon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,14 @@ impl<'a, 'b, O: OffsetSizeTrait> TryFrom<&'a Polygon<'_, O>> for geos::Geometry<
pub struct GEOSPolygon<'a>(pub(crate) geos::Geometry<'a>);

impl<'a> GEOSPolygon<'a> {
pub fn new_unchecked(geom: geos::Geometry<'a>) -> Self {
Self(geom)
}

#[allow(dead_code)]
pub fn try_new(geom: geos::Geometry<'a>) -> Result<Self> {
// TODO: make Err
assert!(matches!(geom.geometry_type(), GeometryTypes::LineString));

Ok(Self(geom))
if matches!(geom.geometry_type(), GeometryTypes::Polygon) {
Ok(Self(geom))
} else {
Err(GeoArrowError::General(
"Geometry type must be polygon".to_string(),
))
}
}

#[allow(dead_code)]
Expand Down Expand Up @@ -88,10 +86,13 @@ impl<'a, 'b> GEOSConstPolygon<'a, 'b> {

#[allow(dead_code)]
pub fn try_new(geom: geos::ConstGeometry<'a, 'b>) -> Result<Self> {
// TODO: make Err
assert!(matches!(geom.geometry_type(), GeometryTypes::LineString));

Ok(Self(geom))
if matches!(geom.geometry_type(), GeometryTypes::Polygon) {
Ok(Self(geom))
} else {
Err(GeoArrowError::General(
"Geometry type must be polygon".to_string(),
))
}
}

pub fn num_interiors(&self) -> usize {
Expand Down
Loading