postgis/
twkb.rs

1//
2// Copyright (c) Pirmin Kalberer. All rights reserved.
3//
4
5//! Read geometries in [Tiny WKB](https://github.com/TWKB/Specification/blob/master/twkb.md) format.
6//!
7//! ```rust,no_run
8//! # use postgres::{Client, NoTls};
9//! use postgis::{twkb, LineString, ewkb::AsEwkbPoint};
10//!
11//! # let mut client = Client::connect("host=localhost user=postgres", NoTls).unwrap();
12//! for row in &client.query("SELECT ST_AsTWKB(route) FROM busline", &[]).unwrap() {
13//!     let route: twkb::LineString = row.get(0);
14//!     let last_stop = route.points().last().unwrap();
15//!     let _ = client.execute("INSERT INTO stops (stop) VALUES ($1)", &[&last_stop.as_ewkb()]);
16//! }
17//! ```
18
19use crate::{error::Error, ewkb, types as postgis};
20use byteorder::ReadBytesExt;
21use std::f64;
22use std::fmt;
23use std::io::prelude::*;
24use std::slice::Iter;
25use std::u8;
26
27#[derive(PartialEq, Clone, Copy, Debug)]
28pub struct Point {
29    pub x: f64,
30    pub y: f64, // TODO: support for z, m
31}
32
33#[derive(PartialEq, Clone, Debug)]
34pub struct LineString {
35    pub points: Vec<Point>,
36}
37
38#[derive(PartialEq, Clone, Debug)]
39pub struct Polygon {
40    pub rings: Vec<LineString>,
41}
42
43#[derive(PartialEq, Clone, Debug)]
44pub struct MultiPoint {
45    pub points: Vec<Point>,
46    pub ids: Option<Vec<u64>>,
47}
48
49#[derive(PartialEq, Clone, Debug)]
50pub struct MultiLineString {
51    pub lines: Vec<LineString>,
52    pub ids: Option<Vec<u64>>,
53}
54
55#[derive(PartialEq, Clone, Debug)]
56pub struct MultiPolygon {
57    pub polygons: Vec<Polygon>,
58    pub ids: Option<Vec<u64>>,
59}
60
61#[doc(hidden)]
62#[derive(Default, Debug)]
63pub struct TwkbInfo {
64    geom_type: u8,
65    precision: i8,
66    has_idlist: bool,
67    is_empty_geom: bool,
68    size: Option<u64>,
69    has_z: bool,
70    has_m: bool,
71    prec_z: Option<u8>,
72    prec_m: Option<u8>,
73}
74
75pub trait TwkbGeom: fmt::Debug + Sized {
76    fn read_twkb<R: Read>(raw: &mut R) -> Result<Self, Error> {
77        let mut twkb_info: TwkbInfo = Default::default();
78        // type_and_prec     byte
79        // metadata_header   byte
80        // [extended_dims]   byte
81        // [size]            uvarint
82        // [bounds]          bbox
83        let type_and_prec = raw.read_u8()?;
84        twkb_info.geom_type = type_and_prec & 0x0F;
85        twkb_info.precision = decode_zig_zag_64(((type_and_prec & 0xF0) >> 4) as u64) as i8;
86        let metadata_header = raw.read_u8()?;
87        let has_bbox = (metadata_header & 0b0001) != 0;
88        let has_size_attribute = (metadata_header & 0b0010) != 0;
89        twkb_info.has_idlist = (metadata_header & 0b0100) != 0;
90        let has_ext_prec_info = (metadata_header & 0b1000) != 0;
91        twkb_info.is_empty_geom = (metadata_header & 0b10000) != 0;
92        if has_ext_prec_info {
93            let ext_prec_info = raw.read_u8()?;
94            twkb_info.has_z = ext_prec_info & 0b0001 != 0;
95            twkb_info.has_m = ext_prec_info & 0b0010 != 0;
96            twkb_info.prec_z = Some((ext_prec_info & 0x1C) >> 2);
97            twkb_info.prec_m = Some((ext_prec_info & 0xE0) >> 5);
98        }
99        if has_size_attribute {
100            twkb_info.size = Some(read_raw_varint64(raw)?);
101        }
102        if has_bbox {
103            let _xmin = read_int64(raw)?;
104            let _deltax = read_int64(raw)?;
105            let _ymin = read_int64(raw)?;
106            let _deltay = read_int64(raw)?;
107            if twkb_info.has_z {
108                let _zmin = read_int64(raw)?;
109                let _deltaz = read_int64(raw)?;
110            }
111            if twkb_info.has_m {
112                let _mmin = read_int64(raw)?;
113                let _deltam = read_int64(raw)?;
114            }
115        }
116        Self::read_twkb_body(raw, &twkb_info)
117    }
118
119    #[doc(hidden)]
120    fn read_twkb_body<R: Read>(raw: &mut R, twkb_info: &TwkbInfo) -> Result<Self, Error>;
121
122    #[doc(hidden)]
123    fn read_relative_point<R: Read>(
124        raw: &mut R,
125        twkb_info: &TwkbInfo,
126        x: f64,
127        y: f64,
128        z: Option<f64>,
129        m: Option<f64>,
130    ) -> Result<(f64, f64, Option<f64>, Option<f64>), Error> {
131        let x2 = x + read_varint64_as_f64(raw, twkb_info.precision)?;
132        let y2 = y + read_varint64_as_f64(raw, twkb_info.precision)?;
133        let z2 = if twkb_info.has_z {
134            let dz = read_varint64_as_f64(raw, twkb_info.precision)?;
135            z.map(|v| v + dz)
136        } else {
137            None
138        };
139        let m2 = if twkb_info.has_m {
140            let dm = read_varint64_as_f64(raw, twkb_info.precision)?;
141            m.map(|v| v + dm)
142        } else {
143            None
144        };
145        Ok((x2, y2, z2, m2))
146    }
147
148    fn read_idlist<R: Read>(raw: &mut R, size: usize) -> Result<Vec<u64>, Error> {
149        let mut idlist = Vec::new();
150        idlist.reserve(size);
151        for _ in 0..size {
152            let id = read_raw_varint64(raw)?;
153            idlist.push(id);
154        }
155        Ok(idlist)
156    }
157}
158
159// --- helper functions for reading ---
160
161fn read_raw_varint64<R: Read>(raw: &mut R) -> Result<u64, Error> {
162    // from rust-protobuf
163    let mut r: u64 = 0;
164    let mut i = 0;
165    loop {
166        if i == 10 {
167            return Err(Error::Read("invalid varint".into()));
168        }
169        let b = raw.read_u8()?;
170        // TODO: may overflow if i == 9
171        r = r | (((b & 0x7f) as u64) << (i * 7));
172        i += 1;
173        if b < 0x80 {
174            return Ok(r);
175        }
176    }
177}
178
179fn read_int64<R: Read>(raw: &mut R) -> Result<i64, Error> {
180    read_raw_varint64(raw).map(|v| v as i64)
181}
182
183fn decode_zig_zag_64(n: u64) -> i64 {
184    ((n >> 1) as i64) ^ (-((n & 1) as i64))
185}
186
187fn varint64_to_f64(varint: u64, precision: i8) -> f64 {
188    if precision >= 0 {
189        (decode_zig_zag_64(varint) as f64) / 10u64.pow(precision as u32) as f64
190    } else {
191        (decode_zig_zag_64(varint) as f64) * 10u64.pow(precision.abs() as u32) as f64
192    }
193}
194
195fn read_varint64_as_f64<R: Read>(raw: &mut R, precision: i8) -> Result<f64, Error> {
196    read_raw_varint64(raw).map(|v| varint64_to_f64(v, precision))
197}
198
199// ---
200
201impl Point {
202    fn new_from_opt_vals(x: f64, y: f64, _z: Option<f64>, _m: Option<f64>) -> Self {
203        Point { x: x, y: y }
204    }
205}
206
207impl postgis::Point for Point {
208    fn x(&self) -> f64 {
209        self.x
210    }
211    fn y(&self) -> f64 {
212        self.y
213    }
214}
215
216impl TwkbGeom for Point {
217    fn read_twkb_body<R: Read>(raw: &mut R, twkb_info: &TwkbInfo) -> Result<Self, Error> {
218        if twkb_info.is_empty_geom {
219            return Ok(Point::new_from_opt_vals(f64::NAN, f64::NAN, None, None));
220        }
221        let x = read_varint64_as_f64(raw, twkb_info.precision)?;
222        let y = read_varint64_as_f64(raw, twkb_info.precision)?;
223        let z = if twkb_info.has_z {
224            Some(read_varint64_as_f64(raw, twkb_info.precision)?)
225        } else {
226            None
227        };
228        let m = if twkb_info.has_m {
229            Some(read_varint64_as_f64(raw, twkb_info.precision)?)
230        } else {
231            None
232        };
233        Ok(Self::new_from_opt_vals(x, y, z, m))
234    }
235}
236
237impl<'a> ewkb::AsEwkbPoint<'a> for Point {
238    fn as_ewkb(&'a self) -> ewkb::EwkbPoint<'a> {
239        ewkb::EwkbPoint {
240            geom: self,
241            srid: None,
242            point_type: ewkb::PointType::Point,
243        }
244    }
245}
246
247impl TwkbGeom for LineString {
248    fn read_twkb_body<R: Read>(raw: &mut R, twkb_info: &TwkbInfo) -> Result<Self, Error> {
249        // npoints           uvarint
250        // pointarray        varint[]
251        let mut points: Vec<Point> = Vec::new();
252        if !twkb_info.is_empty_geom {
253            let npoints = read_raw_varint64(raw)?;
254            points.reserve(npoints as usize);
255            let mut x = 0.0;
256            let mut y = 0.0;
257            let mut z = if twkb_info.has_z { Some(0.0) } else { None };
258            let mut m = if twkb_info.has_m { Some(0.0) } else { None };
259            for _ in 0..npoints {
260                let (x2, y2, z2, m2) = Self::read_relative_point(raw, twkb_info, x, y, z, m)?;
261                points.push(Point::new_from_opt_vals(x2, y2, z2, m2));
262                x = x2;
263                y = y2;
264                z = z2;
265                m = m2;
266            }
267        }
268        Ok(LineString { points: points })
269    }
270}
271
272impl<'a> postgis::LineString<'a> for LineString {
273    type ItemType = Point;
274    type Iter = Iter<'a, Self::ItemType>;
275    fn points(&'a self) -> Self::Iter {
276        self.points.iter()
277    }
278}
279
280impl<'a> ewkb::AsEwkbLineString<'a> for LineString {
281    type PointType = Point;
282    type Iter = Iter<'a, Point>;
283    fn as_ewkb(&'a self) -> ewkb::EwkbLineString<'a, Self::PointType, Self::Iter> {
284        ewkb::EwkbLineString {
285            geom: self,
286            srid: None,
287            point_type: ewkb::PointType::Point,
288        }
289    }
290}
291
292impl TwkbGeom for Polygon {
293    fn read_twkb_body<R: Read>(raw: &mut R, twkb_info: &TwkbInfo) -> Result<Self, Error> {
294        // nrings            uvarint
295        // npoints[0]        uvarint
296        // pointarray[0]     varint[]
297        // ...
298        // npoints[n]        uvarint
299        // pointarray[n]     varint[]
300        let mut rings: Vec<LineString> = Vec::new();
301        let nrings = read_raw_varint64(raw)?;
302        rings.reserve(nrings as usize);
303        let mut x = 0.0;
304        let mut y = 0.0;
305        let mut z = if twkb_info.has_z { Some(0.0) } else { None };
306        let mut m = if twkb_info.has_m { Some(0.0) } else { None };
307        for _ in 0..nrings {
308            let mut points: Vec<Point> = Vec::new();
309            let npoints = read_raw_varint64(raw)?;
310            points.reserve(npoints as usize);
311            let (x0, y0, z0, m0) = (x, y, z, m);
312            for _ in 0..npoints {
313                let (x2, y2, z2, m2) = Self::read_relative_point(raw, twkb_info, x, y, z, m)?;
314                points.push(Point::new_from_opt_vals(x2, y2, z2, m2));
315                x = x2;
316                y = y2;
317                z = z2;
318                m = m2;
319            }
320            // close ring, if necessary
321            if x != x0 && y != y0 && z != z0 && m != m0 {
322                points.push(Point::new_from_opt_vals(x0, y0, z0, m0));
323            }
324            rings.push(LineString { points: points });
325        }
326        Ok(Polygon { rings: rings })
327    }
328}
329
330impl<'a> postgis::Polygon<'a> for Polygon {
331    type ItemType = LineString;
332    type Iter = Iter<'a, Self::ItemType>;
333    fn rings(&'a self) -> Self::Iter {
334        self.rings.iter()
335    }
336}
337
338impl<'a> ewkb::AsEwkbPolygon<'a> for Polygon {
339    type PointType = Point;
340    type PointIter = Iter<'a, Point>;
341    type ItemType = LineString;
342    type Iter = Iter<'a, Self::ItemType>;
343    fn as_ewkb(
344        &'a self,
345    ) -> ewkb::EwkbPolygon<'a, Self::PointType, Self::PointIter, Self::ItemType, Self::Iter> {
346        ewkb::EwkbPolygon {
347            geom: self,
348            srid: None,
349            point_type: ewkb::PointType::Point,
350        }
351    }
352}
353
354impl TwkbGeom for MultiPoint {
355    fn read_twkb_body<R: Read>(raw: &mut R, twkb_info: &TwkbInfo) -> Result<Self, Error> {
356        // npoints           uvarint
357        // [idlist]          varint[]
358        // pointarray        varint[]
359        let mut points: Vec<Point> = Vec::new();
360        let mut ids: Option<Vec<u64>> = None;
361        if !twkb_info.is_empty_geom {
362            let npoints = read_raw_varint64(raw)?;
363            points.reserve(npoints as usize);
364
365            if twkb_info.has_idlist {
366                let idlist = Self::read_idlist(raw, npoints as usize)?;
367                ids = Some(idlist);
368            }
369
370            let mut x = 0.0;
371            let mut y = 0.0;
372            let mut z = if twkb_info.has_z { Some(0.0) } else { None };
373            let mut m = if twkb_info.has_m { Some(0.0) } else { None };
374            for _ in 0..npoints {
375                let (x2, y2, z2, m2) = Self::read_relative_point(raw, twkb_info, x, y, z, m)?;
376                points.push(Point::new_from_opt_vals(x2, y2, z2, m2));
377                x = x2;
378                y = y2;
379                z = z2;
380                m = m2;
381            }
382        }
383        Ok(MultiPoint {
384            points: points,
385            ids: ids,
386        })
387    }
388}
389
390impl<'a> postgis::MultiPoint<'a> for MultiPoint {
391    type ItemType = Point;
392    type Iter = Iter<'a, Self::ItemType>;
393    fn points(&'a self) -> Self::Iter {
394        self.points.iter()
395    }
396}
397
398impl<'a> ewkb::AsEwkbMultiPoint<'a> for MultiPoint {
399    type PointType = Point;
400    type Iter = Iter<'a, Point>;
401    fn as_ewkb(&'a self) -> ewkb::EwkbMultiPoint<'a, Self::PointType, Self::Iter> {
402        ewkb::EwkbMultiPoint {
403            geom: self,
404            srid: None,
405            point_type: ewkb::PointType::Point,
406        }
407    }
408}
409
410impl TwkbGeom for MultiLineString {
411    fn read_twkb_body<R: Read>(raw: &mut R, twkb_info: &TwkbInfo) -> Result<Self, Error> {
412        // nlinestrings      uvarint
413        // [idlist]          varint[]
414        // npoints[0]        uvarint
415        // pointarray[0]     varint[]
416        // ...
417        // npoints[n]        uvarint
418        // pointarray[n]     varint[]
419        let mut lines: Vec<LineString> = Vec::new();
420        let mut ids: Option<Vec<u64>> = None;
421        let nlines = read_raw_varint64(raw)?;
422        lines.reserve(nlines as usize);
423
424        if twkb_info.has_idlist {
425            let idlist = Self::read_idlist(raw, nlines as usize)?;
426            ids = Some(idlist);
427        }
428
429        let mut x = 0.0;
430        let mut y = 0.0;
431        let mut z = if twkb_info.has_z { Some(0.0) } else { None };
432        let mut m = if twkb_info.has_m { Some(0.0) } else { None };
433        for _ in 0..nlines {
434            let mut points: Vec<Point> = Vec::new();
435            let npoints = read_raw_varint64(raw)?;
436            points.reserve(npoints as usize);
437            for _ in 0..npoints {
438                let (x2, y2, z2, m2) = Self::read_relative_point(raw, twkb_info, x, y, z, m)?;
439                points.push(Point::new_from_opt_vals(x2, y2, z2, m2));
440                x = x2;
441                y = y2;
442                z = z2;
443                m = m2;
444            }
445            lines.push(LineString { points: points });
446        }
447        Ok(MultiLineString {
448            lines: lines,
449            ids: ids,
450        })
451    }
452}
453
454impl<'a> postgis::MultiLineString<'a> for MultiLineString {
455    type ItemType = LineString;
456    type Iter = Iter<'a, Self::ItemType>;
457    fn lines(&'a self) -> Self::Iter {
458        self.lines.iter()
459    }
460}
461
462impl<'a> ewkb::AsEwkbMultiLineString<'a> for MultiLineString {
463    type PointType = Point;
464    type PointIter = Iter<'a, Point>;
465    type ItemType = LineString;
466    type Iter = Iter<'a, Self::ItemType>;
467    fn as_ewkb(
468        &'a self,
469    ) -> ewkb::EwkbMultiLineString<'a, Self::PointType, Self::PointIter, Self::ItemType, Self::Iter>
470    {
471        ewkb::EwkbMultiLineString {
472            geom: self,
473            srid: None,
474            point_type: ewkb::PointType::Point,
475        }
476    }
477}
478
479impl TwkbGeom for MultiPolygon {
480    fn read_twkb_body<R: Read>(raw: &mut R, twkb_info: &TwkbInfo) -> Result<Self, Error> {
481        // npolygons         uvarint
482        // [idlist]          varint[]
483        // nrings[0]         uvarint
484        // npoints[0][0]     uvarint
485        // pointarray[0][0]  varint[]
486        // ...
487        // nrings[n]         uvarint
488        // npoints[n][m]     uvarint
489        // pointarray[n][m]  varint[]
490        let mut polygons: Vec<Polygon> = Vec::new();
491        let mut ids: Option<Vec<u64>> = None;
492        let npolygons = read_raw_varint64(raw)?;
493        polygons.reserve(npolygons as usize);
494
495        if twkb_info.has_idlist {
496            let idlist = Self::read_idlist(raw, npolygons as usize)?;
497            ids = Some(idlist);
498        }
499
500        let mut x = 0.0;
501        let mut y = 0.0;
502        let mut z = if twkb_info.has_z { Some(0.0) } else { None };
503        let mut m = if twkb_info.has_m { Some(0.0) } else { None };
504        for _ in 0..npolygons {
505            let mut rings: Vec<LineString> = Vec::new();
506            let nrings = read_raw_varint64(raw)?;
507            rings.reserve(nrings as usize);
508            for _ in 0..nrings {
509                let mut points: Vec<Point> = Vec::new();
510                let npoints = read_raw_varint64(raw)?;
511                points.reserve(npoints as usize);
512                let (x0, y0, z0, m0) = (x, y, z, m);
513                for _ in 0..npoints {
514                    let (x2, y2, z2, m2) = Self::read_relative_point(raw, twkb_info, x, y, z, m)?;
515                    points.push(Point::new_from_opt_vals(x2, y2, z2, m2));
516                    x = x2;
517                    y = y2;
518                    z = z2;
519                    m = m2;
520                }
521                // close ring, if necessary
522                if x != x0 && y != y0 && z != z0 && m != m0 {
523                    points.push(Point::new_from_opt_vals(x0, y0, z0, m0));
524                }
525                rings.push(LineString { points: points });
526            }
527            polygons.push(Polygon { rings: rings });
528        }
529        Ok(MultiPolygon {
530            polygons: polygons,
531            ids: ids,
532        })
533    }
534}
535
536impl<'a> postgis::MultiPolygon<'a> for MultiPolygon {
537    type ItemType = Polygon;
538    type Iter = Iter<'a, Self::ItemType>;
539    fn polygons(&'a self) -> Self::Iter {
540        self.polygons.iter()
541    }
542}
543
544impl<'a> ewkb::AsEwkbMultiPolygon<'a> for MultiPolygon {
545    type PointType = Point;
546    type PointIter = Iter<'a, Point>;
547    type LineType = LineString;
548    type LineIter = Iter<'a, Self::LineType>;
549    type ItemType = Polygon;
550    type Iter = Iter<'a, Self::ItemType>;
551    fn as_ewkb(
552        &'a self,
553    ) -> ewkb::EwkbMultiPolygon<
554        'a,
555        Self::PointType,
556        Self::PointIter,
557        Self::LineType,
558        Self::LineIter,
559        Self::ItemType,
560        Self::Iter,
561    > {
562        ewkb::EwkbMultiPolygon {
563            geom: self,
564            srid: None,
565            point_type: ewkb::PointType::Point,
566        }
567    }
568}
569
570#[cfg(test)]
571use ewkb::{
572    AsEwkbLineString, AsEwkbMultiLineString, AsEwkbMultiPoint, AsEwkbMultiPolygon, AsEwkbPoint,
573    AsEwkbPolygon, EwkbWrite,
574};
575
576#[cfg(test)]
577#[cfg_attr(rustfmt, rustfmt_skip)]
578fn hex_to_vec(hexstr: &str) -> Vec<u8> {
579    hexstr.as_bytes().chunks(2).map(|chars| {
580        let hb = if chars[0] <= 57 { chars[0] - 48 } else { chars[0] - 87 };
581        let lb = if chars[1] <= 57 { chars[1] - 48 } else { chars[1] - 87 };
582        hb * 16 + lb
583    }).collect::<Vec<_>>()
584}
585
586#[test]
587#[cfg_attr(rustfmt, rustfmt_skip)]
588fn test_read_point() {
589    let twkb = hex_to_vec("01001427"); // SELECT encode(ST_AsTWKB('POINT(10 -20)'::geometry), 'hex')
590    let point = Point::read_twkb(&mut twkb.as_slice()).unwrap();
591    assert_eq!(format!("{:.0?}", point), "Point { x: 10, y: -20 }");
592
593    let twkb = hex_to_vec("0108011427c601"); // SELECT encode(ST_AsTWKB('POINT(10 -20 99)'::geometry), 'hex')
594    let point = Point::read_twkb(&mut twkb.as_slice()).unwrap();
595    assert_eq!(format!("{:.0?}", point), "Point { x: 10, y: -20 }");
596
597    let twkb = hex_to_vec("2100ca019503"); // SELECT encode(ST_AsTWKB('POINT(10.12 -20.34)'::geometry, 1), 'hex')
598    let point = Point::read_twkb(&mut twkb.as_slice()).unwrap();
599    assert_eq!(format!("{:.1?}", point), "Point { x: 10.1, y: -20.3 }");
600
601    let twkb = hex_to_vec("11000203"); // SELECT encode(ST_AsTWKB('POINT(11.12 -22.34)'::geometry, -1), 'hex')
602    let point = Point::read_twkb(&mut twkb.as_slice()).unwrap();
603    assert_eq!(format!("{:.0?}", point), "Point { x: 10, y: -20 }");
604
605    let twkb = hex_to_vec("0110"); // SELECT encode(ST_AsTWKB('POINT EMPTY'::geometry), 'hex')
606    let point = Point::read_twkb(&mut twkb.as_slice()).unwrap();
607    assert_eq!(format!("{:?}", point), "Point { x: NaN, y: NaN }");
608
609    let twkb = hex_to_vec("a10080897aff91f401"); // SELECT encode(ST_AsTWKB('SRID=4326;POINT(10 -20)'::geometry), 'hex')
610    let point = Point::read_twkb(&mut twkb.as_slice()).unwrap();
611    assert_eq!(format!("{:.0?}", point), "Point { x: 10, y: -20 }");
612}
613
614#[test]
615#[cfg_attr(rustfmt, rustfmt_skip)]
616fn test_read_line() {
617    let twkb = hex_to_vec("02000214271326"); // SELECT encode(ST_AsTWKB('LINESTRING (10 -20, -0 -0.5)'::geometry), 'hex')
618    let line = LineString::read_twkb(&mut twkb.as_slice()).unwrap();
619    assert_eq!(format!("{:.0?}", line), "LineString { points: [Point { x: 10, y: -20 }, Point { x: 0, y: -1 }] }");
620
621    let twkb = hex_to_vec("220002c8018f03c7018603"); // SELECT encode(ST_AsTWKB('LINESTRING (10 -20, -0 -0.5)'::geometry, 1), 'hex')
622    let line = LineString::read_twkb(&mut twkb.as_slice()).unwrap();
623    assert_eq!(format!("{:.1?}", line), "LineString { points: [Point { x: 10.0, y: -20.0 }, Point { x: 0.0, y: -0.5 }] }");
624
625    let twkb = hex_to_vec("0210"); // SELECT encode(ST_AsTWKB('LINESTRING EMPTY'::geometry), 'hex')
626    let line = LineString::read_twkb(&mut twkb.as_slice()).unwrap();
627    assert_eq!(format!("{:?}", line), "LineString { points: [] }");
628}
629
630#[test]
631#[cfg_attr(rustfmt, rustfmt_skip)]
632fn test_read_polygon() {
633    let twkb = hex_to_vec("03000205000004000004030000030514141700001718000018"); // SELECT encode(ST_AsTWKB('POLYGON ((0 0, 2 0, 2 2, 0 2, 0 0),(10 10, -2 10, -2 -2, 10 -2, 10 10))'::geometry), 'hex')
634    let poly = Polygon::read_twkb(&mut twkb.as_slice()).unwrap();
635    assert_eq!(format!("{:.0?}", poly), "Polygon { rings: [LineString { points: [Point { x: 0, y: 0 }, Point { x: 2, y: 0 }, Point { x: 2, y: 2 }, Point { x: 0, y: 2 }, Point { x: 0, y: 0 }] }, LineString { points: [Point { x: 10, y: 10 }, Point { x: -2, y: 10 }, Point { x: -2, y: -2 }, Point { x: 10, y: -2 }, Point { x: 10, y: 10 }] }] }");
636}
637
638#[test]
639#[cfg_attr(rustfmt, rustfmt_skip)]
640fn test_read_multipoint() {
641    let twkb = hex_to_vec("04000214271326"); // SELECT encode(ST_AsTWKB('MULTIPOINT ((10 -20), (0 -0.5))'::geometry), 'hex')
642    let points = MultiPoint::read_twkb(&mut twkb.as_slice()).unwrap();
643    assert_eq!(format!("{:.0?}", points), "MultiPoint { points: [Point { x: 10, y: -20 }, Point { x: 0, y: -1 }], ids: None }");
644}
645
646#[test]
647#[cfg_attr(rustfmt, rustfmt_skip)]
648fn test_read_multiline() {
649    let twkb = hex_to_vec("05000202142713260200020400"); // SELECT encode(ST_AsTWKB('MULTILINESTRING ((10 -20, 0 -0.5), (0 0, 2 0))'::geometry), 'hex')
650    let lines = MultiLineString::read_twkb(&mut twkb.as_slice()).unwrap();
651    assert_eq!(format!("{:.0?}", lines), "MultiLineString { lines: [LineString { points: [Point { x: 10, y: -20 }, Point { x: 0, y: -1 }] }, LineString { points: [Point { x: 0, y: 0 }, Point { x: 2, y: 0 }] }], ids: None }");
652}
653
654#[test]
655#[cfg_attr(rustfmt, rustfmt_skip)]
656fn test_read_multipolygon() {
657    let twkb = hex_to_vec("060002010500000400000403000003010514141700001718000018"); // SELECT encode(ST_AsTWKB('MULTIPOLYGON (((0 0, 2 0, 2 2, 0 2, 0 0)), ((10 10, -2 10, -2 -2, 10 -2, 10 10)))'::geometry), 'hex')
658    let polys = MultiPolygon::read_twkb(&mut twkb.as_slice()).unwrap();
659    assert_eq!(format!("{:.0?}", polys), "MultiPolygon { polygons: [Polygon { rings: [LineString { points: [Point { x: 0, y: 0 }, Point { x: 2, y: 0 }, Point { x: 2, y: 2 }, Point { x: 0, y: 2 }, Point { x: 0, y: 0 }] }] }, Polygon { rings: [LineString { points: [Point { x: 10, y: 10 }, Point { x: -2, y: 10 }, Point { x: -2, y: -2 }, Point { x: 10, y: -2 }, Point { x: 10, y: 10 }] }] }], ids: None }");
660}
661
662#[test]
663#[cfg_attr(rustfmt, rustfmt_skip)]
664fn test_write_point() {
665    let twkb = hex_to_vec("01001427"); // SELECT encode(ST_AsTWKB('POINT(10 -20)'::geometry), 'hex')
666    let point = Point::read_twkb(&mut twkb.as_slice()).unwrap();
667    assert_eq!(format!("{:?}", point.as_ewkb()), "EwkbPoint");
668    assert_eq!(point.as_ewkb().to_hex_ewkb(), "0101000000000000000000244000000000000034C0");
669}
670
671#[test]
672#[cfg_attr(rustfmt, rustfmt_skip)]
673fn test_write_line() {
674    let twkb = hex_to_vec("220002c8018f03c7018603"); // SELECT encode(ST_AsTWKB('LINESTRING (10 -20, -0 -0.5)'::geometry, 1), 'hex')
675    let line = LineString::read_twkb(&mut twkb.as_slice()).unwrap();
676    assert_eq!(format!("{:?}", line.as_ewkb()), "EwkbLineString");
677    assert_eq!(line.as_ewkb().to_hex_ewkb(), "010200000002000000000000000000244000000000000034C00000000000000000000000000000E0BF");
678}
679
680#[test]
681#[cfg_attr(rustfmt, rustfmt_skip)]
682fn test_write_polygon() {
683    let twkb = hex_to_vec("03000205000004000004030000030514141700001718000018"); // SELECT encode(ST_AsTWKB('POLYGON ((0 0, 2 0, 2 2, 0 2, 0 0),(10 10, -2 10, -2 -2, 10 -2, 10 10))'::geometry), 'hex')
684    let polygon = Polygon::read_twkb(&mut twkb.as_slice()).unwrap();
685    assert_eq!(format!("{:?}", polygon.as_ewkb()), "EwkbPolygon");
686    assert_eq!(polygon.as_ewkb().to_hex_ewkb(), "010300000002000000050000000000000000000000000000000000000000000000000000400000000000000000000000000000004000000000000000400000000000000000000000000000004000000000000000000000000000000000050000000000000000002440000000000000244000000000000000C0000000000000244000000000000000C000000000000000C0000000000000244000000000000000C000000000000024400000000000002440");
687}
688
689#[test]
690#[cfg_attr(rustfmt, rustfmt_skip)]
691fn test_write_multipoint() {
692    let twkb = hex_to_vec("04000214271326"); // SELECT encode(ST_AsTWKB('MULTIPOINT ((10 -20), (0 -0.5))'::geometry), 'hex')
693    let multipoint = MultiPoint::read_twkb(&mut twkb.as_slice()).unwrap();
694    assert_eq!(format!("{:?}", multipoint.as_ewkb()), "EwkbMultiPoint");
695    //assert_eq!(multipoint.as_ewkb().to_hex_ewkb(), "0104000000020000000101000000000000000000244000000000000034C001010000000000000000000000000000000000E0BF");
696    // "MULTIPOINT(10 -20,0 -1)"
697    assert_eq!(multipoint.as_ewkb().to_hex_ewkb(), "0104000000020000000101000000000000000000244000000000000034C001010000000000000000000000000000000000F0BF");
698}
699
700#[test]
701#[cfg_attr(rustfmt, rustfmt_skip)]
702fn test_write_multiline() {
703    let twkb = hex_to_vec("05000202142713260200020400"); // SELECT encode(ST_AsTWKB('MULTILINESTRING ((10 -20, 0 -0.5), (0 0, 2 0))'::geometry), 'hex')
704    let multiline = MultiLineString::read_twkb(&mut twkb.as_slice()).unwrap();
705    assert_eq!(format!("{:?}", multiline.as_ewkb()), "EwkbMultiLineString");
706    //assert_eq!(multiline.as_ewkb().to_hex_ewkb(), "010500000002000000010200000002000000000000000000244000000000000034C00000000000000000000000000000E0BF0102000000020000000000000000000000000000000000000000000000000000400000000000000000");
707    // "MULTILINESTRING((10 -20,0 -1),(0 0,2 0))"
708    assert_eq!(multiline.as_ewkb().to_hex_ewkb(), "010500000002000000010200000002000000000000000000244000000000000034C00000000000000000000000000000F0BF0102000000020000000000000000000000000000000000000000000000000000400000000000000000");
709}
710
711#[test]
712#[cfg_attr(rustfmt, rustfmt_skip)]
713fn test_write_multipoly() {
714    let twkb = hex_to_vec("060002010500000400000403000003010514141700001718000018"); // SELECT encode(ST_AsTWKB('MULTIPOLYGON (((0 0, 2 0, 2 2, 0 2, 0 0)), ((10 10, -2 10, -2 -2, 10 -2, 10 10)))'::geometry), 'hex')
715    let multipoly = MultiPolygon::read_twkb(&mut twkb.as_slice()).unwrap();
716    assert_eq!(format!("{:?}", multipoly.as_ewkb()), "EwkbMultiPolygon");
717    assert_eq!(multipoly.as_ewkb().to_hex_ewkb(), "010600000002000000010300000001000000050000000000000000000000000000000000000000000000000000400000000000000000000000000000004000000000000000400000000000000000000000000000004000000000000000000000000000000000010300000001000000050000000000000000002440000000000000244000000000000000C0000000000000244000000000000000C000000000000000C0000000000000244000000000000000C000000000000024400000000000002440");
718}