senax-common 0.4.10

Senax common library
Documentation
use anyhow::ensure;
use bytes::{BufMut, BytesMut};
use schemars::JsonSchema;
use senax_encoder::{Decode, Encode, Pack, Unpack};
use serde::{Deserialize, Serialize};
use std::{convert::TryInto, fmt::Display, str::FromStr};

#[derive(
    Deserialize,
    Serialize,
    Encode,
    Decode,
    Pack,
    Unpack,
    Copy,
    Clone,
    Debug,
    Default,
    PartialEq,
    JsonSchema,
)]
#[cfg_attr(
    feature = "graphql6",
    derive(graphql6::SimpleObject, graphql6::InputObject)
)]
#[cfg_attr(feature = "graphql6", graphql(input_name = "PointInput"))]
#[cfg_attr(
    feature = "graphql7",
    derive(graphql7::SimpleObject, graphql7::InputObject)
)]
#[cfg_attr(feature = "graphql7", graphql(input_name = "PointInput"))]
#[cfg_attr(feature = "utoipa5", derive(utoipa5::ToSchema))]
#[cfg_attr(feature = "utoipa5", schema(as = PointInput))]
pub struct Point {
    pub x: f64,
    pub y: f64,
}

impl From<&(f64, f64)> for Point {
    fn from(v: &(f64, f64)) -> Self {
        Self { x: v.0, y: v.1 }
    }
}

impl Point {
    pub fn to_tuple(&self) -> (f64, f64) {
        (self.x, self.y)
    }
}
impl From<Vec<u8>> for Point {
    fn from(input: Vec<u8>) -> Self {
        Self::from(input.as_slice())
    }
}
impl From<&Vec<u8>> for Point {
    fn from(input: &Vec<u8>) -> Self {
        Self::from(input.as_slice())
    }
}
impl From<&[u8]> for Point {
    fn from(input: &[u8]) -> Self {
        if input.len() < 21 {
            return Point {
                x: f64::NAN,
                y: f64::NAN,
            };
        }
        let (bytes, input) = input.split_at(1);
        let endian = u8::from_le_bytes(bytes.try_into().unwrap());
        let (bytes, input) = input.split_at(4);
        let g_type = if endian == 1 {
            u32::from_le_bytes(bytes.try_into().unwrap())
        } else {
            u32::from_be_bytes(bytes.try_into().unwrap())
        };
        if g_type != 1 {
            return Point {
                x: f64::NAN,
                y: f64::NAN,
            };
        }
        let (bytes, input) = input.split_at(8);
        let x = if endian == 1 {
            f64::from_le_bytes(bytes.try_into().unwrap())
        } else {
            f64::from_be_bytes(bytes.try_into().unwrap())
        };
        let (bytes, _input) = input.split_at(8);
        let y = if endian == 1 {
            f64::from_le_bytes(bytes.try_into().unwrap())
        } else {
            f64::from_be_bytes(bytes.try_into().unwrap())
        };
        Point { x, y }
    }
}

impl From<Point> for Vec<u8> {
    fn from(point: Point) -> Self {
        let mut buf = BytesMut::with_capacity(21);
        buf.put_u8(1);
        buf.put_u32_le(1);
        buf.put_f64_le(point.x);
        buf.put_f64_le(point.y);
        buf.to_vec()
    }
}

impl Point {
    pub fn to_lng_lat_wkb(&self) -> Vec<u8> {
        let mut buf = BytesMut::with_capacity(21);
        buf.put_u8(1);
        buf.put_u32_le(1);
        buf.put_f64_le(self.x);
        buf.put_f64_le(self.y);
        buf.to_vec()
    }
}

impl FromStr for Point {
    type Err = anyhow::Error;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let coords: Vec<&str> = s
            .trim_matches(|p| p == '(' || p == ')')
            .split(',')
            .map(|v| v.trim())
            .collect();
        ensure!(coords.len() != 2, "illegal format");
        let x = coords[0].parse::<f64>()?;
        let y = coords[1].parse::<f64>()?;
        Ok(Point { x, y })
    }
}
impl Display for Point {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_fmt(format_args!("{},{}", self.x, self.y))
    }
}

pub trait ToPoint {
    fn to_point(&self) -> Point;
}

impl ToPoint for Vec<u8> {
    fn to_point(&self) -> Point {
        Point::from(self)
    }
}

impl ToPoint for (f64, f64) {
    fn to_point(&self) -> Point {
        Point::from(self)
    }
}