Skip to content

Commit

Permalink
Use TryFrom from std
Browse files Browse the repository at this point in the history
  • Loading branch information
GuillaumeGomez committed Jul 30, 2020
1 parent 7a8441a commit 1614a49
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 103 deletions.
11 changes: 6 additions & 5 deletions examples/from_geo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ extern crate geos;
#[cfg(feature = "geo")]
use geo_types::{Coordinate, LineString, Polygon};
#[cfg(feature = "geo")]
use geos::from_geo::TryInto;
#[cfg(feature = "geo")]
use geos::{Error, Geom, Geometry};
#[cfg(feature = "geo")]
use std::convert::TryInto;

#[cfg(feature = "geo")]
fn fun() -> Result<(), Error> {
Expand All @@ -33,10 +33,11 @@ fn fun() -> Result<(), Error> {
let geom: Geometry = (&p).try_into()?;

assert!(geom.contains(&geom)?);
assert!(!geom.contains(&(&exterior).try_into()?)?);
let tmp: Geometry = (&exterior).try_into()?;
assert!(!geom.contains(&tmp)?);

assert!(geom.covers(&(&exterior).try_into()?)?);
assert!(geom.touches(&(&exterior).try_into()?)?);
assert!(geom.covers(&tmp)?);
assert!(geom.touches(&tmp)?);
Ok(())
}

Expand Down
74 changes: 36 additions & 38 deletions src/from_geo.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
use crate::{CoordDimensions, CoordSeq, Geometry as GGeometry};
use error::Error;
use geo_types::{Coordinate, LineString, MultiPolygon, Point, Polygon};

use std;
use std::borrow::Borrow;

// define our own TryInto while the std trait is not stable
pub trait TryInto<T> {
type Err;
fn try_into(self) -> Result<T, Self::Err>;
}
use std::convert::{TryFrom, TryInto};

fn create_coord_seq_from_vec<'a>(coords: &'a [Coordinate<f64>]) -> Result<CoordSeq, Error> {
create_coord_seq(coords.iter(), coords.len())
Expand All @@ -27,21 +23,21 @@ where
Ok(coord_seq)
}

impl<'a> TryInto<GGeometry<'a>> for &'a Point<f64> {
type Err = Error;
impl<'a> TryFrom<&'a Point<f64>> for GGeometry<'a> {
type Error = Error;

fn try_into(self) -> Result<GGeometry<'a>, Self::Err> {
let coord_seq = create_coord_seq(std::iter::once(&self.0), 1)?;
fn try_from(other: &'a Point<f64>) -> Result<GGeometry<'a>, Self::Error> {
let coord_seq = create_coord_seq(std::iter::once(&other.0), 1)?;

GGeometry::create_point(coord_seq)
}
}

impl<'a, T: Borrow<Point<f64>>> TryInto<GGeometry<'a>> for &'a [T] {
type Err = Error;
impl<'a, T: Borrow<Point<f64>>> TryFrom<&'a [T]> for GGeometry<'a> {
type Error = Error;

fn try_into(self) -> Result<GGeometry<'a>, Self::Err> {
let geom_points = self
fn try_from(other: &'a [T]) -> Result<GGeometry<'a>, Self::Error> {
let geom_points = other
.into_iter()
.map(|p| p.borrow().try_into())
.collect::<Result<Vec<_>, _>>()?;
Expand All @@ -50,11 +46,11 @@ impl<'a, T: Borrow<Point<f64>>> TryInto<GGeometry<'a>> for &'a [T] {
}
}

impl<'a> TryInto<GGeometry<'a>> for &'a LineString<f64> {
type Err = Error;
impl<'a> TryFrom<&'a LineString<f64>> for GGeometry<'a> {
type Error = Error;

fn try_into(self) -> Result<GGeometry<'a>, Self::Err> {
let coord_seq = create_coord_seq_from_vec(self.0.as_slice())?;
fn try_from(other: &'a LineString<f64>) -> Result<GGeometry<'a>, Self::Error> {
let coord_seq = create_coord_seq_from_vec(other.0.as_slice())?;

GGeometry::create_line_string(coord_seq)
}
Expand All @@ -66,11 +62,11 @@ struct LineRing<'a>(&'a LineString<f64>);

