postgis_butmaintained/
twkb.rs

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