sqlx_xugu/types/geometry/
line.rs

1use crate::arguments::XuguArgumentValue;
2use crate::protocol::text::ColumnType;
3use crate::{Xugu, XuguTypeInfo, XuguValueRef};
4use bytes::Buf;
5use sqlx_core::decode::Decode;
6use sqlx_core::encode::{Encode, IsNull};
7use sqlx_core::error::BoxDynError;
8use sqlx_core::types::Type;
9use sqlx_core::Error;
10use std::borrow::Cow;
11use std::fmt::{Display, Formatter};
12use std::str::FromStr;
13
14const ERROR: &str = "[E50044]error decoding LINE";
15
16/// ## Xugu Geometric Line type
17///
18/// Description: Infinite line
19/// Representation: `{A, B, C}`
20///
21/// Lines are represented by the linear equation Ax + By + C = 0, where A and B are not both zero.
22///
23#[derive(Debug, Clone, PartialEq)]
24pub struct XgLine {
25    pub a: f64,
26    pub b: f64,
27    pub c: f64,
28}
29
30impl Type<Xugu> for XgLine {
31    fn type_info() -> XuguTypeInfo {
32        XuguTypeInfo::binary(ColumnType::LINE)
33    }
34
35    fn compatible(ty: &XuguTypeInfo) -> bool {
36        matches!(
37            ty.r#type,
38            ColumnType::CHAR | ColumnType::LINE | ColumnType::LINE_OLD
39        )
40    }
41}
42
43impl<'r> Decode<'r, Xugu> for XgLine {
44    fn decode(value: XuguValueRef<'r>) -> Result<Self, BoxDynError> {
45        let s = value.as_str()?;
46        Ok(Self::from_str(s)?)
47    }
48}
49
50impl Encode<'_, Xugu> for XgLine {
51    fn encode_by_ref(&self, args: &mut Vec<XuguArgumentValue>) -> Result<IsNull, BoxDynError> {
52        let s = self.to_string();
53
54        args.push(XuguArgumentValue::Str(Cow::Owned(s)));
55
56        Ok(IsNull::No)
57    }
58
59    fn produces(&self) -> Option<XuguTypeInfo> {
60        Some(XuguTypeInfo::binary(ColumnType::CHAR))
61    }
62}
63
64impl Display for XgLine {
65    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
66        write!(f, "{{{},{},{}}}", self.a, self.b, self.c)
67    }
68}
69
70impl FromStr for XgLine {
71    type Err = BoxDynError;
72
73    fn from_str(s: &str) -> Result<Self, Self::Err> {
74        let mut parts = s
75            .trim_matches(|c| c == '{' || c == '}' || c == ' ')
76            .split(',');
77
78        let a = parts
79            .next()
80            .and_then(|s| s.trim().parse::<f64>().ok())
81            .ok_or_else(|| format!("{}: could not get a from {}", ERROR, s))?;
82
83        let b = parts
84            .next()
85            .and_then(|s| s.trim().parse::<f64>().ok())
86            .ok_or_else(|| format!("{}: could not get b from {}", ERROR, s))?;
87
88        let c = parts
89            .next()
90            .and_then(|s| s.trim().parse::<f64>().ok())
91            .ok_or_else(|| format!("{}: could not get c from {}", ERROR, s))?;
92
93        if parts.next().is_some() {
94            return Err(format!("{}: too many numbers inputted in {}", ERROR, s).into());
95        }
96
97        Ok(Self { a, b, c })
98    }
99}
100
101impl XgLine {
102    pub fn from_bytes(mut bytes: &[u8]) -> Result<Self, Error> {
103        let a = bytes.get_f64();
104        let b = bytes.get_f64();
105        let c = bytes.get_f64();
106        Ok(Self { a, b, c })
107    }
108}