libhaystack 3.1.5

Rust implementation of the Haystack 4 data types, defs, filter, units, and encodings
Documentation
// Copyright (C) 2020 - 2022, J2 Innovations

//! Haystack Coord

use crate::haystack::val::Value;
use std::{
    cmp::Ordering,
    convert::{From, TryFrom},
    hash::Hash,
};

/// Coordinate latitude and longitude
///
/// # Example
/// Create a coord value
/// ```
/// use libhaystack::val::*;
///
/// let coord = Value::from(Coord {
///             lat: 45.0,
///             long: 23.0,
/// });
/// assert!(coord.is_coord());
/// // Get the Coord value
/// assert_eq!(Coord::try_from(&coord).unwrap().lat, 45.0);
///```
///
#[derive(Copy, Clone, Debug, Default)]
pub struct Coord {
    pub lat: f64,
    pub long: f64,
}
impl Coord {
    pub fn make(lat: f64, long: f64) -> Coord {
        Coord { lat, long }
    }
}

/// Converts from `Coord` to a `Coord` `Value`
impl From<Coord> for Value {
    fn from(value: Coord) -> Self {
        Value::Coord(value)
    }
}

/// Tries to convert from `Value` to a `Coord`
impl TryFrom<&Value> for Coord {
    type Error = &'static str;
    fn try_from(value: &Value) -> Result<Self, Self::Error> {
        match value {
            Value::Coord(v) => Ok(*v),
            _ => Err("Value is not an `Coord`"),
        }
    }
}

impl Hash for Coord {
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        self.lat.to_bits().hash(state);
        self.long.to_bits().hash(state);
    }
}

impl PartialEq for Coord {
    fn eq(&self, other: &Self) -> bool {
        self.lat.eq(&other.lat) && self.long.eq(&other.long)
    }
}

impl Eq for Coord {}

#[allow(clippy::non_canonical_partial_ord_impl)]
impl PartialOrd for Coord {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        self.lat.partial_cmp(&other.lat).and_then(|ord| {
            if ord == Ordering::Equal {
                self.long.partial_cmp(&other.long)
            } else {
                Some(ord)
            }
        })
    }
}

impl Ord for Coord {
    fn cmp(&self, other: &Self) -> Ordering {
        // Order by latitude first, then longitude
        if self.lat < other.lat {
            Ordering::Less
        } else if self.lat > other.lat {
            Ordering::Greater
        } else if self.long < other.long {
            Ordering::Less
        } else if self.long > other.long {
            Ordering::Greater
        } else {
            Ordering::Equal
        }
    }
}