diff --git a/CHANGES.md b/CHANGES.md index 299a06f..b6c5f32 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,8 +2,12 @@ ## Unreleased ### Changed -* Now accepts `MULTIPOINT`s with less parentheses, as output by `ST_AsText` in postgis: +* Now accepts `MULTIPOINT`s with fewer parentheses, as output by `ST_AsText` in postgis: `MULTIPOINT(0 1, 2 3)` in addition to `MULTIPOINT((0 1), (2 3))` +* BREAKING: Replace `Wkt::items` with `Wkt::item` and remove `Wkt::add_item()`. + * +* BREAKING: Reject empty strings instead of parsing them into an empty `Wkt`. + * ## 0.9.2 - 2020-04-30 ### Added diff --git a/benches/parse.rs b/benches/parse.rs index 4d8c634..b1f0edd 100644 --- a/benches/parse.rs +++ b/benches/parse.rs @@ -2,8 +2,6 @@ extern crate criterion; extern crate wkt; -use criterion::Criterion; - fn criterion_benchmark(c: &mut criterion::Criterion) { c.bench_function("parse small", |bencher| { let s = include_str!("./small.wkt"); diff --git a/src/conversion.rs b/src/conversion.rs index f77e566..18eac48 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -42,16 +42,11 @@ where { type Error = Error; - fn try_from(mut wkt: Wkt) -> Result { - if wkt.items.len() == 1 { - Self::try_from(wkt.items.pop().unwrap()) - } else { - Geometry::GeometryCollection(GeometryCollection(wkt.items)).try_into() - } + fn try_from(wkt: Wkt) -> Result { + Self::try_from(wkt.item) } } -#[macro_use] macro_rules! try_from_wkt_impl { ($($type: ident),+) => { $( @@ -59,24 +54,19 @@ macro_rules! try_from_wkt_impl { 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)), - } - }) + fn try_from(wkt: Wkt) -> Result { + let item = wkt.item; + 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)), - } + }) } } )+ @@ -321,8 +311,7 @@ mod tests { m: None, })) .as_item(); - let mut wkt = Wkt::new(); - wkt.add_item(w_point); + let wkt = Wkt { item: w_point }; let converted = geo_types::Geometry::try_from(wkt).unwrap(); let g_point: geo_types::Point = geo_types::Point::new(1.0, 2.0); @@ -330,39 +319,6 @@ mod tests { assert_eq!(converted, geo_types::Geometry::Point(g_point)); } - #[test] - fn convert_collection_wkt() { - let w_point_1 = Point(Some(Coord { - x: 1.0, - y: 2.0, - z: None, - m: None, - })) - .as_item(); - let w_point_2 = Point(Some(Coord { - x: 3.0, - y: 4.0, - z: None, - m: None, - })) - .as_item(); - let mut wkt = Wkt::new(); - wkt.add_item(w_point_1); - wkt.add_item(w_point_2); - - let converted = geo_types::Geometry::try_from(wkt).unwrap(); - let geo_collection: geo_types::GeometryCollection = - geo_types::GeometryCollection(vec![ - geo_types::Point::new(1.0, 2.0).into(), - geo_types::Point::new(3.0, 4.0).into(), - ]); - - assert_eq!( - converted, - geo_types::Geometry::GeometryCollection(geo_collection) - ); - } - #[test] fn convert_empty_point() { let point = Point(None); diff --git a/src/deserialize.rs b/src/deserialize.rs index e69e622..1a9fe4e 100644 --- a/src/deserialize.rs +++ b/src/deserialize.rs @@ -71,14 +71,8 @@ where where E: Error, { - let mut wkt = Wkt::from_str(s).map_err(|e| serde::de::Error::custom(e))?; - if wkt.items.len() == 1 { - Ok(wkt.items.remove(0)) - } else { - Err(serde::de::Error::custom( - "WKT should have only 1 Geometry item", - )) - } + let wkt = Wkt::from_str(s).map_err(|e| serde::de::Error::custom(e))?; + Ok(wkt.item) } } @@ -197,7 +191,7 @@ mod tests { .deserialize_any(WktVisitor::::default()) .unwrap(); assert!(matches!( - wkt.items[0], + wkt.item, Geometry::Point(Point(Some(Coord { x: _, // floating-point types cannot be used in patterns y: _, // floating-point types cannot be used in patterns diff --git a/src/lib.rs b/src/lib.rs index b8ff00c..476fd65 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -131,28 +131,19 @@ pub struct Wkt where T: WktFloat, { - pub items: Vec>, + pub item: Geometry, } impl Wkt where T: WktFloat + FromStr + Default, { - pub fn new() -> Self { - Wkt { items: vec![] } - } - - pub fn add_item(&mut self, item: Geometry) { - self.items.push(item); - } - pub fn from_str(wkt_str: &str) -> Result { let tokens = Tokens::from_str(wkt_str); Wkt::from_tokens(tokens) } fn from_tokens(tokens: Tokens) -> Result { - let mut wkt = Wkt::new(); let mut tokens = tokens.peekable(); let word = match tokens.next() { Some(Token::Word(word)) => { @@ -161,14 +152,12 @@ where } word } - None => return Ok(wkt), _ => return Err("Invalid WKT format"), }; match Geometry::from_word_and_tokens(&word, &mut tokens) { - Ok(item) => wkt.add_item(item), + Ok(item) => Ok(Wkt { item }), Err(s) => return Err(s), } - Ok(wkt) } } @@ -230,22 +219,20 @@ mod tests { #[test] fn empty_string() { - let wkt: Wkt = Wkt::from_str("").ok().unwrap(); - assert_eq!(0, wkt.items.len()); + let res: Result, _> = Wkt::from_str(""); + assert!(res.is_err()); } #[test] fn empty_items() { - let mut wkt: Wkt = Wkt::from_str("POINT EMPTY").ok().unwrap(); - assert_eq!(1, wkt.items.len()); - match wkt.items.pop().unwrap() { + let wkt: Wkt = Wkt::from_str("POINT EMPTY").ok().unwrap(); + match wkt.item { Geometry::Point(Point(None)) => (), _ => unreachable!(), }; - let mut wkt: Wkt = Wkt::from_str("MULTIPOLYGON EMPTY").ok().unwrap(); - assert_eq!(1, wkt.items.len()); - match wkt.items.pop().unwrap() { + let wkt: Wkt = Wkt::from_str("MULTIPOLYGON EMPTY").ok().unwrap(); + match wkt.item { Geometry::MultiPolygon(MultiPolygon(polygons)) => assert_eq!(polygons.len(), 0), _ => unreachable!(), }; @@ -253,9 +240,8 @@ mod tests { #[test] fn lowercase_point() { - let mut wkt: Wkt = Wkt::from_str("point EMPTY").ok().unwrap(); - assert_eq!(1, wkt.items.len()); - match wkt.items.pop().unwrap() { + let wkt: Wkt = Wkt::from_str("point EMPTY").ok().unwrap(); + match wkt.item { Geometry::Point(Point(None)) => (), _ => unreachable!(), }; @@ -272,10 +258,8 @@ mod tests { #[test] fn support_jts_linearring() { - let mut wkt: Wkt = Wkt::from_str("linearring (10 20, 30 40)").ok().unwrap(); - assert_eq!(1, wkt.items.len()); - - match wkt.items.pop().unwrap() { + let wkt: Wkt = Wkt::from_str("linearring (10 20, 30 40)").ok().unwrap(); + match wkt.item { Geometry::LineString(_ls) => (), _ => panic!("expected to be parsed as a LINESTRING"), }; diff --git a/src/towkt.rs b/src/towkt.rs index 6d146ce..42d701c 100644 --- a/src/towkt.rs +++ b/src/towkt.rs @@ -219,8 +219,6 @@ where { fn to_wkt(&self) -> Wkt { let w_geom = g_geom_to_w_geom(&self); - Wkt { - items: vec![w_geom], - } + Wkt { item: w_geom } } } diff --git a/src/types/geometrycollection.rs b/src/types/geometrycollection.rs index 0ddc35c..4218294 100644 --- a/src/types/geometrycollection.rs +++ b/src/types/geometrycollection.rs @@ -88,11 +88,10 @@ mod tests { #[test] fn basic_geometrycollection() { - let mut wkt: Wkt = Wkt::from_str("GEOMETRYCOLLECTION (POINT (8 4)))") + let wkt: Wkt = Wkt::from_str("GEOMETRYCOLLECTION (POINT (8 4)))") .ok() .unwrap(); - assert_eq!(1, wkt.items.len()); - let items = match wkt.items.pop().unwrap() { + let items = match wkt.item { Geometry::GeometryCollection(GeometryCollection(items)) => items, _ => unreachable!(), }; @@ -101,12 +100,10 @@ mod tests { #[test] fn complex_geometrycollection() { - let mut wkt: Wkt = - Wkt::from_str("GEOMETRYCOLLECTION (POINT (8 4),LINESTRING(4 6,7 10)))") - .ok() - .unwrap(); - assert_eq!(1, wkt.items.len()); - let items = match wkt.items.pop().unwrap() { + let wkt: Wkt = Wkt::from_str("GEOMETRYCOLLECTION (POINT (8 4),LINESTRING(4 6,7 10)))") + .ok() + .unwrap(); + let items = match wkt.item { Geometry::GeometryCollection(GeometryCollection(items)) => items, _ => unreachable!(), }; diff --git a/src/types/linestring.rs b/src/types/linestring.rs index 0f9b8df..96e5ddb 100644 --- a/src/types/linestring.rs +++ b/src/types/linestring.rs @@ -67,9 +67,8 @@ mod tests { #[test] fn basic_linestring() { - let mut wkt = Wkt::from_str("LINESTRING (10 -20, -0 -0.5)").ok().unwrap(); - assert_eq!(1, wkt.items.len()); - let coords = match wkt.items.pop().unwrap() { + let wkt = Wkt::from_str("LINESTRING (10 -20, -0 -0.5)").ok().unwrap(); + let coords = match wkt.item { Geometry::LineString(LineString(coords)) => coords, _ => unreachable!(), }; diff --git a/src/types/multilinestring.rs b/src/types/multilinestring.rs index bf144c5..76eb0a5 100644 --- a/src/types/multilinestring.rs +++ b/src/types/multilinestring.rs @@ -76,11 +76,10 @@ mod tests { #[test] fn basic_multilinestring() { - let mut wkt: Wkt = Wkt::from_str("MULTILINESTRING ((8 4, -3 0), (4 0, 6 -10))") + let wkt: Wkt = Wkt::from_str("MULTILINESTRING ((8 4, -3 0), (4 0, 6 -10))") .ok() .unwrap(); - assert_eq!(1, wkt.items.len()); - let lines = match wkt.items.pop().unwrap() { + let lines = match wkt.item { Geometry::MultiLineString(MultiLineString(lines)) => lines, _ => unreachable!(), }; diff --git a/src/types/multipoint.rs b/src/types/multipoint.rs index a85f4d1..730ee2d 100644 --- a/src/types/multipoint.rs +++ b/src/types/multipoint.rs @@ -72,9 +72,8 @@ mod tests { #[test] fn basic_multipoint() { - let mut wkt: Wkt = Wkt::from_str("MULTIPOINT ((8 4), (4 0))").ok().unwrap(); - assert_eq!(1, wkt.items.len()); - let points = match wkt.items.pop().unwrap() { + let wkt: Wkt = Wkt::from_str("MULTIPOINT ((8 4), (4 0))").ok().unwrap(); + let points = match wkt.item { Geometry::MultiPoint(MultiPoint(points)) => points, _ => unreachable!(), }; @@ -83,9 +82,8 @@ mod tests { #[test] fn postgis_style_multipoint() { - let mut wkt: Wkt = Wkt::from_str("MULTIPOINT (8 4, 4 0)").unwrap(); - assert_eq!(1, wkt.items.len()); - let points = match wkt.items.pop().unwrap() { + let wkt: Wkt = Wkt::from_str("MULTIPOINT (8 4, 4 0)").unwrap(); + let points = match wkt.item { Geometry::MultiPoint(MultiPoint(points)) => points, _ => unreachable!(), }; @@ -94,9 +92,8 @@ mod tests { #[test] fn mixed_parens_multipoint() { - let mut wkt: Wkt = Wkt::from_str("MULTIPOINT (8 4, (4 0))").unwrap(); - assert_eq!(1, wkt.items.len()); - let points = match wkt.items.pop().unwrap() { + let wkt: Wkt = Wkt::from_str("MULTIPOINT (8 4, (4 0))").unwrap(); + let points = match wkt.item { Geometry::MultiPoint(MultiPoint(points)) => points, _ => unreachable!(), }; @@ -105,9 +102,8 @@ mod tests { #[test] fn empty_multipoint() { - let mut wkt: Wkt = Wkt::from_str("MULTIPOINT EMPTY").unwrap(); - assert_eq!(1, wkt.items.len()); - let points = match wkt.items.pop().unwrap() { + let wkt: Wkt = Wkt::from_str("MULTIPOINT EMPTY").unwrap(); + let points = match wkt.item { Geometry::MultiPoint(MultiPoint(points)) => points, _ => unreachable!(), }; diff --git a/src/types/multipolygon.rs b/src/types/multipolygon.rs index 50d6835..a406db4 100644 --- a/src/types/multipolygon.rs +++ b/src/types/multipolygon.rs @@ -81,11 +81,10 @@ mod tests { #[test] fn basic_multipolygon() { - let mut wkt: Wkt = Wkt::from_str("MULTIPOLYGON (((8 4)), ((4 0)))") + let wkt: Wkt = Wkt::from_str("MULTIPOLYGON (((8 4)), ((4 0)))") .ok() .unwrap(); - assert_eq!(1, wkt.items.len()); - let polygons = match wkt.items.pop().unwrap() { + let polygons = match wkt.item { Geometry::MultiPolygon(MultiPolygon(polygons)) => polygons, _ => unreachable!(), }; diff --git a/src/types/point.rs b/src/types/point.rs index 2b5d1af..f369df9 100644 --- a/src/types/point.rs +++ b/src/types/point.rs @@ -72,9 +72,8 @@ mod tests { #[test] fn basic_point() { - let mut wkt = Wkt::from_str("POINT (10 -20)").ok().unwrap(); - assert_eq!(1, wkt.items.len()); - let coord = match wkt.items.pop().unwrap() { + let wkt = Wkt::from_str("POINT (10 -20)").ok().unwrap(); + let coord = match wkt.item { Geometry::Point(Point(Some(coord))) => coord, _ => unreachable!(), }; @@ -86,12 +85,10 @@ mod tests { #[test] fn basic_point_whitespace() { - let mut wkt: Wkt = - Wkt::from_str(" \n\t\rPOINT \n\t\r( \n\r\t10 \n\t\r-20 \n\t\r) \n\t\r") - .ok() - .unwrap(); - assert_eq!(1, wkt.items.len()); - let coord = match wkt.items.pop().unwrap() { + let wkt: Wkt = Wkt::from_str(" \n\t\rPOINT \n\t\r( \n\r\t10 \n\t\r-20 \n\t\r) \n\t\r") + .ok() + .unwrap(); + let coord = match wkt.item { Geometry::Point(Point(Some(coord))) => coord, _ => unreachable!(), }; diff --git a/src/types/polygon.rs b/src/types/polygon.rs index 36e59e7..5f51046 100644 --- a/src/types/polygon.rs +++ b/src/types/polygon.rs @@ -76,12 +76,10 @@ mod tests { #[test] fn basic_polygon() { - let mut wkt: Wkt = - Wkt::from_str("POLYGON ((8 4, 4 0, 0 4, 8 4), (7 3, 4 1, 1 4, 7 3))") - .ok() - .unwrap(); - assert_eq!(1, wkt.items.len()); - let lines = match wkt.items.pop().unwrap() { + let wkt: Wkt = Wkt::from_str("POLYGON ((8 4, 4 0, 0 4, 8 4), (7 3, 4 1, 1 4, 7 3))") + .ok() + .unwrap(); + let lines = match wkt.item { Geometry::Polygon(Polygon(lines)) => lines, _ => unreachable!(), };