1use std::fmt::Debug;
2use std::io::Cursor;
3
4use crate::{
5 ewkb::{EwkbSerializable, GeometryType, BIG_ENDIAN},
6 polygon::*,
7 sql_types::{Geography, Geometry},
8 types::*,
9};
10
11#[cfg(feature = "diesel")]
12use crate::{
13 ewkb::read_ewkb_header,
14 geometrycollection::{read_geometry_collection_body, write_geometry_collection},
15 linestring::{read_linestring_body, write_linestring},
16 multiline::{read_multiline_body, write_multiline},
17 multipoint::{read_multi_point_body, write_multi_point},
18 multipolygon::{read_multi_polygon_body, write_multi_polygon},
19 points::{read_point_coordinates, write_point},
20};
21
22use byteorder::{BigEndian, LittleEndian};
23
24impl<T> GeometryContainer<T>
25where
26 T: PointT + Clone,
27{
28 pub fn dimension(&self) -> u32 {
29 match self {
30 GeometryContainer::Point(g) => g.dimension(),
31 GeometryContainer::LineString(g) => g.dimension(),
32 GeometryContainer::Polygon(g) => g.dimension(),
33 GeometryContainer::MultiPoint(g) => g.dimension(),
34 GeometryContainer::MultiLineString(g) => g.dimension(),
35 GeometryContainer::MultiPolygon(g) => g.dimension(),
36 GeometryContainer::GeometryCollection(g) => g.dimension(),
37 }
38 }
39}
40
41#[cfg(feature = "diesel")]
42impl<T> diesel::serialize::ToSql<Geometry, diesel::pg::Pg> for GeometryContainer<T>
43where
44 T: PointT
45 + Debug
46 + PartialEq
47 + Clone
48 + EwkbSerializable
49 + diesel::serialize::ToSql<Geometry, diesel::pg::Pg>,
50{
51 fn to_sql(
52 &self,
53 out: &mut diesel::serialize::Output<diesel::pg::Pg>,
54 ) -> diesel::serialize::Result {
55 match self {
56 GeometryContainer::Point(g) => write_point(g, g.get_srid(), out),
57 GeometryContainer::MultiPoint(g) => write_multi_point(g, g.srid, out),
58 GeometryContainer::LineString(g) => write_linestring(g, g.srid, out),
59 GeometryContainer::MultiLineString(g) => write_multiline(g, g.srid, out),
60 GeometryContainer::Polygon(g) => write_polygon(g, g.srid, out),
61 GeometryContainer::MultiPolygon(g) => write_multi_polygon(g, g.srid, out),
62 GeometryContainer::GeometryCollection(g) => write_geometry_collection(g, g.srid, out),
63 }
64 }
65}
66
67#[cfg(feature = "diesel")]
68impl<T> diesel::serialize::ToSql<Geography, diesel::pg::Pg> for GeometryContainer<T>
69where
70 T: PointT
71 + Debug
72 + PartialEq
73 + Clone
74 + EwkbSerializable
75 + diesel::serialize::ToSql<Geometry, diesel::pg::Pg>,
76{
77 fn to_sql(
78 &self,
79 out: &mut diesel::serialize::Output<diesel::pg::Pg>,
80 ) -> diesel::serialize::Result {
81 match self {
82 GeometryContainer::Point(g) => write_point(g, g.get_srid(), out),
83 GeometryContainer::MultiPoint(g) => write_multi_point(g, g.srid, out),
84 GeometryContainer::LineString(g) => write_linestring(g, g.srid, out),
85 GeometryContainer::MultiLineString(g) => write_multiline(g, g.srid, out),
86 GeometryContainer::Polygon(g) => write_polygon(g, g.srid, out),
87 GeometryContainer::MultiPolygon(g) => write_multi_polygon(g, g.srid, out),
88 GeometryContainer::GeometryCollection(g) => write_geometry_collection(g, g.srid, out),
89 }
90 }
91}
92
93#[cfg(feature = "diesel")]
94impl<T> diesel::deserialize::FromSql<Geometry, diesel::pg::Pg> for GeometryContainer<T>
95where
96 T: PointT + Debug + Clone + diesel::deserialize::FromSql<Geometry, diesel::pg::Pg>,
97{
98 fn from_sql(bytes: diesel::pg::PgValue) -> diesel::deserialize::Result<Self> {
99 use byteorder::ReadBytesExt;
100
101 let mut cursor = Cursor::new(bytes.as_bytes());
102 let end = cursor.read_u8()?;
103 let container = if end == BIG_ENDIAN {
104 let g_header = read_ewkb_header::<BigEndian>(&mut cursor)?;
105 match GeometryType::from(g_header.g_type) {
106 GeometryType::Point => {
107 GeometryContainer::Point(read_point_coordinates::<BigEndian, T>(
108 &mut cursor,
109 g_header.g_type,
110 g_header.srid,
111 )?)
112 }
113 GeometryType::MultiPoint => {
114 GeometryContainer::MultiPoint(read_multi_point_body::<BigEndian, T>(
115 g_header.g_type,
116 g_header.srid,
117 &mut cursor,
118 )?)
119 }
120 GeometryType::LineString => {
121 GeometryContainer::LineString(read_linestring_body::<BigEndian, T>(
122 g_header.g_type,
123 g_header.srid,
124 &mut cursor,
125 )?)
126 }
127 GeometryType::MultiLineString => {
128 GeometryContainer::MultiLineString(read_multiline_body::<BigEndian, T>(
129 g_header.g_type,
130 g_header.srid,
131 &mut cursor,
132 )?)
133 }
134 GeometryType::Polygon => {
135 GeometryContainer::Polygon(read_polygon_body::<BigEndian, T>(
136 g_header.g_type,
137 g_header.srid,
138 &mut cursor,
139 )?)
140 }
141 GeometryType::MultiPolygon => {
142 GeometryContainer::MultiPolygon(read_multi_polygon_body::<BigEndian, T>(
143 g_header.g_type,
144 g_header.srid,
145 &mut cursor,
146 )?)
147 }
148 GeometryType::GeometryCollection => {
149 GeometryContainer::GeometryCollection(read_geometry_collection_body::<
150 BigEndian,
151 T,
152 >(
153 g_header.g_type,
154 g_header.srid,
155 &mut cursor,
156 )?)
157 }
158 }
159 } else {
160 let g_header = read_ewkb_header::<LittleEndian>(&mut cursor)?;
161 match GeometryType::from(g_header.g_type) {
162 GeometryType::Point => {
163 GeometryContainer::Point(read_point_coordinates::<LittleEndian, T>(
164 &mut cursor,
165 g_header.g_type,
166 g_header.srid,
167 )?)
168 }
169 GeometryType::MultiPoint => {
170 GeometryContainer::MultiPoint(read_multi_point_body::<LittleEndian, T>(
171 g_header.g_type,
172 g_header.srid,
173 &mut cursor,
174 )?)
175 }
176 GeometryType::LineString => {
177 GeometryContainer::LineString(read_linestring_body::<LittleEndian, T>(
178 g_header.g_type,
179 g_header.srid,
180 &mut cursor,
181 )?)
182 }
183 GeometryType::MultiLineString => {
184 GeometryContainer::MultiLineString(read_multiline_body::<LittleEndian, T>(
185 g_header.g_type,
186 g_header.srid,
187 &mut cursor,
188 )?)
189 }
190 GeometryType::Polygon => {
191 GeometryContainer::Polygon(read_polygon_body::<LittleEndian, T>(
192 g_header.g_type,
193 g_header.srid,
194 &mut cursor,
195 )?)
196 }
197 GeometryType::MultiPolygon => {
198 GeometryContainer::MultiPolygon(read_multi_polygon_body::<LittleEndian, T>(
199 g_header.g_type,
200 g_header.srid,
201 &mut cursor,
202 )?)
203 }
204 GeometryType::GeometryCollection => {
205 GeometryContainer::GeometryCollection(read_geometry_collection_body::<
206 LittleEndian,
207 T,
208 >(
209 g_header.g_type,
210 g_header.srid,
211 &mut cursor,
212 )?)
213 }
214 }
215 };
216 Ok(container)
217 }
218}
219
220#[cfg(feature = "diesel")]
221impl<T> diesel::deserialize::FromSql<Geography, diesel::pg::Pg> for GeometryContainer<T>
222where
223 T: PointT + Debug + Clone + diesel::deserialize::FromSql<Geometry, diesel::pg::Pg>,
224{
225 fn from_sql(bytes: diesel::pg::PgValue) -> diesel::deserialize::Result<Self> {
226 diesel::deserialize::FromSql::<Geometry, diesel::pg::Pg>::from_sql(bytes)
227 }
228}