From 1ea19ae641654fbc3aa1f6b87a31b4c947f1f4b3 Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Fri, 29 Jan 2021 15:44:57 -0600 Subject: [PATCH] specific errors and `try_into` for inner geo-types --- CHANGES.md | 5 ++++ Cargo.toml | 4 ++- src/conversion.rs | 68 ++++++++++++++++++++++++++++++++++++++--------- src/lib.rs | 2 ++ 4 files changed, 66 insertions(+), 13 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 5fc4d94..46aeca7 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,6 +2,11 @@ ## Unreleased +* WKT errors impl `std::error::Error` + * +* Add TryFrom for converting directly to geo-types::Geometry enum members, such + as `geo_types::LineString::try_from(wkt)` + * * Add `geo-types::Geometry::from(wkt)` * BREAKING: update geo-types, apply new `geo_types::CoordFloat` * diff --git a/Cargo.toml b/Cargo.toml index 47bc86d..4d7cfc9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,8 +10,9 @@ readme = "README.md" keywords = ["geo", "geospatial", "wkt"] [dependencies] -geo-types = {version = "0.7", optional = true} +geo-types = {version = "0.7.1", optional = true} num-traits = "0.2" +thiserror = "1.0.23" [dev-dependencies] criterion = { version = "0.2" } @@ -22,3 +23,4 @@ default = ["geo-types"] [[bench]] name = "parse" harness = false + diff --git a/src/conversion.rs b/src/conversion.rs index 45aa6cc..378ea0c 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -17,23 +17,23 @@ use Geometry; use Wkt; use std::convert::{TryFrom, TryInto}; -use std::fmt; use geo_types::CoordFloat; +use thiserror::Error; -#[derive(Debug)] +#[derive(Error, Debug)] pub enum Error { + #[error("The WKT Point was empty, but geo_type::Points cannot be empty")] PointConversionError, -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Error::PointConversionError => { - f.write_str("impossible to convert empty point to geo_type point") - } - } - } + #[error("Mismatched geometry (expected {expected:?}, found {found:?})")] + MismatchedGeometry { + expected: &'static str, + found: &'static str, + }, + #[error("Wrong number of Geometries: {0}")] + WrongNumberOfGeometries(usize), + #[error("External error: {0}")] + External(Box), } impl TryFrom> for geo_types::Geometry @@ -51,6 +51,50 @@ where } } +#[macro_use] +macro_rules! try_from_wkt_impl { + ($($type: ident),+) => { + $( + /// Convert a Wkt enum into a specific geo-type + impl TryFrom> for geo_types::$type { + type Error = Error; + + fn try_from(mut wkt: Wkt) -> Result { + match wkt.items.len() { + 1 => { + let item = wkt.items.pop().unwrap(); + let geometry = geo_types::Geometry::try_from(item)?; + Self::try_from(geometry).map_err(|e| { + match e { + geo_types::Error::MismatchedGeometry { expected, found } => { + Error::MismatchedGeometry { expected, found } + } + // currently only one error type in geo-types error enum, but that seems likely to change + #[allow(unreachable_patterns)] + other => Error::External(Box::new(other)), + } + }) + } + other => Err(Error::WrongNumberOfGeometries(other)), + } + } + } + )+ + } +} + +try_from_wkt_impl!( + Point, + Line, + LineString, + Polygon, + MultiPoint, + MultiLineString, + MultiPolygon, + Rect, + Triangle +); + impl From> for geo_types::Coordinate where T: CoordFloat, diff --git a/src/lib.rs b/src/lib.rs index 231c0db..4328b81 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -35,6 +35,8 @@ pub mod types; #[cfg(feature = "geo-types")] extern crate geo_types; +extern crate thiserror; + #[cfg(feature = "geo-types")] pub use towkt::ToWkt;