postgres_types_extra/
pg_polygon.rs

1use 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 PgPolygon {
9    pub points: Vec<PgPoint>,
10}
11
12impl fmt::Display for PgPolygon {
13    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
14        write!(
15            f,
16            "({})",
17            self.points
18                .iter()
19                .map(|p| p.to_string())
20                .collect::<Vec<_>>()
21                .join(",")
22        )
23    }
24}
25
26impl FromSql<'_> for PgPolygon {
27    fn from_sql(ty: &Type, mut raw: &[u8]) -> Result<Self, Box<dyn Error + Sync + Send>> {
28        if ty.name() != "polygon" {
29            return Err("Unexpected type".into());
30        }
31        let npoints = raw.get_i32();
32        let mut points = Vec::with_capacity(npoints as usize);
33        for _ in 0..npoints {
34            let x = raw.get_f64();
35            let y = raw.get_f64();
36            points.push(PgPoint { x, y });
37        }
38        Ok(PgPolygon { points })
39    }
40
41    accepts!(POLYGON);
42}
43
44impl ToSql for PgPolygon {
45    fn to_sql(
46        &self,
47        ty: &Type,
48        out: &mut bytes::BytesMut,
49    ) -> Result<postgres_types::IsNull, Box<dyn Error + Sync + Send>>
50    where
51        Self: Sized,
52    {
53        if ty.name() != "polygon" {
54            return Err("Unexpected type".into());
55        }
56
57        let npoints: i32 = self.points.len().try_into()?;
58        out.put_i32(npoints);
59
60        for pt in &self.points {
61            out.put_f64(pt.x);
62            out.put_f64(pt.y);
63        }
64
65        Ok(IsNull::No)
66    }
67
68    accepts!(POLYGON);
69
70    to_sql_checked!();
71}