postgis_butmaintained/
ewkb.rs

1//! Read and write geometries in [OGC WKB](http://www.opengeospatial.org/standards/sfa) format.
2//!
3//! Support for SRID information according to [PostGIS EWKB extensions](https://git.osgeo.org/gitea/postgis/postgis/src/branch/master/doc/ZMSgeoms.txt)
4
5mod encoding;
6use crate::{error::Error, types as postgis};
7use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
8use encoding::*;
9use std;
10use std::fmt;
11use std::io::prelude::*;
12use std::iter::FromIterator;
13use std::slice::Iter;
14
15// Re-export point types
16pub mod point;
17pub use point::*;
18pub mod container;
19pub use container::point::*;
20mod geometry;
21pub use geometry::*;
22
23// --- Traits
24
25pub trait EwkbRead: fmt::Debug + Sized {
26    fn point_type() -> PointType;
27
28    fn read_ewkb<R: Read>(raw: &mut R) -> Result<Self, Error> {
29        let byte_order = raw.read_i8()?;
30        let is_be = byte_order == 0i8;
31
32        let type_id = read_u32(raw, is_be)?;
33        let mut srid: Option<i32> = None;
34        if type_id & 0x20000000 == 0x20000000 {
35            srid = Some(read_i32(raw, is_be)?);
36        }
37        Self::read_ewkb_body(raw, is_be, type_id, srid)
38    }
39
40    #[doc(hidden)]
41    fn read_ewkb_body<R: Read>(
42        raw: &mut R,
43        is_be: bool,
44        type_id: u32,
45        srid: Option<i32>,
46    ) -> Result<Self, Error>;
47}
48
49pub trait EwkbWrite: fmt::Debug + Sized {
50    fn opt_srid(&self) -> Option<i32> {
51        None
52    }
53
54    fn wkb_type_id(point_type: &PointType, srid: Option<i32>) -> u32 {
55        let mut type_ = 0;
56        if srid.is_some() {
57            type_ |= 0x20000000;
58        }
59        if *point_type == PointType::PointZ || *point_type == PointType::PointZM {
60            type_ |= 0x80000000;
61        }
62        if *point_type == PointType::PointM || *point_type == PointType::PointZM {
63            type_ |= 0x40000000;
64        }
65        type_
66    }
67
68    fn type_id(&self) -> u32;
69
70    fn write_ewkb<W: Write + ?Sized>(&self, w: &mut W) -> Result<(), Error> {
71        // use LE
72        w.write_u8(0x01)?;
73        let type_id = self.type_id();
74        w.write_u32::<LittleEndian>(type_id)?;
75        self.opt_srid()
76            .map(|srid| w.write_i32::<LittleEndian>(srid));
77        self.write_ewkb_body(w)?;
78        Ok(())
79    }
80    #[doc(hidden)]
81    fn write_ewkb_body<W: Write + ?Sized>(&self, w: &mut W) -> Result<(), Error>;
82
83    fn to_hex_ewkb(&self) -> String {
84        let mut buf: Vec<u8> = Vec::new();
85        self.write_ewkb(&mut buf).unwrap();
86        let hex: String = buf
87            .iter()
88            .fold(String::new(), |s, &b| s + &format!("{:02X}", b));
89        hex
90    }
91}
92
93// --- helpers
94
95impl From<std::io::Error> for Error {
96    fn from(e: std::io::Error) -> Error {
97        Error::Read(format!("error while reading: {:?}", e))
98    }
99}
100
101// --- Point
102
103fn has_z(type_id: u32) -> bool {
104    type_id & 0x80000000 == 0x80000000
105}
106fn has_m(type_id: u32) -> bool {
107    type_id & 0x40000000 == 0x40000000
108}
109
110#[test]
111#[rustfmt::skip]
112fn test_point_write() {
113    // 'POINT (10 -20)'
114    let point = Point::new(10.0, -20.0, None);
115    assert_eq!(point.as_ewkb().to_hex_ewkb(), "0101000000000000000000244000000000000034C0");
116
117    // 'POINT (10 -20 100)'
118    let point = PointZ { x: 10.0, y: -20.0, z: 100.0, srid: None };
119    assert_eq!(point.as_ewkb().to_hex_ewkb(), "0101000080000000000000244000000000000034C00000000000005940");
120
121    // 'POINTM (10 -20 1)'
122    let point = PointM { x: 10.0, y: -20.0, m: 1.0, srid: None };
123    assert_eq!(point.as_ewkb().to_hex_ewkb(), "0101000040000000000000244000000000000034C0000000000000F03F");
124
125    // 'POINT (10 -20 100 1)'
126    let point = PointZM { x: 10.0, y: -20.0, z: 100.0, m: 1.0, srid: None };
127    assert_eq!(point.as_ewkb().to_hex_ewkb(), "01010000C0000000000000244000000000000034C00000000000005940000000000000F03F");
128
129    // 'POINT (-0 -1)'
130    let point = Point::new(0.0, -1.0, None);
131    assert_eq!(point.as_ewkb().to_hex_ewkb(), "01010000000000000000000000000000000000F0BF");
132    // TODO: -0 in PostGIS gives 01010000000000000000000080000000000000F0BF
133
134    // 'SRID=4326;POINT (10 -20)'
135    let point = Point::new(10.0, -20.0, Some(4326));
136    assert_eq!(point.as_ewkb().to_hex_ewkb(), "0101000020E6100000000000000000244000000000000034C0");
137}
138
139#[test]
140#[rustfmt::skip]
141fn test_line_write() {
142    let p = |x, y| Point::new(x, y, None);
143    // 'LINESTRING (10 -20, 0 -0.5)'
144    let line = LineStringT::<Point> {srid: None, points: vec![p(10.0, -20.0), p(0., -0.5)]};
145    assert_eq!(line.as_ewkb().to_hex_ewkb(), "010200000002000000000000000000244000000000000034C00000000000000000000000000000E0BF");
146
147    // 'SRID=4326;LINESTRING (10 -20, 0 -0.5)'
148    let line = LineStringT::<Point> {srid: Some(4326), points: vec![p(10.0, -20.0), p(0., -0.5)]};
149    assert_eq!(line.as_ewkb().to_hex_ewkb(), "0102000020E610000002000000000000000000244000000000000034C00000000000000000000000000000E0BF");
150
151    let p = |x, y, z| PointZ { x, y, z, srid: Some(4326) };
152    // 'SRID=4326;LINESTRING (10 -20 100, 0 0.5 101)'
153    let line = LineStringT::<PointZ> {srid: Some(4326), points: vec![p(10.0, -20.0, 100.0), p(0., -0.5, 101.0)]};
154    assert_eq!(line.as_ewkb().to_hex_ewkb(), "01020000A0E610000002000000000000000000244000000000000034C000000000000059400000000000000000000000000000E0BF0000000000405940");
155}
156
157#[test]
158#[rustfmt::skip]
159fn test_polygon_write() {
160    let p = |x, y| Point::new(x, y, Some(4326));
161    // SELECT 'SRID=4326;POLYGON ((0 0, 2 0, 2 2, 0 2, 0 0))'::geometry
162    let line = LineStringT::<Point> {srid: Some(4326), points: vec![p(0., 0.), p(2., 0.), p(2., 2.), p(0., 2.), p(0., 0.)]};
163    let poly = PolygonT::<Point> {srid: Some(4326), rings: vec![line]};
164    assert_eq!(poly.as_ewkb().to_hex_ewkb(), "0103000020E610000001000000050000000000000000000000000000000000000000000000000000400000000000000000000000000000004000000000000000400000000000000000000000000000004000000000000000000000000000000000");
165}
166
167#[test]
168#[rustfmt::skip]
169fn test_multipoint_write() {
170    let p = |x, y, z| PointZ { x, y, z, srid: Some(4326) };
171    // SELECT 'SRID=4326;MULTIPOINT ((10 -20 100), (0 -0.5 101))'::geometry
172    let points = MultiPointT::<PointZ> {srid: Some(4326), points: vec![p(10.0, -20.0, 100.0), p(0., -0.5, 101.0)]};
173    assert_eq!(points.as_ewkb().to_hex_ewkb(), "01040000A0E6100000020000000101000080000000000000244000000000000034C0000000000000594001010000800000000000000000000000000000E0BF0000000000405940");
174}
175
176#[test]
177#[rustfmt::skip]
178fn test_multiline_write() {
179    let p = |x, y| Point::new(x, y, Some(4326));
180    // SELECT 'SRID=4326;MULTILINESTRING ((10 -20, 0 -0.5), (0 0, 2 0))'::geometry
181    let line1 = LineStringT::<Point> {srid: Some(4326), points: vec![p(10.0, -20.0), p(0., -0.5)]};
182    let line2 = LineStringT::<Point> {srid: Some(4326), points: vec![p(0., 0.), p(2., 0.)]};
183    let multiline = MultiLineStringT::<Point> {srid: Some(4326),lines: vec![line1, line2]};
184    assert_eq!(multiline.as_ewkb().to_hex_ewkb(), "0105000020E610000002000000010200000002000000000000000000244000000000000034C00000000000000000000000000000E0BF0102000000020000000000000000000000000000000000000000000000000000400000000000000000");
185}
186
187#[test]
188#[rustfmt::skip]
189fn test_multipolygon_write() {
190    let p = |x, y| Point::new(x, y, Some(4326));
191    // SELECT 'SRID=4326;MULTIPOLYGON (((0 0, 2 0, 2 2, 0 2, 0 0)), ((10 10, -2 10, -2 -2, 10 -2, 10 10)))'::geometry
192    let line = LineStringT::<Point> {srid: Some(4326), points: vec![p(0., 0.), p(2., 0.), p(2., 2.), p(0., 2.), p(0., 0.)]};
193    let poly1 = PolygonT::<Point> {srid: Some(4326), rings: vec![line]};
194    let line = LineStringT::<Point> {srid: Some(4326), points: vec![p(10., 10.), p(-2., 10.), p(-2., -2.), p(10., -2.), p(10., 10.)]};
195    let poly2 = PolygonT::<Point> {srid: Some(4326), rings: vec![line]};
196    let multipoly = MultiPolygonT::<Point> {srid: Some(4326), polygons: vec![poly1, poly2]};
197    assert_eq!(multipoly.as_ewkb().to_hex_ewkb(), "0106000020E610000002000000010300000001000000050000000000000000000000000000000000000000000000000000400000000000000000000000000000004000000000000000400000000000000000000000000000004000000000000000000000000000000000010300000001000000050000000000000000002440000000000000244000000000000000C0000000000000244000000000000000C000000000000000C0000000000000244000000000000000C000000000000024400000000000002440");
198}
199
200#[test]
201#[rustfmt::skip]
202fn test_ewkb_adapters() {
203    let point = Point::new(10.0, -20.0, Some(4326));
204    let ewkb = EwkbPoint { geom: &point, srid: Some(4326), point_type: PointType::Point };
205    assert_eq!(ewkb.to_hex_ewkb(), "0101000020E6100000000000000000244000000000000034C0");
206    assert_eq!(point.as_ewkb().to_hex_ewkb(), "0101000020E6100000000000000000244000000000000034C0");
207}
208
209#[cfg(test)]
210#[rustfmt::skip]
211fn hex_to_vec(hexstr: &str) -> Vec<u8> {
212    hexstr.as_bytes().chunks(2).map(|chars| {
213        let hb = if chars[0] <= 57 { chars[0] - 48 } else { chars[0] - 55 };
214        let lb = if chars[1] <= 57 { chars[1] - 48 } else { chars[1] - 55 };
215        hb * 16 + lb
216    }).collect::<Vec<_>>()
217}
218
219#[test]
220#[rustfmt::skip]
221fn test_point_read() {
222    // SELECT 'POINT(10 -20)'::geometry
223    let ewkb = hex_to_vec("0101000000000000000000244000000000000034C0");
224    assert_eq!(ewkb, &[1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 64, 0, 0, 0, 0, 0, 0, 52, 192]);
225    let point = Point::read_ewkb(&mut ewkb.as_slice()).unwrap();
226    assert_eq!(point.x(), 10.0);
227    assert_eq!(point.y(), -20.0);
228    assert_eq!(point.srid, None);
229
230    // SELECT 'POINT(10 -20 100)'::geometry
231    let ewkb = hex_to_vec("0101000080000000000000244000000000000034C00000000000005940");
232    let point = PointZ::read_ewkb(&mut ewkb.as_slice()).unwrap();
233    assert_eq!(point, PointZ { x: 10.0, y: -20.0, z: 100.0, srid: None });
234
235    let point = Point::read_ewkb(&mut ewkb.as_slice()).unwrap();
236    assert_eq!(point.x(), 10.0);
237    assert_eq!(point.y(), -20.0);
238    assert_eq!(point.srid, None);
239
240    // SELECT 'POINTM(10 -20 1)'::geometry
241    let ewkb = hex_to_vec("0101000040000000000000244000000000000034C0000000000000F03F");
242    let point = PointM::read_ewkb(&mut ewkb.as_slice()).unwrap();
243    assert_eq!(point, PointM { x: 10.0, y: -20.0, m: 1.0, srid: None });
244
245    // SELECT 'POINT(10 -20 100 1)'::geometry
246    let ewkb = hex_to_vec("01010000C0000000000000244000000000000034C00000000000005940000000000000F03F");
247    let point = PointZM::read_ewkb(&mut ewkb.as_slice()).unwrap();
248    assert_eq!(point, PointZM { x: 10.0, y: -20.0, z: 100.0, m: 1.0, srid: None });
249}
250
251#[test]
252#[rustfmt::skip]
253fn test_line_read() {
254    let p = |x, y| Point::new(x, y, None);
255    // SELECT 'LINESTRING (10 -20, 0 -0.5)'::geometry
256    let ewkb = hex_to_vec("010200000002000000000000000000244000000000000034C00000000000000000000000000000E0BF");
257    let line = LineStringT::<Point>::read_ewkb(&mut ewkb.as_slice()).unwrap();
258    assert_eq!(line, LineStringT::<Point> {srid: None, points: vec![p(10.0, -20.0), p(0., -0.5)]});
259
260    let p = |x, y, z| PointZ { x, y, z, srid: Some(4326) };
261    // SELECT 'SRID=4326;LINESTRING (10 -20 100, 0 -0.5 101)'::geometry
262    let ewkb = hex_to_vec("01020000A0E610000002000000000000000000244000000000000034C000000000000059400000000000000000000000000000E0BF0000000000405940");
263    let line = LineStringT::<PointZ>::read_ewkb(&mut ewkb.as_slice()).unwrap();
264    assert_eq!(line, LineStringT::<PointZ> {srid: Some(4326), points: vec![p(10.0, -20.0, 100.0), p(0., -0.5, 101.0)]});
265}
266
267#[test]
268#[rustfmt::skip]
269fn test_polygon_read() {
270    let p = |x, y| Point::new(x, y, Some(4326));
271    // SELECT 'SRID=4326;POLYGON ((0 0, 2 0, 2 2, 0 2, 0 0))'::geometry
272    let ewkb = hex_to_vec("0103000020E610000001000000050000000000000000000000000000000000000000000000000000400000000000000000000000000000004000000000000000400000000000000000000000000000004000000000000000000000000000000000");
273    let poly = PolygonT::<Point>::read_ewkb(&mut ewkb.as_slice()).unwrap();
274    let line = LineStringT::<Point> {srid: Some(4326), points: vec![p(0., 0.), p(2., 0.), p(2., 2.), p(0., 2.), p(0., 0.)]};
275    assert_eq!(poly, PolygonT::<Point> {srid: Some(4326), rings: vec![line]});
276}
277
278#[test]
279#[rustfmt::skip]
280fn test_multipoint_read() {
281    let p = |x, y, z| PointZ { x, y, z, srid: None }; // PostGIS doesn't store SRID for sub-geometries
282    // SELECT 'SRID=4326;MULTIPOINT ((10 -20 100), (0 -0.5 101))'::geometry
283    let ewkb = hex_to_vec("01040000A0E6100000020000000101000080000000000000244000000000000034C0000000000000594001010000800000000000000000000000000000E0BF0000000000405940");
284    let points = MultiPointT::<PointZ>::read_ewkb(&mut ewkb.as_slice()).unwrap();
285    assert_eq!(points, MultiPointT::<PointZ> {srid: Some(4326), points: vec![p(10.0, -20.0, 100.0), p(0., -0.5, 101.0)]});
286}
287
288#[test]
289#[rustfmt::skip]
290fn test_multiline_read() {
291    let p = |x, y| Point::new(x, y, None); // PostGIS doesn't store SRID for sub-geometries
292    // SELECT 'SRID=4326;MULTILINESTRING ((10 -20, 0 -0.5), (0 0, 2 0))'::geometry
293    let ewkb = hex_to_vec("0105000020E610000002000000010200000002000000000000000000244000000000000034C00000000000000000000000000000E0BF0102000000020000000000000000000000000000000000000000000000000000400000000000000000");
294    let poly = MultiLineStringT::<Point>::read_ewkb(&mut ewkb.as_slice()).unwrap();
295    let line1 = LineStringT::<Point> {srid: None, points: vec![p(10.0, -20.0), p(0., -0.5)]};
296    let line2 = LineStringT::<Point> {srid: None, points: vec![p(0., 0.), p(2., 0.)]};
297    assert_eq!(poly, MultiLineStringT::<Point> {srid: Some(4326), lines: vec![line1, line2]});
298}
299
300#[test]
301#[rustfmt::skip]
302fn test_multipolygon_read() {
303    let p = |x, y| Point::new(x, y, None); // PostGIS doesn't store SRID for sub-geometries
304    // SELECT 'SRID=4326;MULTIPOLYGON (((0 0, 2 0, 2 2, 0 2, 0 0)), ((10 10, -2 10, -2 -2, 10 -2, 10 10)))'::geometry
305    let ewkb = hex_to_vec("0106000020E610000002000000010300000001000000050000000000000000000000000000000000000000000000000000400000000000000000000000000000004000000000000000400000000000000000000000000000004000000000000000000000000000000000010300000001000000050000000000000000002440000000000000244000000000000000C0000000000000244000000000000000C000000000000000C0000000000000244000000000000000C000000000000024400000000000002440");
306    let multipoly = MultiPolygonT::<Point>::read_ewkb(&mut ewkb.as_slice()).unwrap();
307    let line = LineStringT::<Point> {srid: None, points: vec![p(0., 0.), p(2., 0.), p(2., 2.), p(0., 2.), p(0., 0.)]};
308    let poly1 = PolygonT::<Point> {srid: None, rings: vec![line]};
309    let line = LineStringT::<Point> {srid: None, points: vec![p(10., 10.), p(-2., 10.), p(-2., -2.), p(10., -2.), p(10., 10.)]};
310    let poly2 = PolygonT::<Point> {srid: None, rings: vec![line]};
311    assert_eq!(multipoly, MultiPolygonT::<Point> {srid: Some(4326), polygons: vec![poly1, poly2]});
312}
313
314#[test]
315#[rustfmt::skip]
316fn test_geometrycollection_read() {
317    // SELECT 'GeometryCollection(POINT (10 10),POINT (30 30),LINESTRING (15 15, 20 20))'::geometry
318    let ewkb = hex_to_vec("01070000000300000001010000000000000000002440000000000000244001010000000000000000003E400000000000003E400102000000020000000000000000002E400000000000002E4000000000000034400000000000003440");
319    let geom = GeometryCollectionT::<Point>::read_ewkb(&mut ewkb.as_slice()).unwrap();
320    
321    // Check basic structure
322    assert_eq!(geom.geometries.len(), 3);
323    assert_eq!(geom.srid, None);
324    
325    // Check first point
326    match &geom.geometries[0] {
327        GeometryT::Point(pt) => {
328            assert_eq!(pt.x(), 10.0);
329            assert_eq!(pt.y(), 10.0);
330            assert_eq!(pt.srid, None);
331        },
332        _ => panic!("First geometry is not a Point")
333    }
334    
335    // Check second point
336    match &geom.geometries[1] {
337        GeometryT::Point(pt) => {
338            assert_eq!(pt.x(), 30.0);
339            assert_eq!(pt.y(), 30.0);
340            assert_eq!(pt.srid, None);
341        },
342        _ => panic!("Second geometry is not a Point")
343    }
344    
345    // Check linestring
346    match &geom.geometries[2] {
347        GeometryT::LineString(ls) => {
348            assert_eq!(ls.points.len(), 2);
349            assert_eq!(ls.points[0].x(), 15.0);
350            assert_eq!(ls.points[0].y(), 15.0);
351            assert_eq!(ls.points[1].x(), 20.0);
352            assert_eq!(ls.points[1].y(), 20.0);
353        },
354        _ => panic!("Third geometry is not a LineString")
355    }
356}
357
358#[test]
359#[rustfmt::skip]
360fn test_geometry_read() {
361    // SELECT 'POINT(10 -20 100 1)'::geometry
362    let ewkb = hex_to_vec("01010000C0000000000000244000000000000034C00000000000005940000000000000F03F");
363    let geom = GeometryT::<PointZM>::read_ewkb(&mut ewkb.as_slice()).unwrap();
364    assert_eq!(format!("{:.0?}", geom), "Point(PointZM { x: 10, y: -20, z: 100, m: 1, srid: None })");
365    // SELECT 'SRID=4326;LINESTRING (10 -20 100, 0 -0.5 101)'::geometry
366    let ewkb = hex_to_vec("01020000A0E610000002000000000000000000244000000000000034C000000000000059400000000000000000000000000000E0BF0000000000405940");
367    let geom = GeometryT::<PointZ>::read_ewkb(&mut ewkb.as_slice()).unwrap();
368    assert_eq!(format!("{:.1?}", geom), "LineString(LineStringT { points: [PointZ { x: 10.0, y: -20.0, z: 100.0, srid: Some(4326) }, PointZ { x: 0.0, y: -0.5, z: 101.0, srid: Some(4326) }], srid: Some(4326) })");
369    // SELECT 'SRID=4326;POLYGON ((0 0, 2 0, 2 2, 0 2, 0 0))'::geometry
370    let ewkb = hex_to_vec("0103000020E610000001000000050000000000000000000000000000000000000000000000000000400000000000000000000000000000004000000000000000400000000000000000000000000000004000000000000000000000000000000000");
371    let geom = GeometryT::<Point>::read_ewkb(&mut ewkb.as_slice()).unwrap();
372    
373    // Check polygon structure
374    match &geom {
375        GeometryT::Polygon(poly) => {
376            assert_eq!(poly.srid, Some(4326));
377            assert_eq!(poly.rings.len(), 1);
378            
379            // Check the points in the ring
380            let ring = &poly.rings[0];
381            assert_eq!(ring.points.len(), 5);
382            
383            // Create expected points
384            let expected_points = [
385                (0.0, 0.0),
386                (2.0, 0.0),
387                (2.0, 2.0),
388                (0.0, 2.0),
389                (0.0, 0.0)
390            ];
391            
392            // Verify each point in the ring
393            for (i, point) in ring.points.iter().enumerate() {
394                assert_eq!(point.x(), expected_points[i].0);
395                assert_eq!(point.y(), expected_points[i].1);
396                assert_eq!(point.srid, Some(4326));
397            }
398        },
399        _ => panic!("Geometry is not a Polygon")
400    }
401    // SELECT 'SRID=4326;MULTIPOINT ((10 -20 100), (0 -0.5 101))'::geometry
402    let ewkb = hex_to_vec("01040000A0E6100000020000000101000080000000000000244000000000000034C0000000000000594001010000800000000000000000000000000000E0BF0000000000405940");
403    let geom = GeometryT::<PointZ>::read_ewkb(&mut ewkb.as_slice()).unwrap();
404    assert_eq!(format!("{:.1?}", geom), "MultiPoint(MultiPointT { points: [PointZ { x: 10.0, y: -20.0, z: 100.0, srid: None }, PointZ { x: 0.0, y: -0.5, z: 101.0, srid: None }], srid: Some(4326) })");
405    // SELECT 'SRID=4326;MULTILINESTRING ((10 -20, 0 -0.5), (0 0, 2 0))'::geometry
406    let ewkb = hex_to_vec("0105000020E610000002000000010200000002000000000000000000244000000000000034C00000000000000000000000000000E0BF0102000000020000000000000000000000000000000000000000000000000000400000000000000000");
407    let geom = GeometryT::<Point>::read_ewkb(&mut ewkb.as_slice()).unwrap();
408    
409    // Check multilinestring structure
410    match &geom {
411        GeometryT::MultiLineString(mls) => {
412            assert_eq!(mls.srid, Some(4326));
413            assert_eq!(mls.lines.len(), 2);
414            
415            // First linestring
416            let line1 = &mls.lines[0];
417            assert_eq!(line1.points.len(), 2);
418            assert_eq!(line1.points[0].x(), 10.0);
419            assert_eq!(line1.points[0].y(), -20.0);
420            assert_eq!(line1.points[1].x(), 0.0);
421            assert_eq!(line1.points[1].y(), -0.5);
422            
423            // Second linestring
424            let line2 = &mls.lines[1];
425            assert_eq!(line2.points.len(), 2);
426            assert_eq!(line2.points[0].x(), 0.0);
427            assert_eq!(line2.points[0].y(), 0.0);
428            assert_eq!(line2.points[1].x(), 2.0);
429            assert_eq!(line2.points[1].y(), 0.0);
430        },
431        _ => panic!("Geometry is not a MultiLineString")
432    };
433    // SELECT 'SRID=4326;MULTIPOLYGON (((0 0, 2 0, 2 2, 0 2, 0 0)), ((10 10, -2 10, -2 -2, 10 -2, 10 10)))'::geometry
434    let ewkb = hex_to_vec("0106000020E610000002000000010300000001000000050000000000000000000000000000000000000000000000000000400000000000000000000000000000004000000000000000400000000000000000000000000000004000000000000000000000000000000000010300000001000000050000000000000000002440000000000000244000000000000000C0000000000000244000000000000000C000000000000000C0000000000000244000000000000000C000000000000024400000000000002440");
435    let geom = GeometryT::<Point>::read_ewkb(&mut ewkb.as_slice()).unwrap();
436    
437    // Check multipolygon structure
438    match &geom {
439        GeometryT::MultiPolygon(mpoly) => {
440            assert_eq!(mpoly.srid, Some(4326));
441            assert_eq!(mpoly.polygons.len(), 2);
442            
443            // First polygon
444            let poly1 = &mpoly.polygons[0];
445            assert_eq!(poly1.rings.len(), 1);
446            let ring1 = &poly1.rings[0];
447            assert_eq!(ring1.points.len(), 5);
448            
449            // Check coordinates of first polygon
450            let points1 = [
451                (0.0, 0.0),
452                (2.0, 0.0),
453                (2.0, 2.0),
454                (0.0, 2.0),
455                (0.0, 0.0)
456            ];
457            
458            for (i, pt) in ring1.points.iter().enumerate() {
459                assert_eq!(pt.x(), points1[i].0);
460                assert_eq!(pt.y(), points1[i].1);
461            }
462            
463            // Second polygon
464            let poly2 = &mpoly.polygons[1];
465            assert_eq!(poly2.rings.len(), 1);
466            let ring2 = &poly2.rings[0];
467            assert_eq!(ring2.points.len(), 5);
468            
469            // Check coordinates of second polygon
470            let points2 = [
471                (10.0, 10.0),
472                (-2.0, 10.0),
473                (-2.0, -2.0),
474                (10.0, -2.0),
475                (10.0, 10.0)
476            ];
477            
478            for (i, pt) in ring2.points.iter().enumerate() {
479                assert_eq!(pt.x(), points2[i].0);
480                assert_eq!(pt.y(), points2[i].1);
481            }
482        },
483        _ => panic!("Geometry is not a MultiPolygon")
484    };
485    // SELECT 'GeometryCollection(POINT (10 10),POINT (30 30),LINESTRING (15 15, 20 20))'::geometry
486    let ewkb = hex_to_vec("01070000000300000001010000000000000000002440000000000000244001010000000000000000003E400000000000003E400102000000020000000000000000002E400000000000002E4000000000000034400000000000003440");
487    let geom = GeometryT::<Point>::read_ewkb(&mut ewkb.as_slice()).unwrap();
488    
489    // Check geometry collection structure
490    match &geom {
491        GeometryT::GeometryCollection(gc) => {
492            assert_eq!(gc.srid, None);
493            assert_eq!(gc.geometries.len(), 3);
494            
495            // First point
496            match &gc.geometries[0] {
497                GeometryT::Point(pt) => {
498                    assert_eq!(pt.x(), 10.0);
499                    assert_eq!(pt.y(), 10.0);
500                },
501                _ => panic!("First geometry is not a Point")
502            }
503            
504            // Second point
505            match &gc.geometries[1] {
506                GeometryT::Point(pt) => {
507                    assert_eq!(pt.x(), 30.0);
508                    assert_eq!(pt.y(), 30.0);
509                },
510                _ => panic!("Second geometry is not a Point")
511            }
512            
513            // LineString
514            match &gc.geometries[2] {
515                GeometryT::LineString(ls) => {
516                    assert_eq!(ls.points.len(), 2);
517                    assert_eq!(ls.points[0].x(), 15.0);
518                    assert_eq!(ls.points[0].y(), 15.0);
519                    assert_eq!(ls.points[1].x(), 20.0);
520                    assert_eq!(ls.points[1].y(), 20.0);
521                },
522                _ => panic!("Third geometry is not a LineString")
523            }
524        },
525        _ => panic!("Geometry is not a GeometryCollection")
526    };
527}
528
529#[test]
530#[rustfmt::skip]
531fn test_read_error() {
532    // SELECT 'LINESTRING (10 -20, 0 -0.5)'::geometry
533    let ewkb = hex_to_vec("010200000002000000000000000000244000000000000034C00000000000000000000000000000E0BF");
534    let poly = PolygonT::<Point>::read_ewkb(&mut ewkb.as_slice());
535    assert!(poly.is_err()); // UnexpectedEof "failed to fill whole buffer"
536}
537
538#[test]
539#[rustfmt::skip]
540fn test_iterators() {
541    // Iterator traits:
542    use crate::types::LineString;
543
544    let p = |x, y| Point::new(x, y, None);
545    let line = self::LineStringT::<Point> {srid: Some(4326), points: vec![p(10.0, -20.0), p(0., -0.5)]};
546    let last_point = line.points().last().unwrap();
547    assert_eq!(last_point.x(), 0.);
548    assert_eq!(last_point.y(), -0.5);
549    assert_eq!(last_point.srid, None);
550}
551
552#[cfg(all(test, feature = "serde"))]
553mod serde_tests {
554    use super::*;
555    use serde_json;
556
557    #[test]
558    fn test_serde_point() {
559        let point = Point::new(10.0, 20.0, Some(4326));
560
561        let serialized = serde_json::to_string(&point).unwrap();
562        let deserialized: Point = serde_json::from_str(&serialized).unwrap();
563
564        assert_eq!(point, deserialized);
565    }
566
567    #[test]
568    fn test_serde_point_z() {
569        let point = PointZ {
570            x: 10.0,
571            y: 20.0,
572            z: 30.0,
573            srid: Some(4326),
574        };
575
576        let serialized = serde_json::to_string(&point).unwrap();
577        let deserialized: PointZ = serde_json::from_str(&serialized).unwrap();
578
579        assert_eq!(point, deserialized);
580    }
581
582    #[test]
583    fn test_serde_geometry_t() {
584        let point = Point::new(10.0, 20.0, Some(4326));
585        let geometry = GeometryT::Point(point);
586
587        let serialized = serde_json::to_string(&geometry).unwrap();
588        let deserialized: GeometryT<Point> = serde_json::from_str(&serialized).unwrap();
589
590        match deserialized {
591            GeometryT::Point(p) => assert_eq!(p, point),
592            _ => panic!("Deserialized to wrong variant"),
593        }
594    }
595}