use serde::{Deserialize, Serialize};
use std::fmt;
use uuid::Uuid;
macro_rules! uuid_id {
($(#[$attr:meta])* $name:ident) => {
$(#[$attr])*
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
pub struct $name(pub Uuid);
impl $name {
pub fn new() -> Self {
Self(Uuid::new_v4())
}
pub fn from_uuid(uuid: Uuid) -> Self {
Self(uuid)
}
pub fn as_uuid(&self) -> &Uuid {
&self.0
}
}
impl Default for $name {
fn default() -> Self {
Self::new()
}
}
impl fmt::Display for $name {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
};
}
uuid_id!(
ProjectId
);
uuid_id!(
ConfigId
);
uuid_id!(
ExperimentId
);
uuid_id!(
SessionId
);
uuid_id!(
SignalId
);
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
pub struct AdapterId(String);
impl AdapterId {
pub fn new(name: impl Into<String>) -> Self {
Self(name.into())
}
pub fn as_str(&self) -> &str {
&self.0
}
}
impl fmt::Display for AdapterId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.0)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn project_id_roundtrips_through_json() {
let id = ProjectId::new();
let json = serde_json::to_string(&id).unwrap();
let back: ProjectId = serde_json::from_str(&json).unwrap();
assert_eq!(id, back);
}
#[test]
fn distinct_ids_are_not_equal() {
let a = ProjectId::new();
let b = ProjectId::new();
assert_ne!(a, b);
}
#[test]
fn from_uuid_then_as_uuid_roundtrips() {
let raw = Uuid::new_v4();
let id = SessionId::from_uuid(raw);
assert_eq!(id.as_uuid(), &raw);
}
#[test]
fn display_matches_inner_uuid() {
let raw = Uuid::new_v4();
let id = ConfigId::from_uuid(raw);
assert_eq!(format!("{id}"), format!("{raw}"));
}
#[test]
fn adapter_id_roundtrips() {
let id = AdapterId::new("claude-code");
let json = serde_json::to_string(&id).unwrap();
let back: AdapterId = serde_json::from_str(&json).unwrap();
assert_eq!(id, back);
assert_eq!(id.as_str(), "claude-code");
}
#[test]
fn adapter_id_display_matches_inner_string() {
let id = AdapterId::new("aider");
assert_eq!(format!("{id}"), "aider");
}
#[test]
fn distinct_id_types_are_not_interchangeable() {
let _project = ProjectId::new();
let _config = ConfigId::new();
}
}