postgres_types_extra/
pg_path.rs1use bytes::{Buf, BufMut};
2use postgres_types::{FromSql, IsNull, ToSql, Type, accepts, to_sql_checked};
3use std::{error::Error, fmt};
4
5use super::pg_point::PgPoint;
6
7#[derive(Debug, Clone, PartialEq)]
8pub struct PgPath {
9 pub points: Vec<PgPoint>,
10 pub is_closed: bool,
11}
12
13impl fmt::Display for PgPath {
14 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
15 let path_type = if self.is_closed { "(" } else { "[" };
16 write!(
17 f,
18 "{}{}{})",
19 path_type,
20 self.points
21 .iter()
22 .map(|p| p.to_string())
23 .collect::<Vec<_>>()
24 .join(","),
25 if self.is_closed { ")" } else { "]" }
26 )
27 }
28}
29
30impl FromSql<'_> for PgPath {
31 fn from_sql(ty: &Type, mut raw: &[u8]) -> Result<Self, Box<dyn Error + Sync + Send>> {
32 if ty.name() != "path" {
33 return Err("Unexpected type".into());
34 }
35 let is_closed = raw.get_u8() != 0;
36 let npoints = raw.get_i32();
37 let mut points = Vec::with_capacity(npoints as usize);
38 for _ in 0..npoints {
39 let x = raw.get_f64();
40 let y = raw.get_f64();
41 points.push(PgPoint { x, y });
42 }
43 Ok(PgPath { points, is_closed })
44 }
45
46 accepts!(PATH);
47}
48
49impl ToSql for PgPath {
50 fn to_sql(
51 &self,
52 ty: &Type,
53 out: &mut bytes::BytesMut,
54 ) -> Result<postgres_types::IsNull, Box<dyn Error + Sync + Send>>
55 where
56 Self: Sized,
57 {
58 if ty.name() != "path" {
59 return Err("Unexpected type".into());
60 }
61
62 out.put_u8(if self.is_closed { 1 } else { 0 });
64
65 let npoints: i32 = self.points.len().try_into()?;
67 out.put_i32(npoints);
68
69 for pt in &self.points {
71 out.put_f64(pt.x);
72 out.put_f64(pt.y);
73 }
74
75 Ok(IsNull::No)
76 }
77
78 accepts!(PATH);
79
80 to_sql_checked!();
81}