use std::sync::LazyLock;
use regex::Regex;
use thiserror::Error;
use crate::{
EMLError,
utils::{StringValue, StringValueData},
};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RDGeographicLocation {
pub x: StringValue<RDCoordinate>,
pub y: StringValue<RDCoordinate>,
}
impl RDGeographicLocation {
pub fn new(x: impl Into<RDCoordinate>, y: impl Into<RDCoordinate>) -> Self {
Self {
x: StringValue::from_value(x.into()),
y: StringValue::from_value(y.into()),
}
}
pub fn coordinates(&self) -> Result<(RDCoordinate, RDCoordinate), EMLError> {
let x = self.x.cloned_value()?;
let y = self.y.cloned_value()?;
Ok((x, y))
}
}
static RD_COORDINATE_RE: LazyLock<Regex> = LazyLock::new(|| {
Regex::new(r"^\d{1,6}(\.\d{1,})?$").expect("Failed to compile RD coordinate regex")
});
#[derive(Debug, Clone, PartialEq, Eq, Error)]
#[error("Invalid RD coordinate syntax: {0}")]
pub struct InvalidRDCoordinate(String);
impl From<InvalidRDCoordinate> for EMLError {
fn from(err: InvalidRDCoordinate) -> Self {
EMLError::value_conversion(err)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RDCoordinate(String);
impl RDCoordinate {
pub fn new(s: &str) -> Result<Self, InvalidRDCoordinate> {
Self::parse_from_str(s)
}
pub fn value(&self) -> &str {
&self.0
}
}
impl StringValueData for RDCoordinate {
type Error = InvalidRDCoordinate;
fn parse_from_str(s: &str) -> Result<Self, Self::Error> {
if !s.is_empty() && RD_COORDINATE_RE.is_match(s) {
Ok(Self(s.into()))
} else {
Err(InvalidRDCoordinate(s.into()))
}
}
fn to_raw_value(&self) -> Box<str> {
self.0.clone().into_boxed_str()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_rd_coordinate_regex_compiles() {
LazyLock::force(&RD_COORDINATE_RE);
}
}