[go: up one dir, main page]

postgis/
ewkb.rs

1//
2// Copyright (c) ShuYu Wang <andelf@gmail.com>, Feather Workshop and Pirmin Kalberer. All rights reserved.
3//
4//! Read and write geometries in [OGC WKB](http://www.opengeospatial.org/standards/sfa) format.
5//!
6//! Support for SRID information according to [PostGIS EWKB extensions](https://git.osgeo.org/gitea/postgis/postgis/src/branch/master/doc/ZMSgeoms.txt)
7
8use crate::{error::Error, types as postgis};
9use byteorder::{BigEndian, LittleEndian, ReadBytesExt, WriteBytesExt};
10use std;
11use std::fmt;
12use std::io::prelude::*;
13use std::iter::FromIterator;
14use std::slice::Iter;
15
16// --- Structs for reading PostGIS geometries into
17
18#[derive(PartialEq, Clone, Copy, Debug)]
19pub struct Point {
20    pub x: f64,
21    pub y: f64,
22    pub srid: Option<i32>,
23}
24
25#[derive(PartialEq, Clone, Copy, Debug)]
26pub struct PointZ {
27    pub x: f64,
28    pub y: f64,
29    pub z: f64,
30    pub srid: Option<i32>,
31}
32
33#[derive(PartialEq, Clone, Copy, Debug)]
34pub struct PointM {
35    pub x: f64,
36    pub y: f64,
37    pub m: f64,
38    pub srid: Option<i32>,
39}
40
41#[derive(PartialEq, Clone, Copy, Debug)]
42pub struct PointZM {
43    pub x: f64,
44    pub y: f64,
45    pub z: f64,
46    pub m: f64,
47    pub srid: Option<i32>,
48}
49
50#[derive(PartialEq, Clone, Copy, Debug)]
51pub enum PointType {
52    Point,
53    PointZ,
54    PointM,
55    PointZM,
56}
57
58// --- Traits
59
60pub trait EwkbRead: fmt::Debug + Sized {
61    fn point_type() -> PointType;
62
63    fn read_ewkb<R: Read>(raw: &mut R) -> Result<Self, Error> {
64        let byte_order = raw.read_i8()?;
65        let is_be = byte_order == 0i8;
66
67        let type_id = read_u32(raw, is_be)?;
68        let mut srid: Option<i32> = None;
69        if type_id & 0x20000000 == 0x20000000 {
70            srid = Some(read_i32(raw, is_be)?);
71        }
72        Self::read_ewkb_body(raw, is_be, type_id, srid)
73    }
74
75    #[doc(hidden)]
76    fn read_ewkb_body<R: Read>(
77        raw: &mut R,
78        is_be: bool,
79        type_id: u32,
80        srid: Option<i32>,
81    ) -> Result<Self, Error>;
82}
83
84pub trait EwkbWrite: fmt::Debug + Sized {
85    fn opt_srid(&self) -> Option<i32> {
86        None
87    }
88
89    fn wkb_type_id(point_type: &PointType, srid: Option<i32>) -> u32 {
90        let mut type_ = 0;
91        if srid.is_some() {
92            type_ |= 0x20000000;
93        }
94        if *point_type == PointType::PointZ || *point_type == PointType::PointZM {
95            type_ |= 0x80000000;
96        }
97        if *point_type == PointType::PointM || *point_type == PointType::PointZM {
98            type_ |= 0x40000000;
99        }
100        type_
101    }
102
103    fn type_id(&self) -> u32;
104
105    fn write_ewkb<W: Write + ?Sized>(&self, w: &mut W) -> Result<(), Error> {
106        // use LE
107        w.write_u8(0x01)?;
108        let type_id = self.type_id();
109        w.write_u32::<LittleEndian>(type_id)?;
110        self.opt_srid()
111            .map(|srid| w.write_i32::<LittleEndian>(srid));
112        self.write_ewkb_body(w)?;
113        Ok(())
114    }
115    #[doc(hidden)]
116    fn write_ewkb_body<W: Write + ?Sized>(&self, w: &mut W) -> Result<(), Error>;
117
118    fn to_hex_ewkb(&self) -> String {
119        let mut buf: Vec<u8> = Vec::new();
120        let _ = self.write_ewkb(&mut buf).unwrap();
121        let hex: String = buf
122            .iter()
123            .fold(String::new(), |s, &b| s + &format!("{:02X}", b));
124        hex
125    }
126}
127
128// --- helpers
129
130impl From<std::io::Error> for Error {
131    fn from(e: std::io::Error) -> Error {
132        Error::Read(format!("error while reading: {:?}", e))
133    }
134}
135
136fn read_u32<R: Read>(raw: &mut R, is_be: bool) -> Result<u32, Error> {
137    Ok(if is_be {
138        raw.read_u32::<BigEndian>()?
139    } else {
140        raw.read_u32::<LittleEndian>()?
141    })
142}
143
144fn read_i32<R: Read>(raw: &mut R, is_be: bool) -> Result<i32, Error> {
145    Ok(if is_be {
146        raw.read_i32::<BigEndian>()?
147    } else {
148        raw.read_i32::<LittleEndian>()?
149    })
150}
151
152fn read_f64<R: Read>(raw: &mut R, is_be: bool) -> Result<f64, Error> {
153    Ok(if is_be {
154        raw.read_f64::<BigEndian>()?
155    } else {
156        raw.read_f64::<LittleEndian>()?
157    })
158}
159
160// --- Point
161
162fn has_z(type_id: u32) -> bool {
163    type_id & 0x80000000 == 0x80000000
164}
165fn has_m(type_id: u32) -> bool {
166    type_id & 0x40000000 == 0x40000000
167}
168
169impl Point {
170    pub fn new(x: f64, y: f64, srid: Option<i32>) -> Self {
171        Point {
172            x: x,
173            y: y,
174            srid: srid,
175        }
176    }
177    pub fn new_from_opt_vals(
178        x: f64,
179        y: f64,
180        _z: Option<f64>,
181        _m: Option<f64>,
182        srid: Option<i32>,
183    ) -> Self {
184        Self::new(x, y, srid)
185    }
186}
187
188impl postgis::Point for Point {
189    fn x(&self) -> f64 {
190        self.x
191    }
192    fn y(&self) -> f64 {
193        self.y
194    }
195}
196
197impl PointZ {
198    pub fn new(x: f64, y: f64, z: f64, srid: Option<i32>) -> Self {
199        PointZ {
200            x: x,
201            y: y,
202            z: z,
203            srid: srid,
204        }
205    }
206    pub fn new_from_opt_vals(
207        x: f64,
208        y: f64,
209        z: Option<f64>,
210        _m: Option<f64>,
211        srid: Option<i32>,
212    ) -> Self {
213        Self::new(x, y, z.unwrap(), srid)
214    }
215}
216
217impl postgis::Point for PointZ {
218    fn x(&self) -> f64 {
219        self.x
220    }
221    fn y(&self) -> f64 {
222        self.y
223    }
224    fn opt_z(&self) -> Option<f64> {
225        Some(self.z)
226    }
227}
228
229impl PointM {
230    pub fn new(x: f64, y: f64, m: f64, srid: Option<i32>) -> Self {
231        PointM {
232            x: x,
233            y: y,
234            m: m,
235            srid: srid,
236        }
237    }
238    pub fn new_from_opt_vals(
239        x: f64,
240        y: f64,
241        _z: Option<f64>,
242        m: Option<f64>,
243        srid: Option<i32>,
244    ) -> Self {
245        Self::new(x, y, m.unwrap(), srid)
246    }
247}
248
249impl postgis::Point for PointM {
250    fn x(&self) -> f64 {
251        self.x
252    }
253    fn y(&self) -> f64 {
254        self.y
255    }
256    fn opt_m(&self) -> Option<f64> {
257        Some(self.m)
258    }
259}
260
261impl PointZM {
262    pub fn new(x: f64, y: f64, z: f64, m: f64, srid: Option<i32>) -> Self {
263        PointZM {
264            x: x,
265            y: y,
266            z: z,
267            m: m,
268            srid: srid,
269        }
270    }
271    pub fn new_from_opt_vals(
272        x: f64,
273        y: f64,
274        z: Option<f64>,
275        m: Option<f64>,
276        srid: Option<i32>,
277    ) -> Self {
278        Self::new(x, y, z.unwrap(), m.unwrap(), srid)
279    }
280}
281
282impl postgis::Point for PointZM {
283    fn x(&self) -> f64 {
284        self.x
285    }
286    fn y(&self) -> f64 {
287        self.y
288    }
289    fn opt_z(&self) -> Option<f64> {
290        Some(self.z)
291    }
292    fn opt_m(&self) -> Option<f64> {
293        Some(self.m)
294    }
295}
296
297macro_rules! impl_point_read_traits {
298    ($ptype:ident) => {
299        impl EwkbRead for $ptype {
300            fn point_type() -> PointType {
301                PointType::$ptype
302            }
303            fn read_ewkb_body<R: Read>(
304                raw: &mut R,
305                is_be: bool,
306                type_id: u32,
307                srid: Option<i32>,
308            ) -> Result<Self, Error> {
309                let x = read_f64(raw, is_be)?;
310                let y = read_f64(raw, is_be)?;
311                let z = if has_z(type_id) {
312                    Some(read_f64(raw, is_be)?)
313                } else {
314                    None
315                };
316                let m = if has_m(type_id) {
317                    Some(read_f64(raw, is_be)?)
318                } else {
319                    None
320                };
321                Ok(Self::new_from_opt_vals(x, y, z, m, srid))
322            }
323        }
324
325        impl<'a> AsEwkbPoint<'a> for $ptype {
326            fn as_ewkb(&'a self) -> EwkbPoint<'a> {
327                EwkbPoint {
328                    geom: self,
329                    srid: self.srid,
330                    point_type: PointType::$ptype,
331                }
332            }
333        }
334    };
335}
336
337impl_point_read_traits!(Point);
338impl_point_read_traits!(PointZ);
339impl_point_read_traits!(PointM);
340impl_point_read_traits!(PointZM);
341
342pub struct EwkbPoint<'a> {
343    pub geom: &'a dyn postgis::Point,
344    pub srid: Option<i32>,
345    pub point_type: PointType,
346}
347
348pub trait AsEwkbPoint<'a> {
349    fn as_ewkb(&'a self) -> EwkbPoint<'a>;
350}
351
352impl<'a> fmt::Debug for EwkbPoint<'a> {
353    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
354        write!(f, "EwkbPoint")?; //TODO
355        Ok(())
356    }
357}
358
359impl<'a> EwkbWrite for EwkbPoint<'a> {
360    fn type_id(&self) -> u32 {
361        0x01 | Self::wkb_type_id(&self.point_type, self.srid)
362    }
363    fn opt_srid(&self) -> Option<i32> {
364        self.srid
365    }
366    fn write_ewkb_body<W: Write + ?Sized>(&self, w: &mut W) -> Result<(), Error> {
367        w.write_f64::<LittleEndian>(self.geom.x())?;
368        w.write_f64::<LittleEndian>(self.geom.y())?;
369        self.geom.opt_z().map(|z| w.write_f64::<LittleEndian>(z));
370        self.geom.opt_m().map(|m| w.write_f64::<LittleEndian>(m));
371        Ok(())
372    }
373}
374
375macro_rules! point_container_type {
376    // geometries containing points
377    ($geotypetrait:ident for $geotype:ident) => {
378        /// $geotypetrait
379        #[derive(PartialEq, Clone, Debug)]
380        pub struct $geotype<P: postgis::Point + EwkbRead> {
381            pub points: Vec<P>,
382            pub srid: Option<i32>,
383        }
384
385        impl<P: postgis::Point + EwkbRead> $geotype<P> {
386            pub fn new() -> $geotype<P> {
387                $geotype {
388                    points: Vec::new(),
389                    srid: None,
390                }
391            }
392        }
393
394        impl<P> FromIterator<P> for $geotype<P>
395        where
396            P: postgis::Point + EwkbRead,
397        {
398            #[inline]
399            fn from_iter<I: IntoIterator<Item = P>>(iterable: I) -> $geotype<P> {
400                let iterator = iterable.into_iter();
401                let (lower, _) = iterator.size_hint();
402                let mut ret = $geotype::new();
403                ret.points.reserve(lower);
404                for item in iterator {
405                    ret.points.push(item);
406                }
407                ret
408            }
409        }
410
411        impl<'a, P> postgis::$geotypetrait<'a> for $geotype<P>
412        where
413            P: 'a + postgis::Point + EwkbRead,
414        {
415            type ItemType = P;
416            type Iter = Iter<'a, Self::ItemType>;
417            fn points(&'a self) -> Self::Iter {
418                self.points.iter()
419            }
420        }
421    };
422}
423
424macro_rules! geometry_container_type {
425    // geometries containing lines and polygons
426    ($geotypetrait:ident for $geotype:ident contains $itemtype:ident named $itemname:ident) => {
427        #[derive(PartialEq, Clone, Debug)]
428        pub struct $geotype<P: postgis::Point + EwkbRead> {
429            pub $itemname: Vec<$itemtype<P>>,
430            pub srid: Option<i32>,
431        }
432
433        impl<P> $geotype<P>
434        where
435            P: postgis::Point + EwkbRead,
436        {
437            pub fn new() -> $geotype<P> {
438                $geotype {
439                    $itemname: Vec::new(),
440                    srid: None,
441                }
442            }
443        }
444
445        impl<P> FromIterator<$itemtype<P>> for $geotype<P>
446        where
447            P: postgis::Point + EwkbRead,
448        {
449            #[inline]
450            fn from_iter<I: IntoIterator<Item = $itemtype<P>>>(iterable: I) -> $geotype<P> {
451                let iterator = iterable.into_iter();
452                let (lower, _) = iterator.size_hint();
453                let mut ret = $geotype::new();
454                ret.$itemname.reserve(lower);
455                for item in iterator {
456                    ret.$itemname.push(item);
457                }
458                ret
459            }
460        }
461
462        impl<'a, P> postgis::$geotypetrait<'a> for $geotype<P>
463        where
464            P: 'a + postgis::Point + EwkbRead,
465        {
466            type ItemType = $itemtype<P>;
467            type Iter = Iter<'a, Self::ItemType>;
468            fn $itemname(&'a self) -> Self::Iter {
469                self.$itemname.iter()
470            }
471        }
472    };
473}
474
475macro_rules! impl_read_for_point_container_type {
476    (singletype $geotype:ident) => {
477        impl<P> EwkbRead for $geotype<P>
478        where
479            P: postgis::Point + EwkbRead,
480        {
481            fn point_type() -> PointType {
482                P::point_type()
483            }
484            fn read_ewkb_body<R: Read>(
485                raw: &mut R,
486                is_be: bool,
487                type_id: u32,
488                srid: Option<i32>,
489            ) -> Result<Self, Error> {
490                let mut points: Vec<P> = vec![];
491                let size = read_u32(raw, is_be)? as usize;
492                for _ in 0..size {
493                    points.push(P::read_ewkb_body(raw, is_be, type_id, srid)?);
494                }
495                Ok($geotype::<P> {
496                    points: points,
497                    srid: srid,
498                })
499            }
500        }
501    };
502    (multitype $geotype:ident) => {
503        impl<P> EwkbRead for $geotype<P>
504        where
505            P: postgis::Point + EwkbRead,
506        {
507            fn point_type() -> PointType {
508                P::point_type()
509            }
510            fn read_ewkb_body<R: Read>(
511                raw: &mut R,
512                is_be: bool,
513                _type_id: u32,
514                srid: Option<i32>,
515            ) -> Result<Self, Error> {
516                let mut points: Vec<P> = vec![];
517                let size = read_u32(raw, is_be)? as usize;
518                for _ in 0..size {
519                    points.push(P::read_ewkb(raw)?);
520                }
521                Ok($geotype::<P> {
522                    points: points,
523                    srid: srid,
524                })
525            }
526        }
527    };
528}
529
530macro_rules! impl_read_for_geometry_container_type {
531    (singletype $geotype:ident contains $itemtype:ident named $itemname:ident) => {
532        impl<P> EwkbRead for $geotype<P>
533        where
534            P: postgis::Point + EwkbRead,
535        {
536            fn point_type() -> PointType {
537                P::point_type()
538            }
539            fn read_ewkb_body<R: Read>(
540                raw: &mut R,
541                is_be: bool,
542                type_id: u32,
543                srid: Option<i32>,
544            ) -> Result<Self, Error> {
545                let mut $itemname: Vec<$itemtype<P>> = vec![];
546                let size = read_u32(raw, is_be)? as usize;
547                for _ in 0..size {
548                    $itemname.push($itemtype::read_ewkb_body(raw, is_be, type_id, srid)?);
549                }
550                Ok($geotype::<P> {
551                    $itemname: $itemname,
552                    srid: srid,
553                })
554            }
555        }
556    };
557    (multitype $geotype:ident contains $itemtype:ident named $itemname:ident) => {
558        impl<P> EwkbRead for $geotype<P>
559        where
560            P: postgis::Point + EwkbRead,
561        {
562            fn point_type() -> PointType {
563                P::point_type()
564            }
565            fn read_ewkb_body<R: Read>(
566                raw: &mut R,
567                is_be: bool,
568                _type_id: u32,
569                srid: Option<i32>,
570            ) -> Result<Self, Error> {
571                let mut $itemname: Vec<$itemtype<P>> = vec![];
572                let size = read_u32(raw, is_be)? as usize;
573                for _ in 0..size {
574                    $itemname.push($itemtype::read_ewkb(raw)?);
575                }
576                Ok($geotype::<P> {
577                    $itemname: $itemname,
578                    srid: srid,
579                })
580            }
581        }
582    };
583}
584
585macro_rules! point_container_write {
586    ($geotypetrait:ident and $asewkbtype:ident for $geotype:ident to $ewkbtype:ident with type code $typecode:expr, command $writecmd:ident) => {
587        pub struct $ewkbtype<'a, P, I>
588        where
589            P: 'a + postgis::Point,
590            I: 'a + Iterator<Item = &'a P> + ExactSizeIterator<Item = &'a P>,
591        {
592            pub geom: &'a dyn postgis::$geotypetrait<'a, ItemType = P, Iter = I>,
593            pub srid: Option<i32>,
594            pub point_type: PointType,
595        }
596
597        pub trait $asewkbtype<'a> {
598            type PointType: 'a + postgis::Point;
599            type Iter: Iterator<Item = &'a Self::PointType>
600                + ExactSizeIterator<Item = &'a Self::PointType>;
601            fn as_ewkb(&'a self) -> $ewkbtype<'a, Self::PointType, Self::Iter>;
602        }
603
604        impl<'a, T, I> fmt::Debug for $ewkbtype<'a, T, I>
605        where
606            T: 'a + postgis::Point,
607            I: 'a + Iterator<Item = &'a T> + ExactSizeIterator<Item = &'a T>,
608        {
609            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
610                write!(f, stringify!($ewkbtype))?; //TODO
611                Ok(())
612            }
613        }
614
615        impl<'a, T, I> EwkbWrite for $ewkbtype<'a, T, I>
616        where
617            T: 'a + postgis::Point,
618            I: 'a + Iterator<Item = &'a T> + ExactSizeIterator<Item = &'a T>,
619        {
620            fn opt_srid(&self) -> Option<i32> {
621                self.srid
622            }
623
624            fn type_id(&self) -> u32 {
625                $typecode | Self::wkb_type_id(&self.point_type, self.srid)
626            }
627
628            fn write_ewkb_body<W: Write + ?Sized>(&self, w: &mut W) -> Result<(), Error> {
629                w.write_u32::<LittleEndian>(self.geom.points().len() as u32)?;
630                for geom in self.geom.points() {
631                    let wkb = EwkbPoint {
632                        geom: geom,
633                        srid: None,
634                        point_type: self.point_type.clone(),
635                    };
636                    wkb.$writecmd(w)?;
637                }
638                Ok(())
639            }
640        }
641
642        impl<'a, P> $asewkbtype<'a> for $geotype<P>
643        where
644            P: 'a + postgis::Point + EwkbRead,
645        {
646            type PointType = P;
647            type Iter = Iter<'a, P>;
648            fn as_ewkb(&'a self) -> $ewkbtype<'a, Self::PointType, Self::Iter> {
649                $ewkbtype {
650                    geom: self,
651                    srid: self.srid,
652                    point_type: Self::PointType::point_type(),
653                }
654            }
655        }
656    };
657}
658
659macro_rules! geometry_container_write {
660    ($geotypetrait:ident and $asewkbtype:ident for $geotype:ident to $ewkbtype:ident with type code $typecode:expr, contains $ewkbitemtype:ident, $itemtype:ident as $itemtypetrait:ident named $itemname:ident, command $writecmd:ident) => {
661        pub struct $ewkbtype<'a, P, I, T, J>
662        where
663            P: 'a + postgis::Point,
664            I: 'a + Iterator<Item = &'a P> + ExactSizeIterator<Item = &'a P>,
665            T: 'a + postgis::$itemtypetrait<'a, ItemType = P, Iter = I>,
666            J: 'a + Iterator<Item = &'a T> + ExactSizeIterator<Item = &'a T>,
667        {
668            pub geom: &'a dyn postgis::$geotypetrait<'a, ItemType = T, Iter = J>,
669            pub srid: Option<i32>,
670            pub point_type: PointType,
671        }
672
673        pub trait $asewkbtype<'a> {
674            type PointType: 'a + postgis::Point;
675            type PointIter: Iterator<Item = &'a Self::PointType>
676                + ExactSizeIterator<Item = &'a Self::PointType>;
677            type ItemType: 'a
678                + postgis::$itemtypetrait<'a, ItemType = Self::PointType, Iter = Self::PointIter>;
679            type Iter: Iterator<Item = &'a Self::ItemType>
680                + ExactSizeIterator<Item = &'a Self::ItemType>;
681            fn as_ewkb(
682                &'a self,
683            ) -> $ewkbtype<'a, Self::PointType, Self::PointIter, Self::ItemType, Self::Iter>;
684        }
685
686        impl<'a, P, I, T, J> fmt::Debug for $ewkbtype<'a, P, I, T, J>
687        where
688            P: 'a + postgis::Point,
689            I: 'a + Iterator<Item = &'a P> + ExactSizeIterator<Item = &'a P>,
690            T: 'a + postgis::$itemtypetrait<'a, ItemType = P, Iter = I>,
691            J: 'a + Iterator<Item = &'a T> + ExactSizeIterator<Item = &'a T>,
692        {
693            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
694                write!(f, stringify!($ewkbtype))?; //TODO
695                Ok(())
696            }
697        }
698
699        impl<'a, P, I, T, J> EwkbWrite for $ewkbtype<'a, P, I, T, J>
700        where
701            P: 'a + postgis::Point,
702            I: 'a + Iterator<Item = &'a P> + ExactSizeIterator<Item = &'a P>,
703            T: 'a + postgis::$itemtypetrait<'a, ItemType = P, Iter = I>,
704            J: 'a + Iterator<Item = &'a T> + ExactSizeIterator<Item = &'a T>,
705        {
706            fn opt_srid(&self) -> Option<i32> {
707                self.srid
708            }
709
710            fn type_id(&self) -> u32 {
711                $typecode | Self::wkb_type_id(&self.point_type, self.srid)
712            }
713
714            fn write_ewkb_body<W: Write + ?Sized>(&self, w: &mut W) -> Result<(), Error> {
715                w.write_u32::<LittleEndian>(self.geom.$itemname().len() as u32)?;
716                for geom in self.geom.$itemname() {
717                    let wkb = $ewkbitemtype {
718                        geom: geom,
719                        srid: None,
720                        point_type: self.point_type.clone(),
721                    };
722                    wkb.$writecmd(w)?;
723                }
724                Ok(())
725            }
726        }
727
728        impl<'a, P> $asewkbtype<'a> for $geotype<P>
729        where
730            P: 'a + postgis::Point + EwkbRead,
731        {
732            type PointType = P;
733            type PointIter = Iter<'a, P>;
734            type ItemType = $itemtype<P>;
735            type Iter = Iter<'a, Self::ItemType>;
736            fn as_ewkb(
737                &'a self,
738            ) -> $ewkbtype<'a, Self::PointType, Self::PointIter, Self::ItemType, Self::Iter> {
739                $ewkbtype {
740                    geom: self,
741                    srid: self.srid,
742                    point_type: Self::PointType::point_type(),
743                }
744            }
745        }
746    };
747    (multipoly $geotypetrait:ident and $asewkbtype:ident for $geotype:ident to $ewkbtype:ident with type code $typecode:expr, contains $ewkbitemtype:ident, $itemtype:ident as $itemtypetrait:ident named $itemname:ident, command $writecmd:ident) => {
748        pub struct $ewkbtype<'a, P, I, L, K, T, J>
749        where
750            P: 'a + postgis::Point,
751            I: 'a + Iterator<Item = &'a P> + ExactSizeIterator<Item = &'a P>,
752            L: 'a + postgis::LineString<'a, ItemType = P, Iter = I>,
753            K: 'a + Iterator<Item = &'a L> + ExactSizeIterator<Item = &'a L>,
754            T: 'a + postgis::$itemtypetrait<'a, ItemType = L, Iter = K>,
755            J: 'a + Iterator<Item = &'a T> + ExactSizeIterator<Item = &'a T>,
756        {
757            pub geom: &'a dyn postgis::$geotypetrait<'a, ItemType = T, Iter = J>,
758            pub srid: Option<i32>,
759            pub point_type: PointType,
760        }
761
762        pub trait $asewkbtype<'a> {
763            type PointType: 'a + postgis::Point;
764            type PointIter: Iterator<Item = &'a Self::PointType>
765                + ExactSizeIterator<Item = &'a Self::PointType>;
766            type LineType: 'a
767                + postgis::LineString<'a, ItemType = Self::PointType, Iter = Self::PointIter>;
768            type LineIter: Iterator<Item = &'a Self::LineType>
769                + ExactSizeIterator<Item = &'a Self::LineType>;
770            type ItemType: 'a
771                + postgis::$itemtypetrait<'a, ItemType = Self::LineType, Iter = Self::LineIter>;
772            type Iter: Iterator<Item = &'a Self::ItemType>
773                + ExactSizeIterator<Item = &'a Self::ItemType>;
774            fn as_ewkb(
775                &'a self,
776            ) -> $ewkbtype<
777                'a,
778                Self::PointType,
779                Self::PointIter,
780                Self::LineType,
781                Self::LineIter,
782                Self::ItemType,
783                Self::Iter,
784            >;
785        }
786
787        impl<'a, P, I, L, K, T, J> fmt::Debug for $ewkbtype<'a, P, I, L, K, T, J>
788        where
789            P: 'a + postgis::Point,
790            I: 'a + Iterator<Item = &'a P> + ExactSizeIterator<Item = &'a P>,
791            L: 'a + postgis::LineString<'a, ItemType = P, Iter = I>,
792            K: 'a + Iterator<Item = &'a L> + ExactSizeIterator<Item = &'a L>,
793            T: 'a + postgis::$itemtypetrait<'a, ItemType = L, Iter = K>,
794            J: 'a + Iterator<Item = &'a T> + ExactSizeIterator<Item = &'a T>,
795        {
796            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
797                write!(f, stringify!($ewkbtype))?; //TODO
798                Ok(())
799            }
800        }
801
802        impl<'a, P, I, L, K, T, J> EwkbWrite for $ewkbtype<'a, P, I, L, K, T, J>
803        where
804            P: 'a + postgis::Point,
805            I: 'a + Iterator<Item = &'a P> + ExactSizeIterator<Item = &'a P>,
806            L: 'a + postgis::LineString<'a, ItemType = P, Iter = I>,
807            K: 'a + Iterator<Item = &'a L> + ExactSizeIterator<Item = &'a L>,
808            T: 'a + postgis::$itemtypetrait<'a, ItemType = L, Iter = K>,
809            J: 'a + Iterator<Item = &'a T> + ExactSizeIterator<Item = &'a T>,
810        {
811            fn opt_srid(&self) -> Option<i32> {
812                self.srid
813            }
814
815            fn type_id(&self) -> u32 {
816                $typecode | Self::wkb_type_id(&self.point_type, self.srid)
817            }
818
819            fn write_ewkb_body<W: Write + ?Sized>(&self, w: &mut W) -> Result<(), Error> {
820                w.write_u32::<LittleEndian>(self.geom.$itemname().len() as u32)?;
821                for geom in self.geom.$itemname() {
822                    let wkb = $ewkbitemtype {
823                        geom: geom,
824                        srid: None,
825                        point_type: self.point_type.clone(),
826                    };
827                    wkb.$writecmd(w)?;
828                }
829                Ok(())
830            }
831        }
832
833        impl<'a, P> $asewkbtype<'a> for $geotype<P>
834        where
835            P: 'a + postgis::Point + EwkbRead,
836        {
837            type PointType = P;
838            type PointIter = Iter<'a, P>;
839            type LineType = LineStringT<P>;
840            type LineIter = Iter<'a, Self::LineType>;
841            type ItemType = $itemtype<P>;
842            type Iter = Iter<'a, Self::ItemType>;
843            fn as_ewkb(
844                &'a self,
845            ) -> $ewkbtype<
846                'a,
847                Self::PointType,
848                Self::PointIter,
849                Self::LineType,
850                Self::LineIter,
851                Self::ItemType,
852                Self::Iter,
853            > {
854                $ewkbtype {
855                    geom: self,
856                    srid: self.srid,
857                    point_type: Self::PointType::point_type(),
858                }
859            }
860        }
861    };
862}
863
864point_container_type!(LineString for LineStringT);
865impl_read_for_point_container_type!(singletype LineStringT);
866point_container_write!(LineString and AsEwkbLineString for LineStringT
867                       to EwkbLineString with type code 0x02,
868                       command write_ewkb_body);
869
870/// OGC LineString type
871pub type LineString = LineStringT<Point>;
872/// OGC LineStringZ type
873pub type LineStringZ = LineStringT<PointZ>;
874/// OGC LineStringM type
875pub type LineStringM = LineStringT<PointM>;
876/// OGC LineStringZM type
877pub type LineStringZM = LineStringT<PointZM>;
878
879geometry_container_type!(Polygon for PolygonT contains LineStringT named rings);
880impl_read_for_geometry_container_type!(singletype PolygonT contains LineStringT named rings);
881geometry_container_write!(Polygon and AsEwkbPolygon for PolygonT
882                          to EwkbPolygon with type code 0x03,
883                          contains EwkbLineString,LineStringT as LineString named rings,
884                          command write_ewkb_body);
885
886/// OGC Polygon type
887pub type Polygon = PolygonT<Point>;
888/// OGC PolygonZ type
889pub type PolygonZ = PolygonT<PointZ>;
890/// OGC PolygonM type
891pub type PolygonM = PolygonT<PointM>;
892/// OGC PolygonZM type
893pub type PolygonZM = PolygonT<PointZM>;
894
895point_container_type!(MultiPoint for MultiPointT);
896impl_read_for_point_container_type!(multitype MultiPointT);
897point_container_write!(MultiPoint and AsEwkbMultiPoint for MultiPointT
898                       to EwkbMultiPoint with type code 0x04,
899                       command write_ewkb);
900
901/// OGC MultiPoint type
902pub type MultiPoint = MultiPointT<Point>;
903/// OGC MultiPointZ type
904pub type MultiPointZ = MultiPointT<PointZ>;
905/// OGC MultiPointM type
906pub type MultiPointM = MultiPointT<PointM>;
907/// OGC MultiPointZM type
908pub type MultiPointZM = MultiPointT<PointZM>;
909
910geometry_container_type!(MultiLineString for MultiLineStringT contains LineStringT named lines);
911impl_read_for_geometry_container_type!(multitype MultiLineStringT contains LineStringT named lines);
912geometry_container_write!(MultiLineString and AsEwkbMultiLineString for MultiLineStringT
913                          to EwkbMultiLineString with type code 0x05,
914                          contains EwkbLineString,LineStringT as LineString named lines,
915                          command write_ewkb);
916
917/// OGC MultiLineString type
918pub type MultiLineString = MultiLineStringT<Point>;
919/// OGC MultiLineStringZ type
920pub type MultiLineStringZ = MultiLineStringT<PointZ>;
921/// OGC MultiLineStringM type
922pub type MultiLineStringM = MultiLineStringT<PointM>;
923/// OGC MultiLineStringZM type
924pub type MultiLineStringZM = MultiLineStringT<PointZM>;
925
926geometry_container_type!(MultiPolygon for MultiPolygonT contains PolygonT named polygons);
927impl_read_for_geometry_container_type!(multitype MultiPolygonT contains PolygonT named polygons);
928geometry_container_write!(multipoly MultiPolygon and AsEwkbMultiPolygon for MultiPolygonT
929                          to EwkbMultiPolygon with type code 0x06,
930                          contains EwkbPolygon,PolygonT as Polygon named polygons,
931                          command write_ewkb);
932
933/// OGC MultiPolygon type
934pub type MultiPolygon = MultiPolygonT<Point>;
935/// OGC MultiPolygonZ type
936pub type MultiPolygonZ = MultiPolygonT<PointZ>;
937/// OGC MultiPolygonM type
938pub type MultiPolygonM = MultiPolygonT<PointM>;
939/// OGC MultiPolygonZM type
940pub type MultiPolygonZM = MultiPolygonT<PointZM>;
941
942/// Generic Geometry Data Type
943#[derive(Clone, Debug)]
944pub enum GeometryT<P: postgis::Point + EwkbRead> {
945    Point(P),
946    LineString(LineStringT<P>),
947    Polygon(PolygonT<P>),
948    MultiPoint(MultiPointT<P>),
949    MultiLineString(MultiLineStringT<P>),
950    MultiPolygon(MultiPolygonT<P>),
951    GeometryCollection(GeometryCollectionT<P>),
952}
953
954impl<'a, P> postgis::Geometry<'a> for GeometryT<P>
955where
956    P: 'a + postgis::Point + EwkbRead,
957{
958    type Point = P;
959    type LineString = LineStringT<P>;
960    type Polygon = PolygonT<P>;
961    type MultiPoint = MultiPointT<P>;
962    type MultiLineString = MultiLineStringT<P>;
963    type MultiPolygon = MultiPolygonT<P>;
964    type GeometryCollection = GeometryCollectionT<P>;
965    fn as_type(
966        &'a self,
967    ) -> postgis::GeometryType<
968        'a,
969        P,
970        LineStringT<P>,
971        PolygonT<P>,
972        MultiPointT<P>,
973        MultiLineStringT<P>,
974        MultiPolygonT<P>,
975        GeometryCollectionT<P>,
976    > {
977        use crate::ewkb::GeometryT as A;
978        use crate::types::GeometryType as B;
979        match *self {
980            A::Point(ref geom) => B::Point(geom),
981            A::LineString(ref geom) => B::LineString(geom),
982            A::Polygon(ref geom) => B::Polygon(geom),
983            A::MultiPoint(ref geom) => B::MultiPoint(geom),
984            A::MultiLineString(ref geom) => B::MultiLineString(geom),
985            A::MultiPolygon(ref geom) => B::MultiPolygon(geom),
986            A::GeometryCollection(ref geom) => B::GeometryCollection(geom),
987        }
988    }
989}
990
991impl<P> EwkbRead for GeometryT<P>
992where
993    P: postgis::Point + EwkbRead,
994{
995    fn point_type() -> PointType {
996        P::point_type()
997    }
998    fn read_ewkb<R: Read>(raw: &mut R) -> Result<Self, Error> {
999        let byte_order = raw.read_i8()?;
1000        let is_be = byte_order == 0i8;
1001
1002        let type_id = read_u32(raw, is_be)?;
1003        let mut srid: Option<i32> = None;
1004        if type_id & 0x20000000 == 0x20000000 {
1005            srid = Some(read_i32(raw, is_be)?);
1006        }
1007
1008        let geom = match type_id & 0xff {
1009            0x01 => GeometryT::Point(P::read_ewkb_body(raw, is_be, type_id, srid)?),
1010            0x02 => {
1011                GeometryT::LineString(LineStringT::<P>::read_ewkb_body(raw, is_be, type_id, srid)?)
1012            }
1013            0x03 => GeometryT::Polygon(PolygonT::read_ewkb_body(raw, is_be, type_id, srid)?),
1014            0x04 => GeometryT::MultiPoint(MultiPointT::read_ewkb_body(raw, is_be, type_id, srid)?),
1015            0x05 => GeometryT::MultiLineString(MultiLineStringT::read_ewkb_body(
1016                raw, is_be, type_id, srid,
1017            )?),
1018            0x06 => {
1019                GeometryT::MultiPolygon(MultiPolygonT::read_ewkb_body(raw, is_be, type_id, srid)?)
1020            }
1021            0x07 => GeometryT::GeometryCollection(GeometryCollectionT::read_ewkb_body(
1022                raw, is_be, type_id, srid,
1023            )?),
1024            _ => {
1025                return Err(Error::Read(format!(
1026                    "Error reading generic geometry type - unsupported type id {}.",
1027                    type_id
1028                )))
1029            }
1030        };
1031        Ok(geom)
1032    }
1033    fn read_ewkb_body<R: Read>(
1034        _raw: &mut R,
1035        _is_be: bool,
1036        _type_id: u32,
1037        _srid: Option<i32>,
1038    ) -> Result<Self, Error> {
1039        panic!("Not used for generic geometry type")
1040    }
1041}
1042
1043pub enum EwkbGeometry<'a, P, PI, MP, L, LI, ML, Y, YI, MY, G, GI, GC>
1044where
1045    P: 'a + postgis::Point,
1046    PI: 'a + Iterator<Item = &'a P> + ExactSizeIterator<Item = &'a P>,
1047    MP: 'a + postgis::MultiPoint<'a, ItemType = P, Iter = PI>,
1048    L: 'a + postgis::LineString<'a, ItemType = P, Iter = PI>,
1049    LI: 'a + Iterator<Item = &'a L> + ExactSizeIterator<Item = &'a L>,
1050    ML: 'a + postgis::MultiLineString<'a, ItemType = L, Iter = LI>,
1051    Y: 'a + postgis::Polygon<'a, ItemType = L, Iter = LI>,
1052    YI: 'a + Iterator<Item = &'a Y> + ExactSizeIterator<Item = &'a Y>,
1053    MY: 'a + postgis::MultiPolygon<'a, ItemType = Y, Iter = YI>,
1054    G: 'a
1055        + postgis::Geometry<
1056            'a,
1057            Point = P,
1058            LineString = L,
1059            Polygon = Y,
1060            MultiPoint = MP,
1061            MultiLineString = ML,
1062            MultiPolygon = MY,
1063            GeometryCollection = GC,
1064        >,
1065    GI: 'a + Iterator<Item = &'a G> + ExactSizeIterator<Item = &'a G>,
1066    GC: 'a + postgis::GeometryCollection<'a, ItemType = G, Iter = GI>,
1067{
1068    Point(EwkbPoint<'a>),
1069    LineString(EwkbLineString<'a, P, PI>),
1070    Polygon(EwkbPolygon<'a, P, PI, L, LI>),
1071    MultiPoint(EwkbMultiPoint<'a, P, PI>),
1072    MultiLineString(EwkbMultiLineString<'a, P, PI, L, LI>),
1073    MultiPolygon(EwkbMultiPolygon<'a, P, PI, L, LI, Y, YI>),
1074    GeometryCollection(EwkbGeometryCollection<'a, P, PI, MP, L, LI, ML, Y, YI, MY, G, GI, GC>),
1075}
1076
1077pub trait AsEwkbGeometry<'a> {
1078    type PointType: 'a + postgis::Point + EwkbRead;
1079    type PointIter: Iterator<Item = &'a Self::PointType>
1080        + ExactSizeIterator<Item = &'a Self::PointType>;
1081    type MultiPointType: 'a
1082        + postgis::MultiPoint<'a, ItemType = Self::PointType, Iter = Self::PointIter>;
1083    type LineType: 'a + postgis::LineString<'a, ItemType = Self::PointType, Iter = Self::PointIter>;
1084    type LineIter: Iterator<Item = &'a Self::LineType>
1085        + ExactSizeIterator<Item = &'a Self::LineType>;
1086    type MultiLineType: 'a
1087        + postgis::MultiLineString<'a, ItemType = Self::LineType, Iter = Self::LineIter>;
1088    type PolyType: 'a + postgis::Polygon<'a, ItemType = Self::LineType, Iter = Self::LineIter>;
1089    type PolyIter: Iterator<Item = &'a Self::PolyType>
1090        + ExactSizeIterator<Item = &'a Self::PolyType>;
1091    type MultiPolyType: 'a
1092        + postgis::MultiPolygon<'a, ItemType = Self::PolyType, Iter = Self::PolyIter>;
1093    type GeomType: 'a
1094        + postgis::Geometry<
1095            'a,
1096            Point = Self::PointType,
1097            LineString = Self::LineType,
1098            Polygon = Self::PolyType,
1099            MultiPoint = Self::MultiPointType,
1100            MultiLineString = Self::MultiLineType,
1101            MultiPolygon = Self::MultiPolyType,
1102            GeometryCollection = Self::GeomCollection,
1103        >;
1104    type GeomIter: Iterator<Item = &'a Self::GeomType>
1105        + ExactSizeIterator<Item = &'a Self::GeomType>;
1106    type GeomCollection: 'a
1107        + postgis::GeometryCollection<'a, ItemType = Self::GeomType, Iter = Self::GeomIter>;
1108    fn as_ewkb(
1109        &'a self,
1110    ) -> EwkbGeometry<
1111        'a,
1112        Self::PointType,
1113        Self::PointIter,
1114        Self::MultiPointType,
1115        Self::LineType,
1116        Self::LineIter,
1117        Self::MultiLineType,
1118        Self::PolyType,
1119        Self::PolyIter,
1120        Self::MultiPolyType,
1121        Self::GeomType,
1122        Self::GeomIter,
1123        Self::GeomCollection,
1124    >;
1125}
1126
1127impl<'a, P, PI, MP, L, LI, ML, Y, YI, MY, G, GI, GC> fmt::Debug
1128    for EwkbGeometry<'a, P, PI, MP, L, LI, ML, Y, YI, MY, G, GI, GC>
1129where
1130    P: 'a + postgis::Point,
1131    PI: 'a + Iterator<Item = &'a P> + ExactSizeIterator<Item = &'a P>,
1132    MP: 'a + postgis::MultiPoint<'a, ItemType = P, Iter = PI>,
1133    L: 'a + postgis::LineString<'a, ItemType = P, Iter = PI>,
1134    LI: 'a + Iterator<Item = &'a L> + ExactSizeIterator<Item = &'a L>,
1135    ML: 'a + postgis::MultiLineString<'a, ItemType = L, Iter = LI>,
1136    Y: 'a + postgis::Polygon<'a, ItemType = L, Iter = LI>,
1137    YI: 'a + Iterator<Item = &'a Y> + ExactSizeIterator<Item = &'a Y>,
1138    MY: 'a + postgis::MultiPolygon<'a, ItemType = Y, Iter = YI>,
1139    G: 'a
1140        + postgis::Geometry<
1141            'a,
1142            Point = P,
1143            LineString = L,
1144            Polygon = Y,
1145            MultiPoint = MP,
1146            MultiLineString = ML,
1147            MultiPolygon = MY,
1148            GeometryCollection = GC,
1149        >,
1150    GI: 'a + Iterator<Item = &'a G> + ExactSizeIterator<Item = &'a G>,
1151    GC: 'a + postgis::GeometryCollection<'a, ItemType = G, Iter = GI>,
1152{
1153    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1154        write!(f, stringify!(EwkbGeometry))?; //TODO
1155        Ok(())
1156    }
1157}
1158
1159impl<'a, P, PI, MP, L, LI, ML, Y, YI, MY, G, GI, GC> EwkbWrite
1160    for EwkbGeometry<'a, P, PI, MP, L, LI, ML, Y, YI, MY, G, GI, GC>
1161where
1162    P: 'a + postgis::Point,
1163    PI: 'a + Iterator<Item = &'a P> + ExactSizeIterator<Item = &'a P>,
1164    MP: 'a + postgis::MultiPoint<'a, ItemType = P, Iter = PI>,
1165    L: 'a + postgis::LineString<'a, ItemType = P, Iter = PI>,
1166    LI: 'a + Iterator<Item = &'a L> + ExactSizeIterator<Item = &'a L>,
1167    ML: 'a + postgis::MultiLineString<'a, ItemType = L, Iter = LI>,
1168    Y: 'a + postgis::Polygon<'a, ItemType = L, Iter = LI>,
1169    YI: 'a + Iterator<Item = &'a Y> + ExactSizeIterator<Item = &'a Y>,
1170    MY: 'a + postgis::MultiPolygon<'a, ItemType = Y, Iter = YI>,
1171    G: 'a
1172        + postgis::Geometry<
1173            'a,
1174            Point = P,
1175            LineString = L,
1176            Polygon = Y,
1177            MultiPoint = MP,
1178            MultiLineString = ML,
1179            MultiPolygon = MY,
1180            GeometryCollection = GC,
1181        >,
1182    GI: 'a + Iterator<Item = &'a G> + ExactSizeIterator<Item = &'a G>,
1183    GC: 'a + postgis::GeometryCollection<'a, ItemType = G, Iter = GI>,
1184{
1185    fn opt_srid(&self) -> Option<i32> {
1186        match *self {
1187            EwkbGeometry::Point(ref ewkb) => ewkb.opt_srid(),
1188            EwkbGeometry::LineString(ref ewkb) => ewkb.opt_srid(),
1189            EwkbGeometry::Polygon(ref ewkb) => ewkb.opt_srid(),
1190            EwkbGeometry::MultiPoint(ref ewkb) => ewkb.opt_srid(),
1191            EwkbGeometry::MultiLineString(ref ewkb) => ewkb.opt_srid(),
1192            EwkbGeometry::MultiPolygon(ref ewkb) => ewkb.opt_srid(),
1193            EwkbGeometry::GeometryCollection(ref ewkb) => ewkb.opt_srid(),
1194        }
1195    }
1196
1197    fn type_id(&self) -> u32 {
1198        match *self {
1199            EwkbGeometry::Point(ref ewkb) => ewkb.type_id(),
1200            EwkbGeometry::LineString(ref ewkb) => ewkb.type_id(),
1201            EwkbGeometry::Polygon(ref ewkb) => ewkb.type_id(),
1202            EwkbGeometry::MultiPoint(ref ewkb) => ewkb.type_id(),
1203            EwkbGeometry::MultiLineString(ref ewkb) => ewkb.type_id(),
1204            EwkbGeometry::MultiPolygon(ref ewkb) => ewkb.type_id(),
1205            EwkbGeometry::GeometryCollection(ref ewkb) => ewkb.type_id(),
1206        }
1207    }
1208
1209    fn write_ewkb_body<W: Write + ?Sized>(&self, w: &mut W) -> Result<(), Error> {
1210        match *self {
1211            EwkbGeometry::Point(ref ewkb) => ewkb.write_ewkb_body(w),
1212            EwkbGeometry::LineString(ref ewkb) => ewkb.write_ewkb_body(w),
1213            EwkbGeometry::Polygon(ref ewkb) => ewkb.write_ewkb_body(w),
1214            EwkbGeometry::MultiPoint(ref ewkb) => ewkb.write_ewkb_body(w),
1215            EwkbGeometry::MultiLineString(ref ewkb) => ewkb.write_ewkb_body(w),
1216            EwkbGeometry::MultiPolygon(ref ewkb) => ewkb.write_ewkb_body(w),
1217            EwkbGeometry::GeometryCollection(ref ewkb) => ewkb.write_ewkb_body(w),
1218        }
1219    }
1220}
1221
1222impl<'a, P> AsEwkbGeometry<'a> for GeometryT<P>
1223where
1224    P: 'a + postgis::Point + EwkbRead + AsEwkbPoint<'a>,
1225{
1226    type PointType = P;
1227    type PointIter = Iter<'a, P>;
1228    type MultiPointType = MultiPointT<P>;
1229    type LineType = LineStringT<P>;
1230    type LineIter = Iter<'a, Self::LineType>;
1231    type MultiLineType = MultiLineStringT<P>;
1232    type PolyType = PolygonT<P>;
1233    type PolyIter = Iter<'a, Self::PolyType>;
1234    type MultiPolyType = MultiPolygonT<P>;
1235    type GeomType = GeometryT<P>;
1236    type GeomIter = Iter<'a, Self::GeomType>;
1237    type GeomCollection = GeometryCollectionT<P>;
1238    fn as_ewkb(
1239        &'a self,
1240    ) -> EwkbGeometry<
1241        'a,
1242        Self::PointType,
1243        Self::PointIter,
1244        Self::MultiPointType,
1245        Self::LineType,
1246        Self::LineIter,
1247        Self::MultiLineType,
1248        Self::PolyType,
1249        Self::PolyIter,
1250        Self::MultiPolyType,
1251        Self::GeomType,
1252        Self::GeomIter,
1253        Self::GeomCollection,
1254    > {
1255        match *self {
1256            GeometryT::Point(ref geom) => EwkbGeometry::Point(geom.as_ewkb()),
1257            GeometryT::LineString(ref geom) => EwkbGeometry::LineString(geom.as_ewkb()),
1258            GeometryT::Polygon(ref geom) => EwkbGeometry::Polygon(geom.as_ewkb()),
1259            GeometryT::MultiPoint(ref geom) => EwkbGeometry::MultiPoint(geom.as_ewkb()),
1260            GeometryT::MultiLineString(ref geom) => EwkbGeometry::MultiLineString(geom.as_ewkb()),
1261            GeometryT::MultiPolygon(ref geom) => EwkbGeometry::MultiPolygon(geom.as_ewkb()),
1262            GeometryT::GeometryCollection(ref geom) => {
1263                EwkbGeometry::GeometryCollection(geom.as_ewkb())
1264            }
1265        }
1266    }
1267}
1268
1269/// OGC Geometry type
1270pub type Geometry = GeometryT<Point>;
1271/// OGC GeometryZ type
1272pub type GeometryZ = GeometryT<PointZ>;
1273/// OGC GeometryM type
1274pub type GeometryM = GeometryT<PointM>;
1275/// OGC GeometryZM type
1276pub type GeometryZM = GeometryT<PointZM>;
1277
1278#[derive(Clone, Debug)]
1279pub struct GeometryCollectionT<P: postgis::Point + EwkbRead> {
1280    pub geometries: Vec<GeometryT<P>>,
1281    pub srid: Option<i32>,
1282}
1283
1284impl<P> GeometryCollectionT<P>
1285where
1286    P: postgis::Point + EwkbRead,
1287{
1288    pub fn new() -> GeometryCollectionT<P> {
1289        GeometryCollectionT {
1290            geometries: Vec::new(),
1291            srid: None,
1292        }
1293    }
1294}
1295
1296impl<'a, P> postgis::GeometryCollection<'a> for GeometryCollectionT<P>
1297where
1298    P: 'a + postgis::Point + EwkbRead,
1299{
1300    type ItemType = GeometryT<P>;
1301    type Iter = Iter<'a, Self::ItemType>;
1302    fn geometries(&'a self) -> Self::Iter {
1303        self.geometries.iter()
1304    }
1305}
1306
1307impl<P> EwkbRead for GeometryCollectionT<P>
1308where
1309    P: postgis::Point + EwkbRead,
1310{
1311    fn point_type() -> PointType {
1312        P::point_type()
1313    }
1314
1315    fn read_ewkb_body<R: Read>(
1316        raw: &mut R,
1317        is_be: bool,
1318        _type_id: u32,
1319        _srid: Option<i32>,
1320    ) -> Result<Self, Error> {
1321        let mut ret = GeometryCollectionT::new();
1322        let size = read_u32(raw, is_be)? as usize;
1323        for _ in 0..size {
1324            let is_be = raw.read_i8()? == 0i8;
1325
1326            let type_id = read_u32(raw, is_be)?;
1327            let mut srid: Option<i32> = None;
1328            if type_id & 0x20000000 == 0x20000000 {
1329                srid = Some(read_i32(raw, is_be)?);
1330            }
1331            let geom = match type_id & 0xff {
1332                0x01 => GeometryT::Point(P::read_ewkb_body(raw, is_be, type_id, srid)?),
1333                0x02 => GeometryT::LineString(LineStringT::<P>::read_ewkb_body(
1334                    raw, is_be, type_id, srid,
1335                )?),
1336                0x03 => GeometryT::Polygon(PolygonT::read_ewkb_body(raw, is_be, type_id, srid)?),
1337                0x04 => {
1338                    GeometryT::MultiPoint(MultiPointT::read_ewkb_body(raw, is_be, type_id, srid)?)
1339                }
1340                0x05 => GeometryT::MultiLineString(MultiLineStringT::read_ewkb_body(
1341                    raw, is_be, type_id, srid,
1342                )?),
1343                0x06 => GeometryT::MultiPolygon(MultiPolygonT::read_ewkb_body(
1344                    raw, is_be, type_id, srid,
1345                )?),
1346                0x07 => GeometryT::GeometryCollection(GeometryCollectionT::read_ewkb_body(
1347                    raw, is_be, type_id, srid,
1348                )?),
1349                _ => {
1350                    return Err(Error::Read(format!(
1351                        "Error reading generic geometry type - unsupported type id {}.",
1352                        type_id
1353                    )))
1354                }
1355            };
1356            ret.geometries.push(geom);
1357        }
1358        Ok(ret)
1359    }
1360}
1361
1362pub struct EwkbGeometryCollection<'a, P, PI, MP, L, LI, ML, Y, YI, MY, G, GI, GC>
1363where
1364    P: 'a + postgis::Point,
1365    PI: 'a + Iterator<Item = &'a P> + ExactSizeIterator<Item = &'a P>,
1366    MP: 'a + postgis::MultiPoint<'a, ItemType = P, Iter = PI>,
1367    L: 'a + postgis::LineString<'a, ItemType = P, Iter = PI>,
1368    LI: 'a + Iterator<Item = &'a L> + ExactSizeIterator<Item = &'a L>,
1369    ML: 'a + postgis::MultiLineString<'a, ItemType = L, Iter = LI>,
1370    Y: 'a + postgis::Polygon<'a, ItemType = L, Iter = LI>,
1371    YI: 'a + Iterator<Item = &'a Y> + ExactSizeIterator<Item = &'a Y>,
1372    MY: 'a + postgis::MultiPolygon<'a, ItemType = Y, Iter = YI>,
1373    G: 'a
1374        + postgis::Geometry<
1375            'a,
1376            Point = P,
1377            LineString = L,
1378            Polygon = Y,
1379            MultiPoint = MP,
1380            MultiLineString = ML,
1381            MultiPolygon = MY,
1382            GeometryCollection = GC,
1383        >,
1384    GI: 'a + Iterator<Item = &'a G> + ExactSizeIterator<Item = &'a G>,
1385    GC: 'a + postgis::GeometryCollection<'a, ItemType = G, Iter = GI>,
1386{
1387    pub geom: &'a dyn postgis::GeometryCollection<'a, ItemType = G, Iter = GI>,
1388    pub srid: Option<i32>,
1389    pub point_type: PointType,
1390}
1391
1392pub trait AsEwkbGeometryCollection<'a> {
1393    type PointType: 'a + postgis::Point + EwkbRead;
1394    type PointIter: Iterator<Item = &'a Self::PointType>
1395        + ExactSizeIterator<Item = &'a Self::PointType>;
1396    type MultiPointType: 'a
1397        + postgis::MultiPoint<'a, ItemType = Self::PointType, Iter = Self::PointIter>;
1398    type LineType: 'a + postgis::LineString<'a, ItemType = Self::PointType, Iter = Self::PointIter>;
1399    type LineIter: Iterator<Item = &'a Self::LineType>
1400        + ExactSizeIterator<Item = &'a Self::LineType>;
1401    type MultiLineType: 'a
1402        + postgis::MultiLineString<'a, ItemType = Self::LineType, Iter = Self::LineIter>;
1403    type PolyType: 'a + postgis::Polygon<'a, ItemType = Self::LineType, Iter = Self::LineIter>;
1404    type PolyIter: Iterator<Item = &'a Self::PolyType>
1405        + ExactSizeIterator<Item = &'a Self::PolyType>;
1406    type MultiPolyType: 'a
1407        + postgis::MultiPolygon<'a, ItemType = Self::PolyType, Iter = Self::PolyIter>;
1408    type GeomType: 'a
1409        + postgis::Geometry<
1410            'a,
1411            Point = Self::PointType,
1412            LineString = Self::LineType,
1413            Polygon = Self::PolyType,
1414            MultiPoint = Self::MultiPointType,
1415            MultiLineString = Self::MultiLineType,
1416            MultiPolygon = Self::MultiPolyType,
1417            GeometryCollection = Self::GeomCollection,
1418        >;
1419    type GeomIter: Iterator<Item = &'a Self::GeomType>
1420        + ExactSizeIterator<Item = &'a Self::GeomType>;
1421    type GeomCollection: 'a
1422        + postgis::GeometryCollection<'a, ItemType = Self::GeomType, Iter = Self::GeomIter>;
1423    fn as_ewkb(
1424        &'a self,
1425    ) -> EwkbGeometryCollection<
1426        'a,
1427        Self::PointType,
1428        Self::PointIter,
1429        Self::MultiPointType,
1430        Self::LineType,
1431        Self::LineIter,
1432        Self::MultiLineType,
1433        Self::PolyType,
1434        Self::PolyIter,
1435        Self::MultiPolyType,
1436        Self::GeomType,
1437        Self::GeomIter,
1438        Self::GeomCollection,
1439    >;
1440}
1441
1442impl<'a, P, PI, MP, L, LI, ML, Y, YI, MY, G, GI, GC> fmt::Debug
1443    for EwkbGeometryCollection<'a, P, PI, MP, L, LI, ML, Y, YI, MY, G, GI, GC>
1444where
1445    P: 'a + postgis::Point,
1446    PI: 'a + Iterator<Item = &'a P> + ExactSizeIterator<Item = &'a P>,
1447    MP: 'a + postgis::MultiPoint<'a, ItemType = P, Iter = PI>,
1448    L: 'a + postgis::LineString<'a, ItemType = P, Iter = PI>,
1449    LI: 'a + Iterator<Item = &'a L> + ExactSizeIterator<Item = &'a L>,
1450    ML: 'a + postgis::MultiLineString<'a, ItemType = L, Iter = LI>,
1451    Y: 'a + postgis::Polygon<'a, ItemType = L, Iter = LI>,
1452    YI: 'a + Iterator<Item = &'a Y> + ExactSizeIterator<Item = &'a Y>,
1453    MY: 'a + postgis::MultiPolygon<'a, ItemType = Y, Iter = YI>,
1454    G: 'a
1455        + postgis::Geometry<
1456            'a,
1457            Point = P,
1458            LineString = L,
1459            Polygon = Y,
1460            MultiPoint = MP,
1461            MultiLineString = ML,
1462            MultiPolygon = MY,
1463            GeometryCollection = GC,
1464        >,
1465    GI: 'a + Iterator<Item = &'a G> + ExactSizeIterator<Item = &'a G>,
1466    GC: 'a + postgis::GeometryCollection<'a, ItemType = G, Iter = GI>,
1467{
1468    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1469        write!(f, stringify!(EwkbGeometryCollection))?; //TODO
1470        Ok(())
1471    }
1472}
1473
1474impl<'a, P, PI, MP, L, LI, ML, Y, YI, MY, G, GI, GC> EwkbWrite
1475    for EwkbGeometryCollection<'a, P, PI, MP, L, LI, ML, Y, YI, MY, G, GI, GC>
1476where
1477    P: 'a + postgis::Point,
1478    PI: 'a + Iterator<Item = &'a P> + ExactSizeIterator<Item = &'a P>,
1479    MP: 'a + postgis::MultiPoint<'a, ItemType = P, Iter = PI>,
1480    L: 'a + postgis::LineString<'a, ItemType = P, Iter = PI>,
1481    LI: 'a + Iterator<Item = &'a L> + ExactSizeIterator<Item = &'a L>,
1482    ML: 'a + postgis::MultiLineString<'a, ItemType = L, Iter = LI>,
1483    Y: 'a + postgis::Polygon<'a, ItemType = L, Iter = LI>,
1484    YI: 'a + Iterator<Item = &'a Y> + ExactSizeIterator<Item = &'a Y>,
1485    MY: 'a + postgis::MultiPolygon<'a, ItemType = Y, Iter = YI>,
1486    G: 'a
1487        + postgis::Geometry<
1488            'a,
1489            Point = P,
1490            LineString = L,
1491            Polygon = Y,
1492            MultiPoint = MP,
1493            MultiLineString = ML,
1494            MultiPolygon = MY,
1495            GeometryCollection = GC,
1496        >,
1497    GI: 'a + Iterator<Item = &'a G> + ExactSizeIterator<Item = &'a G>,
1498    GC: 'a + postgis::GeometryCollection<'a, ItemType = G, Iter = GI>,
1499{
1500    fn opt_srid(&self) -> Option<i32> {
1501        self.srid
1502    }
1503
1504    fn type_id(&self) -> u32 {
1505        0x07 | Self::wkb_type_id(&self.point_type, self.srid)
1506    }
1507
1508    fn write_ewkb_body<W: Write + ?Sized>(&self, w: &mut W) -> Result<(), Error> {
1509        w.write_u32::<LittleEndian>(self.geom.geometries().len() as u32)?;
1510
1511        for geom in self.geom.geometries() {
1512            match geom.as_type() {
1513                postgis::GeometryType::Point(geom) => {
1514                    let wkb = EwkbPoint {
1515                        geom: geom,
1516                        srid: None,
1517                        point_type: self.point_type.clone(),
1518                    };
1519                    wkb.write_ewkb(w)?;
1520                }
1521                postgis::GeometryType::LineString(geom) => {
1522                    let wkb = EwkbLineString {
1523                        geom: geom,
1524                        srid: None,
1525                        point_type: self.point_type.clone(),
1526                    };
1527                    wkb.write_ewkb(w)?;
1528                }
1529                postgis::GeometryType::Polygon(geom) => {
1530                    let wkb = EwkbPolygon {
1531                        geom: geom,
1532                        srid: None,
1533                        point_type: self.point_type.clone(),
1534                    };
1535                    wkb.write_ewkb(w)?;
1536                }
1537                postgis::GeometryType::MultiPoint(geom) => {
1538                    let wkb = EwkbMultiPoint {
1539                        geom: geom,
1540                        srid: None,
1541                        point_type: self.point_type.clone(),
1542                    };
1543                    wkb.write_ewkb(w)?;
1544                }
1545                postgis::GeometryType::MultiLineString(geom) => {
1546                    let wkb = EwkbMultiLineString {
1547                        geom: geom,
1548                        srid: None,
1549                        point_type: self.point_type.clone(),
1550                    };
1551                    wkb.write_ewkb(w)?;
1552                }
1553                postgis::GeometryType::MultiPolygon(geom) => {
1554                    let wkb = EwkbMultiPolygon {
1555                        geom: geom,
1556                        srid: None,
1557                        point_type: self.point_type.clone(),
1558                    };
1559                    wkb.write_ewkb(w)?;
1560                }
1561                postgis::GeometryType::GeometryCollection(geom) => {
1562                    let wkb = EwkbGeometryCollection {
1563                        geom: geom,
1564                        srid: None,
1565                        point_type: self.point_type.clone(),
1566                    };
1567                    wkb.write_ewkb(w)?;
1568                }
1569            }
1570        }
1571        Ok(())
1572    }
1573}
1574
1575impl<'a, P> AsEwkbGeometryCollection<'a> for GeometryCollectionT<P>
1576where
1577    P: 'a + postgis::Point + EwkbRead,
1578{
1579    type PointType = P;
1580    type PointIter = Iter<'a, P>;
1581    type MultiPointType = MultiPointT<P>;
1582    type LineType = LineStringT<P>;
1583    type LineIter = Iter<'a, Self::LineType>;
1584    type MultiLineType = MultiLineStringT<P>;
1585    type PolyType = PolygonT<P>;
1586    type PolyIter = Iter<'a, Self::PolyType>;
1587    type MultiPolyType = MultiPolygonT<P>;
1588    type GeomType = GeometryT<P>;
1589    type GeomIter = Iter<'a, Self::GeomType>;
1590    type GeomCollection = GeometryCollectionT<P>;
1591    fn as_ewkb(
1592        &'a self,
1593    ) -> EwkbGeometryCollection<
1594        'a,
1595        Self::PointType,
1596        Self::PointIter,
1597        Self::MultiPointType,
1598        Self::LineType,
1599        Self::LineIter,
1600        Self::MultiLineType,
1601        Self::PolyType,
1602        Self::PolyIter,
1603        Self::MultiPolyType,
1604        Self::GeomType,
1605        Self::GeomIter,
1606        Self::GeomCollection,
1607    > {
1608        EwkbGeometryCollection {
1609            geom: self,
1610            srid: self.srid,
1611            point_type: P::point_type(),
1612        }
1613    }
1614}
1615
1616/// OGC GeometryCollection type
1617pub type GeometryCollection = GeometryCollectionT<Point>;
1618/// OGC GeometryCollectionZ type
1619pub type GeometryCollectionZ = GeometryCollectionT<PointZ>;
1620/// OGC GeometryCollectionM type
1621pub type GeometryCollectionM = GeometryCollectionT<PointM>;
1622/// OGC GeometryCollectionZM type
1623pub type GeometryCollectionZM = GeometryCollectionT<PointZM>;
1624
1625#[test]
1626#[cfg_attr(rustfmt, rustfmt_skip)]
1627fn test_point_write() {
1628    // 'POINT (10 -20)'
1629    let point = Point { x: 10.0, y: -20.0, srid: None };
1630    assert_eq!(point.as_ewkb().to_hex_ewkb(), "0101000000000000000000244000000000000034C0");
1631
1632    // 'POINT (10 -20 100)'
1633    let point = PointZ { x: 10.0, y: -20.0, z: 100.0, srid: None };
1634    assert_eq!(point.as_ewkb().to_hex_ewkb(), "0101000080000000000000244000000000000034C00000000000005940");
1635
1636    // 'POINTM (10 -20 1)'
1637    let point = PointM { x: 10.0, y: -20.0, m: 1.0, srid: None };
1638    assert_eq!(point.as_ewkb().to_hex_ewkb(), "0101000040000000000000244000000000000034C0000000000000F03F");
1639
1640    // 'POINT (10 -20 100 1)'
1641    let point = PointZM { x: 10.0, y: -20.0, z: 100.0, m: 1.0, srid: None };
1642    assert_eq!(point.as_ewkb().to_hex_ewkb(), "01010000C0000000000000244000000000000034C00000000000005940000000000000F03F");
1643
1644    // 'POINT (-0 -1)'
1645    let point = Point { x: 0.0, y: -1.0, srid: None };
1646    assert_eq!(point.as_ewkb().to_hex_ewkb(), "01010000000000000000000000000000000000F0BF");
1647    // TODO: -0 in PostGIS gives 01010000000000000000000080000000000000F0BF
1648
1649    // 'SRID=4326;POINT (10 -20)'
1650    let point = Point { x: 10.0, y: -20.0, srid: Some(4326) };
1651    assert_eq!(point.as_ewkb().to_hex_ewkb(), "0101000020E6100000000000000000244000000000000034C0");
1652}
1653
1654#[test]
1655#[cfg_attr(rustfmt, rustfmt_skip)]
1656fn test_line_write() {
1657    let p = |x, y| Point { x: x, y: y, srid: None };
1658    // 'LINESTRING (10 -20, 0 -0.5)'
1659    let line = LineStringT::<Point> {srid: None, points: vec![p(10.0, -20.0), p(0., -0.5)]};
1660    assert_eq!(line.as_ewkb().to_hex_ewkb(), "010200000002000000000000000000244000000000000034C00000000000000000000000000000E0BF");
1661
1662    // 'SRID=4326;LINESTRING (10 -20, 0 -0.5)'
1663    let line = LineStringT::<Point> {srid: Some(4326), points: vec![p(10.0, -20.0), p(0., -0.5)]};
1664    assert_eq!(line.as_ewkb().to_hex_ewkb(), "0102000020E610000002000000000000000000244000000000000034C00000000000000000000000000000E0BF");
1665
1666    let p = |x, y, z| PointZ { x: x, y: y, z: z, srid: Some(4326) };
1667    // 'SRID=4326;LINESTRING (10 -20 100, 0 0.5 101)'
1668    let line = LineStringT::<PointZ> {srid: Some(4326), points: vec![p(10.0, -20.0, 100.0), p(0., -0.5, 101.0)]};
1669    assert_eq!(line.as_ewkb().to_hex_ewkb(), "01020000A0E610000002000000000000000000244000000000000034C000000000000059400000000000000000000000000000E0BF0000000000405940");
1670}
1671
1672#[test]
1673#[cfg_attr(rustfmt, rustfmt_skip)]
1674fn test_polygon_write() {
1675    let p = |x, y| Point { x: x, y: y, srid: Some(4326) };
1676    // SELECT 'SRID=4326;POLYGON ((0 0, 2 0, 2 2, 0 2, 0 0))'::geometry
1677    let line = LineStringT::<Point> {srid: Some(4326), points: vec![p(0., 0.), p(2., 0.), p(2., 2.), p(0., 2.), p(0., 0.)]};
1678    let poly = PolygonT::<Point> {srid: Some(4326), rings: vec![line]};
1679    assert_eq!(poly.as_ewkb().to_hex_ewkb(), "0103000020E610000001000000050000000000000000000000000000000000000000000000000000400000000000000000000000000000004000000000000000400000000000000000000000000000004000000000000000000000000000000000");
1680}
1681
1682#[test]
1683#[cfg_attr(rustfmt, rustfmt_skip)]
1684fn test_multipoint_write() {
1685    let p = |x, y, z| PointZ { x: x, y: y, z: z, srid: Some(4326) };
1686    // SELECT 'SRID=4326;MULTIPOINT ((10 -20 100), (0 -0.5 101))'::geometry
1687    let points = MultiPointT::<PointZ> {srid: Some(4326), points: vec![p(10.0, -20.0, 100.0), p(0., -0.5, 101.0)]};
1688    assert_eq!(points.as_ewkb().to_hex_ewkb(), "01040000A0E6100000020000000101000080000000000000244000000000000034C0000000000000594001010000800000000000000000000000000000E0BF0000000000405940");
1689}
1690
1691#[test]
1692#[cfg_attr(rustfmt, rustfmt_skip)]
1693fn test_multiline_write() {
1694    let p = |x, y| Point { x: x, y: y, srid: Some(4326) };
1695    // SELECT 'SRID=4326;MULTILINESTRING ((10 -20, 0 -0.5), (0 0, 2 0))'::geometry
1696    let line1 = LineStringT::<Point> {srid: Some(4326), points: vec![p(10.0, -20.0), p(0., -0.5)]};
1697    let line2 = LineStringT::<Point> {srid: Some(4326), points: vec![p(0., 0.), p(2., 0.)]};
1698    let multiline = MultiLineStringT::<Point> {srid: Some(4326),lines: vec![line1, line2]};
1699    assert_eq!(multiline.as_ewkb().to_hex_ewkb(), "0105000020E610000002000000010200000002000000000000000000244000000000000034C00000000000000000000000000000E0BF0102000000020000000000000000000000000000000000000000000000000000400000000000000000");
1700}
1701
1702#[test]
1703#[cfg_attr(rustfmt, rustfmt_skip)]
1704fn test_multipolygon_write() {
1705    let p = |x, y| Point { x: x, y: y, srid: Some(4326) };
1706    // 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
1707    let line = LineStringT::<Point> {srid: Some(4326), points: vec![p(0., 0.), p(2., 0.), p(2., 2.), p(0., 2.), p(0., 0.)]};
1708    let poly1 = PolygonT::<Point> {srid: Some(4326), rings: vec![line]};
1709    let line = LineStringT::<Point> {srid: Some(4326), points: vec![p(10., 10.), p(-2., 10.), p(-2., -2.), p(10., -2.), p(10., 10.)]};
1710    let poly2 = PolygonT::<Point> {srid: Some(4326), rings: vec![line]};
1711    let multipoly = MultiPolygonT::<Point> {srid: Some(4326), polygons: vec![poly1, poly2]};
1712    assert_eq!(multipoly.as_ewkb().to_hex_ewkb(), "0106000020E610000002000000010300000001000000050000000000000000000000000000000000000000000000000000400000000000000000000000000000004000000000000000400000000000000000000000000000004000000000000000000000000000000000010300000001000000050000000000000000002440000000000000244000000000000000C0000000000000244000000000000000C000000000000000C0000000000000244000000000000000C000000000000024400000000000002440");
1713}
1714
1715#[test]
1716#[cfg_attr(rustfmt, rustfmt_skip)]
1717fn test_ewkb_adapters() {
1718    let point = Point { x: 10.0, y: -20.0, srid: Some(4326) };
1719    let ewkb = EwkbPoint { geom: &point, srid: Some(4326), point_type: PointType::Point };
1720    assert_eq!(ewkb.to_hex_ewkb(), "0101000020E6100000000000000000244000000000000034C0");
1721    assert_eq!(point.as_ewkb().to_hex_ewkb(), "0101000020E6100000000000000000244000000000000034C0");
1722}
1723
1724#[cfg(test)]
1725#[cfg_attr(rustfmt, rustfmt_skip)]
1726fn hex_to_vec(hexstr: &str) -> Vec<u8> {
1727    hexstr.as_bytes().chunks(2).map(|chars| {
1728        let hb = if chars[0] <= 57 { chars[0] - 48 } else { chars[0] - 55 };
1729        let lb = if chars[1] <= 57 { chars[1] - 48 } else { chars[1] - 55 };
1730        hb * 16 + lb
1731    }).collect::<Vec<_>>()
1732}
1733
1734#[test]
1735#[cfg_attr(rustfmt, rustfmt_skip)]
1736fn test_point_read() {
1737    // SELECT 'POINT(10 -20)'::geometry
1738    let ewkb = hex_to_vec("0101000000000000000000244000000000000034C0");
1739    assert_eq!(ewkb, &[1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 64, 0, 0, 0, 0, 0, 0, 52, 192]);
1740    let point = Point::read_ewkb(&mut ewkb.as_slice()).unwrap();
1741    assert_eq!(point, Point { x: 10.0, y: -20.0, srid: None });
1742
1743    // SELECT 'POINT(10 -20 100)'::geometry
1744    let ewkb = hex_to_vec("0101000080000000000000244000000000000034C00000000000005940");
1745    let point = PointZ::read_ewkb(&mut ewkb.as_slice()).unwrap();
1746    assert_eq!(point, PointZ { x: 10.0, y: -20.0, z: 100.0, srid: None });
1747
1748    let point = Point::read_ewkb(&mut ewkb.as_slice()).unwrap();
1749    assert_eq!(point, Point { x: 10.0, y: -20.0, srid: None });
1750
1751    // SELECT 'POINTM(10 -20 1)'::geometry
1752    let ewkb = hex_to_vec("0101000040000000000000244000000000000034C0000000000000F03F");
1753    let point = PointM::read_ewkb(&mut ewkb.as_slice()).unwrap();
1754    assert_eq!(point, PointM { x: 10.0, y: -20.0, m: 1.0, srid: None });
1755
1756    // SELECT 'POINT(10 -20 100 1)'::geometry
1757    let ewkb = hex_to_vec("01010000C0000000000000244000000000000034C00000000000005940000000000000F03F");
1758    let point = PointZM::read_ewkb(&mut ewkb.as_slice()).unwrap();
1759    assert_eq!(point, PointZM { x: 10.0, y: -20.0, z: 100.0, m: 1.0, srid: None });
1760}
1761
1762#[test]
1763#[cfg_attr(rustfmt, rustfmt_skip)]
1764fn test_line_read() {
1765    let p = |x, y| Point { x: x, y: y, srid: None };
1766    // SELECT 'LINESTRING (10 -20, 0 -0.5)'::geometry
1767    let ewkb = hex_to_vec("010200000002000000000000000000244000000000000034C00000000000000000000000000000E0BF");
1768    let line = LineStringT::<Point>::read_ewkb(&mut ewkb.as_slice()).unwrap();
1769    assert_eq!(line, LineStringT::<Point> {srid: None, points: vec![p(10.0, -20.0), p(0., -0.5)]});
1770
1771    let p = |x, y, z| PointZ { x: x, y: y, z: z, srid: Some(4326) };
1772    // SELECT 'SRID=4326;LINESTRING (10 -20 100, 0 -0.5 101)'::geometry
1773    let ewkb = hex_to_vec("01020000A0E610000002000000000000000000244000000000000034C000000000000059400000000000000000000000000000E0BF0000000000405940");
1774    let line = LineStringT::<PointZ>::read_ewkb(&mut ewkb.as_slice()).unwrap();
1775    assert_eq!(line, LineStringT::<PointZ> {srid: Some(4326), points: vec![p(10.0, -20.0, 100.0), p(0., -0.5, 101.0)]});
1776}
1777
1778#[test]
1779#[cfg_attr(rustfmt, rustfmt_skip)]
1780fn test_polygon_read() {
1781    let p = |x, y| Point { x: x, y: y, srid: Some(4326) };
1782    // SELECT 'SRID=4326;POLYGON ((0 0, 2 0, 2 2, 0 2, 0 0))'::geometry
1783    let ewkb = hex_to_vec("0103000020E610000001000000050000000000000000000000000000000000000000000000000000400000000000000000000000000000004000000000000000400000000000000000000000000000004000000000000000000000000000000000");
1784    let poly = PolygonT::<Point>::read_ewkb(&mut ewkb.as_slice()).unwrap();
1785    let line = LineStringT::<Point> {srid: Some(4326), points: vec![p(0., 0.), p(2., 0.), p(2., 2.), p(0., 2.), p(0., 0.)]};
1786    assert_eq!(poly, PolygonT::<Point> {srid: Some(4326), rings: vec![line]});
1787}
1788
1789#[test]
1790#[cfg_attr(rustfmt, rustfmt_skip)]
1791fn test_multipoint_read() {
1792    let p = |x, y, z| PointZ { x: x, y: y, z: z, srid: None }; // PostGIS doesn't store SRID for sub-geometries
1793    // SELECT 'SRID=4326;MULTIPOINT ((10 -20 100), (0 -0.5 101))'::geometry
1794    let ewkb = hex_to_vec("01040000A0E6100000020000000101000080000000000000244000000000000034C0000000000000594001010000800000000000000000000000000000E0BF0000000000405940");
1795    let points = MultiPointT::<PointZ>::read_ewkb(&mut ewkb.as_slice()).unwrap();
1796    assert_eq!(points, MultiPointT::<PointZ> {srid: Some(4326), points: vec![p(10.0, -20.0, 100.0), p(0., -0.5, 101.0)]});
1797}
1798
1799#[test]
1800#[cfg_attr(rustfmt, rustfmt_skip)]
1801fn test_multiline_read() {
1802    let p = |x, y| Point { x: x, y: y, srid: None }; // PostGIS doesn't store SRID for sub-geometries
1803    // SELECT 'SRID=4326;MULTILINESTRING ((10 -20, 0 -0.5), (0 0, 2 0))'::geometry
1804    let ewkb = hex_to_vec("0105000020E610000002000000010200000002000000000000000000244000000000000034C00000000000000000000000000000E0BF0102000000020000000000000000000000000000000000000000000000000000400000000000000000");
1805    let poly = MultiLineStringT::<Point>::read_ewkb(&mut ewkb.as_slice()).unwrap();
1806    let line1 = LineStringT::<Point> {srid: None, points: vec![p(10.0, -20.0), p(0., -0.5)]};
1807    let line2 = LineStringT::<Point> {srid: None, points: vec![p(0., 0.), p(2., 0.)]};
1808    assert_eq!(poly, MultiLineStringT::<Point> {srid: Some(4326), lines: vec![line1, line2]});
1809}
1810
1811#[test]
1812#[cfg_attr(rustfmt, rustfmt_skip)]
1813fn test_multipolygon_read() {
1814    let p = |x, y| Point { x: x, y: y, srid: None }; // PostGIS doesn't store SRID for sub-geometries
1815    // 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
1816    let ewkb = hex_to_vec("0106000020E610000002000000010300000001000000050000000000000000000000000000000000000000000000000000400000000000000000000000000000004000000000000000400000000000000000000000000000004000000000000000000000000000000000010300000001000000050000000000000000002440000000000000244000000000000000C0000000000000244000000000000000C000000000000000C0000000000000244000000000000000C000000000000024400000000000002440");
1817    let multipoly = MultiPolygonT::<Point>::read_ewkb(&mut ewkb.as_slice()).unwrap();
1818    let line = LineStringT::<Point> {srid: None, points: vec![p(0., 0.), p(2., 0.), p(2., 2.), p(0., 2.), p(0., 0.)]};
1819    let poly1 = PolygonT::<Point> {srid: None, rings: vec![line]};
1820    let line = LineStringT::<Point> {srid: None, points: vec![p(10., 10.), p(-2., 10.), p(-2., -2.), p(10., -2.), p(10., 10.)]};
1821    let poly2 = PolygonT::<Point> {srid: None, rings: vec![line]};
1822    assert_eq!(multipoly, MultiPolygonT::<Point> {srid: Some(4326), polygons: vec![poly1, poly2]});
1823}
1824
1825#[test]
1826#[cfg_attr(rustfmt, rustfmt_skip)]
1827fn test_geometrycollection_read() {
1828    // SELECT 'GeometryCollection(POINT (10 10),POINT (30 30),LINESTRING (15 15, 20 20))'::geometry
1829    let ewkb = hex_to_vec("01070000000300000001010000000000000000002440000000000000244001010000000000000000003E400000000000003E400102000000020000000000000000002E400000000000002E4000000000000034400000000000003440");
1830    let geom = GeometryCollectionT::<Point>::read_ewkb(&mut ewkb.as_slice()).unwrap();
1831    assert_eq!(format!("{:.0?}", geom), "GeometryCollectionT { geometries: [Point(Point { x: 10, y: 10, srid: None }), Point(Point { x: 30, y: 30, srid: None }), LineString(LineStringT { points: [Point { x: 15, y: 15, srid: None }, Point { x: 20, y: 20, srid: None }], srid: None })], srid: None }");
1832}
1833
1834#[test]
1835#[cfg_attr(rustfmt, rustfmt_skip)]
1836fn test_geometry_read() {
1837    // SELECT 'POINT(10 -20 100 1)'::geometry
1838    let ewkb = hex_to_vec("01010000C0000000000000244000000000000034C00000000000005940000000000000F03F");
1839    let geom = GeometryT::<PointZM>::read_ewkb(&mut ewkb.as_slice()).unwrap();
1840    assert_eq!(format!("{:.0?}", geom), "Point(PointZM { x: 10, y: -20, z: 100, m: 1, srid: None })");
1841    // SELECT 'SRID=4326;LINESTRING (10 -20 100, 0 -0.5 101)'::geometry
1842    let ewkb = hex_to_vec("01020000A0E610000002000000000000000000244000000000000034C000000000000059400000000000000000000000000000E0BF0000000000405940");
1843    let geom = GeometryT::<PointZ>::read_ewkb(&mut ewkb.as_slice()).unwrap();
1844    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) })");
1845    // SELECT 'SRID=4326;POLYGON ((0 0, 2 0, 2 2, 0 2, 0 0))'::geometry
1846    let ewkb = hex_to_vec("0103000020E610000001000000050000000000000000000000000000000000000000000000000000400000000000000000000000000000004000000000000000400000000000000000000000000000004000000000000000000000000000000000");
1847    let geom = GeometryT::<Point>::read_ewkb(&mut ewkb.as_slice()).unwrap();
1848    assert_eq!(format!("{:.0?}", geom), "Polygon(PolygonT { rings: [LineStringT { points: [Point { x: 0, y: 0, srid: Some(4326) }, Point { x: 2, y: 0, srid: Some(4326) }, Point { x: 2, y: 2, srid: Some(4326) }, Point { x: 0, y: 2, srid: Some(4326) }, Point { x: 0, y: 0, srid: Some(4326) }], srid: Some(4326) }], srid: Some(4326) })");
1849    // SELECT 'SRID=4326;MULTIPOINT ((10 -20 100), (0 -0.5 101))'::geometry
1850    let ewkb = hex_to_vec("01040000A0E6100000020000000101000080000000000000244000000000000034C0000000000000594001010000800000000000000000000000000000E0BF0000000000405940");
1851    let geom = GeometryT::<PointZ>::read_ewkb(&mut ewkb.as_slice()).unwrap();
1852    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) })");
1853    // SELECT 'SRID=4326;MULTILINESTRING ((10 -20, 0 -0.5), (0 0, 2 0))'::geometry
1854    let ewkb = hex_to_vec("0105000020E610000002000000010200000002000000000000000000244000000000000034C00000000000000000000000000000E0BF0102000000020000000000000000000000000000000000000000000000000000400000000000000000");
1855    let geom = GeometryT::<Point>::read_ewkb(&mut ewkb.as_slice()).unwrap();
1856    assert_eq!(format!("{:.1?}", geom), "MultiLineString(MultiLineStringT { lines: [LineStringT { points: [Point { x: 10.0, y: -20.0, srid: None }, Point { x: 0.0, y: -0.5, srid: None }], srid: None }, LineStringT { points: [Point { x: 0.0, y: 0.0, srid: None }, Point { x: 2.0, y: 0.0, srid: None }], srid: None }], srid: Some(4326) })");
1857    // 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
1858    let ewkb = hex_to_vec("0106000020E610000002000000010300000001000000050000000000000000000000000000000000000000000000000000400000000000000000000000000000004000000000000000400000000000000000000000000000004000000000000000000000000000000000010300000001000000050000000000000000002440000000000000244000000000000000C0000000000000244000000000000000C000000000000000C0000000000000244000000000000000C000000000000024400000000000002440");
1859    let geom = GeometryT::<Point>::read_ewkb(&mut ewkb.as_slice()).unwrap();
1860    assert_eq!(format!("{:.0?}", geom), "MultiPolygon(MultiPolygonT { polygons: [PolygonT { rings: [LineStringT { points: [Point { x: 0, y: 0, srid: None }, Point { x: 2, y: 0, srid: None }, Point { x: 2, y: 2, srid: None }, Point { x: 0, y: 2, srid: None }, Point { x: 0, y: 0, srid: None }], srid: None }], srid: None }, PolygonT { rings: [LineStringT { points: [Point { x: 10, y: 10, srid: None }, Point { x: -2, y: 10, srid: None }, Point { x: -2, y: -2, srid: None }, Point { x: 10, y: -2, srid: None }, Point { x: 10, y: 10, srid: None }], srid: None }], srid: None }], srid: Some(4326) })");
1861    // SELECT 'GeometryCollection(POINT (10 10),POINT (30 30),LINESTRING (15 15, 20 20))'::geometry
1862    let ewkb = hex_to_vec("01070000000300000001010000000000000000002440000000000000244001010000000000000000003E400000000000003E400102000000020000000000000000002E400000000000002E4000000000000034400000000000003440");
1863    let geom = GeometryT::<Point>::read_ewkb(&mut ewkb.as_slice()).unwrap();
1864    assert_eq!(format!("{:.0?}", geom), "GeometryCollection(GeometryCollectionT { geometries: [Point(Point { x: 10, y: 10, srid: None }), Point(Point { x: 30, y: 30, srid: None }), LineString(LineStringT { points: [Point { x: 15, y: 15, srid: None }, Point { x: 20, y: 20, srid: None }], srid: None })], srid: None })");
1865}
1866
1867#[test]
1868#[cfg_attr(rustfmt, rustfmt_skip)]
1869fn test_read_error() {
1870    // SELECT 'LINESTRING (10 -20, 0 -0.5)'::geometry
1871    let ewkb = hex_to_vec("010200000002000000000000000000244000000000000034C00000000000000000000000000000E0BF");
1872    let poly = PolygonT::<Point>::read_ewkb(&mut ewkb.as_slice());
1873    assert!(poly.is_err()); // UnexpectedEof "failed to fill whole buffer"
1874}
1875
1876#[test]
1877#[cfg_attr(rustfmt, rustfmt_skip)]
1878fn test_iterators() {
1879    // Iterator traits:
1880    use crate::types::LineString;
1881
1882    let p = |x, y| Point { x: x, y: y, srid: None };
1883    let line = self::LineStringT::<Point> {srid: Some(4326), points: vec![p(10.0, -20.0), p(0., -0.5)]};
1884    assert_eq!(line.points().last(), Some(&Point { x: 0., y: -0.5, srid: None }));
1885}