/// Convert a geo_types::LineString to a geos LinearRing
/// a LinearRing should be closed so cloase the geometry if needed
impl<'a, 'b> TryInto<GGeometry<'b>> for &'a LineRing<'b> {
type Err = Error;
impl<'a> TryFrom<LineRing<'a>> for GGeometry<'a> {
type Error = Error;

fn try_into(self) -> Result<GGeometry<'b>, Self::Err> {
let points = &(self.0).0;
fn try_from(other: LineRing<'a>) -> Result<GGeometry<'a>, Self::Error> {
let points = &(other.0).0;
let nb_points = points.len();
if nb_points > 0 && nb_points < 3 {
return Err(Error::InvalidGeometry(
Expand All @@ -95,14 +91,14 @@ impl<'a, 'b> TryInto<GGeometry<'b>> for &'a LineRing<'b> {
}
}

impl<'a> TryInto<GGeometry<'a>> for &'a Polygon<f64> {
type Err = Error;
impl<'a> TryFrom<&'a Polygon<f64>> for GGeometry<'a> {
type Error = Error;

fn try_into(self) -> Result<GGeometry<'a>, Self::Err> {
let ring = LineRing(self.exterior());
fn try_from(other: &'a Polygon<f64>) -> Result<GGeometry<'a>, Self::Error> {
let ring = LineRing(other.exterior());
let geom_exterior: GGeometry = ring.try_into()?;

let interiors: Vec<_> = self
let interiors: Vec<_> = other
.interiors()
.iter()
.map(|i| LineRing(i).try_into())
Expand All @@ -112,11 +108,11 @@ impl<'a> TryInto<GGeometry<'a>> for &'a Polygon<f64> {
}
}

impl<'a> TryInto<GGeometry<'a>> for &'a MultiPolygon<f64> {
type Err = Error;
impl<'a> TryFrom<&'a MultiPolygon<f64>> for GGeometry<'a> {
type Error = Error;

fn try_into(self) -> Result<GGeometry<'a>, Self::Err> {
let polygons: Vec<_> = self
fn try_from(other: &'a MultiPolygon<f64>) -> Result<GGeometry<'a>, Self::Error> {
let polygons: Vec<_> = other
.0
.iter()
.map(|p| p.try_into())
Expand All @@ -130,8 +126,8 @@ impl<'a> TryInto<GGeometry<'a>> for &'a MultiPolygon<f64> {
mod test {
use super::LineRing;
use crate::{Geom, Geometry as GGeometry};
use from_geo::TryInto;
use geo_types::{Coordinate, LineString, MultiPolygon, Polygon};
use std::convert::TryInto;

fn coords(tuples: Vec<(f64, f64)>) -> Vec<Coordinate<f64>> {
tuples.into_iter().map(Coordinate::from).collect()
Expand Down Expand Up @@ -161,10 +157,12 @@ mod test {
let geom: GGeometry = (&p).try_into().unwrap();

assert!(geom.contains(&geom).unwrap());
assert!(!geom.contains(&(&exterior).try_into().unwrap()).unwrap());

assert!(geom.covers(&(&exterior).try_into().unwrap()).unwrap());
assert!(geom.touches(&(&exterior).try_into().unwrap()).unwrap());
let tmp: GGeometry = (&exterior).try_into().unwrap();

assert!(!geom.contains(&tmp).unwrap());
assert!(geom.covers(&tmp).unwrap());
assert!(geom.touches(&tmp).unwrap());
}

#[test]
Expand All @@ -189,7 +187,7 @@ mod test {
let geom: GGeometry = (&mp).try_into().unwrap();

assert!(geom.contains(&geom).unwrap());
assert!(geom.contains(&(&p).try_into().unwrap()).unwrap());
assert!(geom.contains::<GGeometry>(&(&p).try_into().unwrap()).unwrap());
}

#[test]
Expand All @@ -199,7 +197,7 @@ mod test {
let p = Polygon::new(exterior, interiors);
let mp = MultiPolygon(vec![p.clone()]);

let geom = (&mp).try_into();
let geom: Result<GGeometry, _> = (&mp).try_into();

assert!(geom.is_err());
}
Expand All @@ -224,7 +222,7 @@ mod test {
let p = Polygon::new(exterior, interiors);
let mp = MultiPolygon(vec![p]);

let _g = (&mp).try_into().unwrap(); // no error
let _g: GGeometry = (&mp).try_into().unwrap(); // no error
}

/// a linear ring can be empty
Expand Down
36 changes: 17 additions & 19 deletions src/from_geojson.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
use crate::{CoordDimensions, CoordSeq, Geometry as GGeometry};
use error::{Error, GResult};
use geojson::{Geometry, Value};
use std::iter;

pub trait TryInto<T> {
type Err;
fn try_into(self) -> Result<T, Self::Err>;
}
use std::convert::{TryFrom, TryInto};
use std::iter;

fn create_coord_seq_from_vec<'a>(coords: &'a [Vec<f64>]) -> Result<CoordSeq, Error> {
create_coord_seq(coords.iter(), coords.len())
Expand Down Expand Up @@ -42,11 +39,11 @@ fn create_closed_coord_seq_from_vec<'a>(points: &'a [Vec<f64>]) -> Result<CoordS
}
}

impl<'a> TryInto<GGeometry<'a>> for &'a Geometry {
type Err = Error;
impl<'a> TryFrom<&'a Geometry> for GGeometry<'a> {
type Error = Error;

fn try_into(self) -> Result<GGeometry<'a>, Self::Err> {
match self.value {
fn try_from(other: &'a Geometry) -> Result<GGeometry<'a>, Self::Error> {
match other.value {
Value::Point(ref c) => GGeometry::create_point(create_coord_seq(iter::once(c), 1)?),
Value::MultiPoint(ref pts) => {
let ggpts = pts
Expand Down Expand Up @@ -108,7 +105,7 @@ impl<'a> TryInto<GGeometry<'a>> for &'a Geometry {
Value::GeometryCollection(ref geoms) => {
let _geoms = geoms
.iter()
.map(|ref geom| geom.try_into())
.map(|geom| geom.try_into())
.collect::<GResult<Vec<GGeometry>>>()?;
GGeometry::create_geometry_collection(_geoms)
}
Expand All @@ -118,22 +115,23 @@ impl<'a> TryInto<GGeometry<'a>> for &'a Geometry {

#[cfg(test)]
mod test {
use crate::from_geojson::TryInto;
use crate::{Geom, Geometry as GGeometry};
use geojson::{Geometry, Value};

use std::convert::TryInto;

#[test]
fn geom_from_geojson_point() {
let geojson_pt = Geometry::new(Value::Point(vec![1., 1.]));
let gpoint: GGeometry = geojson_pt.try_into().unwrap();
let gpoint: GGeometry = (&geojson_pt).try_into().unwrap();

assert_eq!(gpoint.to_wkt_precision(0), Ok("POINT (1 1)".to_string()),);
}

#[test]
fn geom_from_geojson_multipoint() {
let geojson_pts = Geometry::new(Value::MultiPoint(vec![vec![1., 1.], vec![2., 2.]]));
let gpts: GGeometry = geojson_pts.try_into().unwrap();
let gpts: GGeometry = (&geojson_pts).try_into().unwrap();
assert_eq!(
gpts.to_wkt_precision(0),
Ok("MULTIPOINT (1 1, 2 2)".to_string()),
Expand All @@ -143,7 +141,7 @@ mod test {
#[test]
fn geom_from_geojson_line() {
let geojson_line = Geometry::new(Value::LineString(vec![vec![1., 1.], vec![2., 2.]]));
let gline: GGeometry = geojson_line.try_into().unwrap();
let gline: GGeometry = (&geojson_line).try_into().unwrap();
assert_eq!(
gline.to_wkt_precision(0),
Ok("LINESTRING (1 1, 2 2)".to_string()),
Expand All @@ -156,7 +154,7 @@ mod test {
vec![vec![1., 1.], vec![2., 2.]],
vec![vec![3., 3.], vec![4., 4.]],
]));
let glines: GGeometry = geojson_lines.try_into().unwrap();
let glines: GGeometry = (&geojson_lines).try_into().unwrap();
assert_eq!(
glines.to_wkt_precision(0),
Ok("MULTILINESTRING ((1 1, 2 2), (3 3, 4 4))".to_string()),
Expand All @@ -181,7 +179,7 @@ mod test {
vec![0.2, 0.2],
],
]));
let gpolygon: GGeometry = geojson_polygon.try_into().unwrap();
let gpolygon: GGeometry = (&geojson_polygon).try_into().unwrap();
assert_eq!(
gpolygon.to_wkt_precision(1),
Ok("POLYGON ((0.0 0.0, 0.0 3.0, 3.0 3.0, 3.0 0.0, 0.0 0.0), (0.2 0.2, 0.2 2.0, 2.0 2.0, 2.0 0.2, 0.2 0.2))"
Expand All @@ -201,7 +199,7 @@ mod test {
],
vec![vec![0.2, 0.2], vec![0.2, 2.], vec![2., 2.], vec![2., 0.2]],
]));
let gpolygon: GGeometry = geojson_polygon.try_into().unwrap();
let gpolygon: GGeometry = (&geojson_polygon).try_into().unwrap();
assert_eq!(
gpolygon.to_wkt_precision(1),
Ok("POLYGON ((0.0 0.0, 0.0 3.0, 3.0 3.0, 3.0 0.0, 0.0 0.0), (0.2 0.2, 0.2 2.0, 2.0 2.0, 2.0 0.2, 0.2 0.2))"
Expand All @@ -218,7 +216,7 @@ mod test {
vec![1., 0.],
vec![0., 0.],
]]]));
let gmultipolygon: GGeometry = geojson_multipolygon.try_into().unwrap();
let gmultipolygon: GGeometry = (&geojson_multipolygon).try_into().unwrap();
assert_eq!(
gmultipolygon.to_wkt_precision(0),
Ok("MULTIPOLYGON (((0 0, 0 1, 1 1, 1 0, 0 0)))".to_string()),
Expand All @@ -231,7 +229,7 @@ mod test {
Geometry::new(Value::Point(vec![1., 1.])),
Geometry::new(Value::LineString(vec![vec![1., 1.], vec![2., 2.]])),
]));
let gc: GGeometry = geojson_gc.try_into().unwrap();
let gc: GGeometry = (&geojson_gc).try_into().unwrap();
assert_eq!(
gc.to_wkt_precision(0),
Ok("GEOMETRYCOLLECTION (POINT (1 1), LINESTRING (1 1, 2 2))".to_string()),
Expand Down
13 changes: 7 additions & 6 deletions src/to_geo.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
use crate::{ConstGeometry, Geom, Geometry as GGeometry};
use error::Error;
use from_geo::TryInto;
use geo_types::Geometry;
use wkt;
use wkt::conversion::try_into_geometry;

use std::convert::TryFrom;

macro_rules! impl_try_into {
($ty_name:ident $(,$lt:lifetime)?) => (
impl<'a$(,$lt)?> TryInto<Geometry<f64>> for $ty_name<'a$(,$lt)?> {
type Err = Error;
impl<'a$(,$lt)?> TryFrom<$ty_name<'a$(,$lt)?>> for Geometry<f64> {
type Error = Error;

fn try_into(self) -> Result<Geometry<f64>, Self::Err> {
fn try_from(other: $ty_name<'a$(,$lt)?>) -> Result<Geometry<f64>, Self::Error> {
// This is a first draft, it's very inefficient, we use wkt as a pivot format to
// translate the geometry.
// We should at least use wkb, or even better implement a direct translation
let wkt_str = self.to_wkt()?;
let wkt_str = other.to_wkt()?;
let wkt_obj = wkt::Wkt::from_str(&wkt_str)
.map_err(|e| Error::ConversionError(format!("impossible to read wkt: {}", e)))?;

Expand All @@ -37,8 +38,8 @@ impl_try_into!(ConstGeometry, 'c);
#[cfg(test)]
mod test {
use crate::Geometry as GGeometry;
use from_geo::TryInto;
use geo_types::{Coordinate, Geometry, LineString, MultiPolygon, Polygon};
use std::convert::TryInto;

fn coords(tuples: Vec<(f64, f64)>) -> Vec<Coordinate<f64>> {
tuples.into_iter().map(Coordinate::from).collect()
Expand Down
Loading

0 comments on commit 1614a49

Please sign in to comment.