use crate::FeagiDataError;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::fmt::{Display, Formatter};
use std::str::FromStr;
use uuid::Uuid;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct RegionID {
uuid: Uuid,
}
impl RegionID {
pub fn new() -> Self {
Self {
uuid: Uuid::now_v7(),
}
}
pub fn from_uuid(uuid: Uuid) -> Self {
Self { uuid }
}
pub fn from_string(s: &str) -> Result<Self, FeagiDataError> {
Uuid::parse_str(s)
.map(RegionID::from_uuid)
.map_err(|e| FeagiDataError::BadParameters(format!("Invalid RegionID string: {}", e)))
}
pub fn as_uuid(&self) -> Uuid {
self.uuid
}
pub fn as_bytes(&self) -> &[u8; 16] {
self.uuid.as_bytes()
}
}
impl Default for RegionID {
fn default() -> Self {
Self::new()
}
}
impl Display for RegionID {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.uuid)
}
}
impl FromStr for RegionID {
type Err = FeagiDataError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Uuid::parse_str(s)
.map(RegionID::from_uuid)
.map_err(|e| FeagiDataError::BadParameters(format!("Invalid RegionID string: {}", e)))
}
}
impl From<Uuid> for RegionID {
fn from(uuid: Uuid) -> Self {
RegionID::from_uuid(uuid)
}
}
impl From<RegionID> for Uuid {
fn from(region_id: RegionID) -> Self {
region_id.uuid
}
}
impl Serialize for RegionID {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&self.uuid.to_string())
}
}
impl<'de> Deserialize<'de> for RegionID {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
RegionID::from_string(&s).map_err(serde::de::Error::custom)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_region_id_new() {
let id1 = RegionID::new();
let id2 = RegionID::new();
assert_ne!(id1, id2);
}
#[test]
fn test_region_id_from_uuid() {
let uuid = Uuid::now_v7();
let region_id = RegionID::from_uuid(uuid);
assert_eq!(region_id.as_uuid(), uuid);
}
#[test]
fn test_region_id_from_string() {
let uuid_str = "550e8400-e29b-41d4-a716-446655440000";
let region_id = RegionID::from_string(uuid_str).unwrap();
assert_eq!(region_id.to_string(), uuid_str);
}
#[test]
fn test_region_id_from_string_invalid() {
let result = RegionID::from_string("not-a-uuid");
assert!(result.is_err());
}
#[test]
fn test_region_id_display() {
let region_id = RegionID::new();
let display_str = region_id.to_string();
assert_eq!(display_str.len(), 36);
assert!(display_str.contains('-'));
}
#[test]
fn test_region_id_from_str() {
let uuid_str = "550e8400-e29b-41d4-a716-446655440000";
let region_id: RegionID = uuid_str.parse().unwrap();
assert_eq!(region_id.to_string(), uuid_str);
}
#[test]
fn test_region_id_serialization() {
let region_id = RegionID::new();
let json = serde_json::to_string(®ion_id).unwrap();
assert!(json.starts_with('"'));
assert!(json.ends_with('"'));
assert_eq!(json.len(), 38); }
#[test]
fn test_region_id_deserialization() {
let uuid_str = "550e8400-e29b-41d4-a716-446655440000";
let json = format!("\"{}\"", uuid_str);
let region_id: RegionID = serde_json::from_str(&json).unwrap();
assert_eq!(region_id.to_string(), uuid_str);
}
#[test]
fn test_region_id_roundtrip() {
let original = RegionID::new();
let json = serde_json::to_string(&original).unwrap();
let deserialized: RegionID = serde_json::from_str(&json).unwrap();
assert_eq!(original, deserialized);
}
#[test]
fn test_region_id_as_bytes() {
let region_id = RegionID::new();
let bytes = region_id.as_bytes();
assert_eq!(bytes.len(), 16);
}
#[test]
fn test_region_id_default() {
let id1 = RegionID::default();
let id2 = RegionID::default();
assert_ne!(id1, id2);
}
#[test]
fn test_region_id_equality() {
let uuid = Uuid::now_v7();
let id1 = RegionID::from_uuid(uuid);
let id2 = RegionID::from_uuid(uuid);
assert_eq!(id1, id2);
}
#[test]
fn test_region_id_hash() {
use std::collections::HashSet;
let id1 = RegionID::new();
let id2 = RegionID::new();
let mut set = HashSet::new();
set.insert(id1);
set.insert(id2);
assert_eq!(set.len(), 2);
assert!(set.contains(&id1));
assert!(set.contains(&id2));
}
}