Skip to content

Commit

Permalink
conversion error specifies type
Browse files Browse the repository at this point in the history
This also makes public a new geo_types::Error enum.
  • Loading branch information
michaelkirk committed Jan 29, 2021
1 parent 0bbff67 commit 42ed0f4
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 89 deletions.
3 changes: 2 additions & 1 deletion geo-types/CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

## Unreleased

* Add Changes Here
* Add specific details about conversion failures in the newly public `geo_types::Error`
* <https://github.com/georust/geo/pull/614>

## 0.7.0

Expand Down
44 changes: 44 additions & 0 deletions geo-types/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use std::fmt;

#[derive(Debug)]
pub enum Error {
MismatchedGeometry {
expected: &'static str,
found: &'static str,
},
}

impl std::error::Error for Error {}

impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Error::MismatchedGeometry { expected, found } => {
write!(f, "Expected a {}, but found a {}", expected, found)
}
}
}
}

#[cfg(test)]
mod test {
use crate::{Geometry, Point, Rect};
use std::convert::TryFrom;

#[test]
fn error_output() {
let point = Point::new(1.0, 2.0);
let point_geometry = Geometry::from(point);

let rect = Rect::new(Point::new(1.0, 2.0), Point::new(3.0, 4.0));
let rect_geometry = Geometry::from(rect);

Point::try_from(point_geometry).expect("failed to unwrap inner enum Point");

let failure = Point::try_from(rect_geometry).unwrap_err();
assert_eq!(
format!("{}", failure),
"Expected a geo_types::point::Point<f64>, but found a geo_types::rect::Rect<f64>"
);
}
}
137 changes: 49 additions & 88 deletions geo-types/src/geometry.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
use crate::{
CoordNum, GeometryCollection, Line, LineString, MultiLineString, MultiPoint, MultiPolygon,
Point, Polygon, Rect, Triangle,
CoordNum, Error, GeometryCollection, Line, LineString, MultiLineString, MultiPoint,
MultiPolygon, Point, Polygon, Rect, Triangle,
};
use core::any::type_name;
use std::convert::TryFrom;
use std::error::Error;
use std::fmt;

/// An enum representing any possible geometry type.
///
Expand Down Expand Up @@ -182,94 +181,56 @@ impl<T: CoordNum> Geometry<T> {
}
}

#[derive(Debug)]
pub struct FailedToConvertError;

impl fmt::Display for FailedToConvertError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Could not convert from enum member to concrete type")
}
}

impl Error for FailedToConvertError {
fn description(&self) -> &str {
"Could not convert from enum member to concrete type"
}
}

impl<T: CoordNum> TryFrom<Geometry<T>> for Point<T> {
type Error = FailedToConvertError;

fn try_from(geom: Geometry<T>) -> Result<Point<T>, Self::Error> {
match geom {
Geometry::Point(p) => Ok(p),
_ => Err(FailedToConvertError),
#[macro_use]
macro_rules! try_from_geometry_impl {
($($type: ident),+) => {
$(
/// Convert a Geometry enum into its inner type.
///
/// Fails if the enum case does not match the type you are trying to convert it to.
impl <T: CoordNum> TryFrom<Geometry<T>> for $type<T> {
type Error = Error;

fn try_from(geom: Geometry<T>) -> Result<Self, Self::Error> {
match geom {
Geometry::$type(g) => Ok(g),
other => Err(Error::MismatchedGeometry {
expected: type_name::<$type<T>>(),
found: inner_type_name(other)
})
}
}
}
)+
}
}

impl<T: CoordNum> TryFrom<Geometry<T>> for Line<T> {
type Error = FailedToConvertError;
try_from_geometry_impl!(
Point,
Line,
LineString,
Polygon,
MultiPoint,
MultiLineString,
MultiPolygon,
Rect,
Triangle
);

fn try_from(geom: Geometry<T>) -> Result<Line<T>, Self::Error> {
match geom {
Geometry::Line(l) => Ok(l),
_ => Err(FailedToConvertError),
}
}
}

impl<T: CoordNum> TryFrom<Geometry<T>> for LineString<T> {
type Error = FailedToConvertError;

fn try_from(geom: Geometry<T>) -> Result<LineString<T>, Self::Error> {
match geom {
Geometry::LineString(ls) => Ok(ls),
_ => Err(FailedToConvertError),
}
}
}

impl<T: CoordNum> TryFrom<Geometry<T>> for Polygon<T> {
type Error = FailedToConvertError;

fn try_from(geom: Geometry<T>) -> Result<Polygon<T>, Self::Error> {
match geom {
Geometry::Polygon(ls) => Ok(ls),
_ => Err(FailedToConvertError),
}
}
}

impl<T: CoordNum> TryFrom<Geometry<T>> for MultiPoint<T> {
type Error = FailedToConvertError;

fn try_from(geom: Geometry<T>) -> Result<MultiPoint<T>, Self::Error> {
match geom {
Geometry::MultiPoint(mp) => Ok(mp),
_ => Err(FailedToConvertError),
}
}
}

impl<T: CoordNum> TryFrom<Geometry<T>> for MultiLineString<T> {
type Error = FailedToConvertError;

fn try_from(geom: Geometry<T>) -> Result<MultiLineString<T>, Self::Error> {
match geom {
Geometry::MultiLineString(mls) => Ok(mls),
_ => Err(FailedToConvertError),
}
}
}

impl<T: CoordNum> TryFrom<Geometry<T>> for MultiPolygon<T> {
type Error = FailedToConvertError;

fn try_from(geom: Geometry<T>) -> Result<MultiPolygon<T>, Self::Error> {
match geom {
Geometry::MultiPolygon(mp) => Ok(mp),
_ => Err(FailedToConvertError),
}
fn inner_type_name<T>(geometry: Geometry<T>) -> &'static str
where
T: CoordNum,
{
match geometry {
Geometry::Point(_) => type_name::<Point<T>>(),
Geometry::Line(_) => type_name::<Line<T>>(),
Geometry::LineString(_) => type_name::<LineString<T>>(),
Geometry::Polygon(_) => type_name::<Polygon<T>>(),
Geometry::MultiPoint(_) => type_name::<MultiPoint<T>>(),
Geometry::MultiLineString(_) => type_name::<MultiLineString<T>>(),
Geometry::MultiPolygon(_) => type_name::<MultiPolygon<T>>(),
Geometry::GeometryCollection(_) => type_name::<GeometryCollection<T>>(),
Geometry::Rect(_) => type_name::<Rect<T>>(),
Geometry::Triangle(_) => type_name::<Triangle<T>>(),
}
}
3 changes: 3 additions & 0 deletions geo-types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,9 @@ mod rect;
#[allow(deprecated)]
pub use crate::rect::{InvalidRectCoordinatesError, Rect};

mod error;
pub use error::Error;

#[macro_use]
mod macros;

Expand Down
7 changes: 7 additions & 0 deletions geo/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,3 +159,10 @@ impl<T> GeoFloat for T where T: num_traits::Float + GeoNum {}

pub trait GeoNum: CoordNum + algorithm::kernels::HasKernel {}
impl<T> GeoNum for T where T: CoordNum + algorithm::kernels::HasKernel {}

pub enum Error {
MismatchedGeometry {
expected: &'static str,
actual: &'static str,
},
}

0 comments on commit 42ed0f4

Please sign in to comment.