use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::fmt;
use std::hash::Hash;
use std::marker::PhantomData;
use std::str::FromStr;
use uuid::Uuid;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum IdParseError {
InvalidPrefix { expected: &'static str, got: String },
InvalidHex(String),
InvalidLength { expected: usize, got: usize },
}
impl std::fmt::Display for IdParseError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
IdParseError::InvalidPrefix { expected, got } => {
write!(f, "invalid prefix: expected '{}', got '{}'", expected, got)
}
IdParseError::InvalidHex(s) => write!(f, "invalid hex in ID: {}", s),
IdParseError::InvalidLength { expected, got } => {
write!(f, "invalid length: expected {}, got {}", expected, got)
}
}
}
}
impl std::error::Error for IdParseError {}
pub trait IdMarker: Clone + Copy + Send + Sync + 'static {
const PREFIX: &'static str;
fn generate_uuid() -> Uuid {
Uuid::now_v7()
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct TypedId<T: IdMarker> {
uuid: Uuid,
_marker: PhantomData<T>,
}
impl<T: IdMarker> TypedId<T> {
pub fn new() -> Self {
Self {
uuid: T::generate_uuid(),
_marker: PhantomData,
}
}
pub fn new_random() -> Self {
Self {
uuid: Uuid::new_v4(),
_marker: PhantomData,
}
}
pub fn from_uuid(uuid: Uuid) -> Self {
Self {
uuid,
_marker: PhantomData,
}
}
pub fn uuid(&self) -> Uuid {
self.uuid
}
pub fn prefix() -> &'static str {
T::PREFIX
}
pub fn parse(s: &str) -> Result<Self, IdParseError> {
let expected_prefix = format!("{}_", T::PREFIX);
if !s.starts_with(&expected_prefix) {
let got_prefix = s.split('_').next().unwrap_or("").to_string();
return Err(IdParseError::InvalidPrefix {
expected: T::PREFIX,
got: got_prefix,
});
}
let suffix = &s[expected_prefix.len()..];
if suffix.len() != 32 {
return Err(IdParseError::InvalidLength {
expected: 32,
got: suffix.len(),
});
}
if !suffix
.chars()
.all(|c| c.is_ascii_hexdigit() && !c.is_ascii_uppercase())
{
return Err(IdParseError::InvalidHex(suffix.to_string()));
}
let uuid =
Uuid::parse_str(suffix).map_err(|_| IdParseError::InvalidHex(suffix.to_string()))?;
Ok(Self {
uuid,
_marker: PhantomData,
})
}
pub fn from_seed(value: u128) -> Self {
let uuid = Uuid::from_u128(value);
Self {
uuid,
_marker: PhantomData,
}
}
}
impl<T: IdMarker> Default for TypedId<T> {
fn default() -> Self {
Self::new()
}
}
impl<T: IdMarker> From<TypedId<T>> for Uuid {
fn from(id: TypedId<T>) -> Self {
id.uuid
}
}
impl<T: IdMarker> From<Uuid> for TypedId<T> {
fn from(uuid: Uuid) -> Self {
Self::from_uuid(uuid)
}
}
impl<T: IdMarker> std::borrow::Borrow<Uuid> for TypedId<T> {
fn borrow(&self) -> &Uuid {
&self.uuid
}
}
impl<T: IdMarker> AsRef<Uuid> for TypedId<T> {
fn as_ref(&self) -> &Uuid {
&self.uuid
}
}
impl<T: IdMarker> PartialEq<Uuid> for TypedId<T> {
fn eq(&self, other: &Uuid) -> bool {
self.uuid == *other
}
}
impl<T: IdMarker> PartialEq<TypedId<T>> for Uuid {
fn eq(&self, other: &TypedId<T>) -> bool {
*self == other.uuid
}
}
impl<T: IdMarker> fmt::Display for TypedId<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}_{}", T::PREFIX, self.uuid.simple())
}
}
impl<T: IdMarker> fmt::Debug for TypedId<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}({})",
std::any::type_name::<T>()
.split("::")
.last()
.unwrap_or("Id"),
self
)
}
}
impl<T: IdMarker> FromStr for TypedId<T> {
type Err = IdParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::parse(s)
}
}
impl<T: IdMarker> Serialize for TypedId<T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&self.to_string())
}
}
impl<'de, T: IdMarker> Deserialize<'de> for TypedId<T> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
Self::parse(&s).map_err(serde::de::Error::custom)
}
}
#[cfg(feature = "openapi")]
impl<T: IdMarker> utoipa::ToSchema for TypedId<T> {
fn name() -> std::borrow::Cow<'static, str> {
std::borrow::Cow::Owned(format!("{}Id", T::PREFIX))
}
}
#[cfg(feature = "openapi")]
impl<T: IdMarker> utoipa::PartialSchema for TypedId<T> {
#[allow(deprecated)]
fn schema() -> utoipa::openapi::RefOr<utoipa::openapi::schema::Schema> {
let example_value = format!("{}_{}", T::PREFIX, "01933b5a00007000800000000000001");
utoipa::openapi::ObjectBuilder::new()
.schema_type(utoipa::openapi::schema::Type::String)
.description(Some(format!(
"Prefixed identifier with '{}' prefix",
T::PREFIX
)))
.example(Some(serde_json::json!(example_value)))
.pattern(Some(format!("^{}_[0-9a-f]{{32}}$", T::PREFIX)))
.into()
}
}
#[cfg(feature = "sqlx")]
impl<T: IdMarker> sqlx::Type<sqlx::Postgres> for TypedId<T> {
fn type_info() -> sqlx::postgres::PgTypeInfo {
<Uuid as sqlx::Type<sqlx::Postgres>>::type_info()
}
fn compatible(ty: &sqlx::postgres::PgTypeInfo) -> bool {
<Uuid as sqlx::Type<sqlx::Postgres>>::compatible(ty)
}
}
#[cfg(feature = "sqlx")]
impl<T: IdMarker> sqlx::Encode<'_, sqlx::Postgres> for TypedId<T> {
fn encode_by_ref(
&self,
buf: &mut sqlx::postgres::PgArgumentBuffer,
) -> Result<sqlx::encode::IsNull, Box<dyn std::error::Error + Send + Sync>> {
<Uuid as sqlx::Encode<sqlx::Postgres>>::encode_by_ref(&self.uuid, buf)
}
}
#[cfg(feature = "sqlx")]
impl<T: IdMarker> sqlx::Decode<'_, sqlx::Postgres> for TypedId<T> {
fn decode(
value: sqlx::postgres::PgValueRef<'_>,
) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
let uuid = <Uuid as sqlx::Decode<sqlx::Postgres>>::decode(value)?;
Ok(Self::from_uuid(uuid))
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct OrgIdMarker;
impl IdMarker for OrgIdMarker {
const PREFIX: &'static str = "org";
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct AgentIdMarker;
impl IdMarker for AgentIdMarker {
const PREFIX: &'static str = "agent";
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct AgentVersionIdMarker;
impl IdMarker for AgentVersionIdMarker {
const PREFIX: &'static str = "agentver";
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct HarnessIdMarker;
impl IdMarker for HarnessIdMarker {
const PREFIX: &'static str = "harness";
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct AgentIdentityIdMarker;
impl IdMarker for AgentIdentityIdMarker {
const PREFIX: &'static str = "identity";
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct TriggerIdMarker;
impl IdMarker for TriggerIdMarker {
const PREFIX: &'static str = "trg";
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct PrincipalIdMarker;
impl IdMarker for PrincipalIdMarker {
const PREFIX: &'static str = "principal";
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct SessionIdMarker;
impl IdMarker for SessionIdMarker {
const PREFIX: &'static str = "session";
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct SessionParticipantIdMarker;
impl IdMarker for SessionParticipantIdMarker {
const PREFIX: &'static str = "part";
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct MessageIdMarker;
impl IdMarker for MessageIdMarker {
const PREFIX: &'static str = "message";
fn generate_uuid() -> Uuid {
Uuid::new_v4()
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct EventIdMarker;
impl IdMarker for EventIdMarker {
const PREFIX: &'static str = "event";
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct ProviderIdMarker;
impl IdMarker for ProviderIdMarker {
const PREFIX: &'static str = "provider";
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct ModelIdMarker;
impl IdMarker for ModelIdMarker {
const PREFIX: &'static str = "model";
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct ImageIdMarker;
impl IdMarker for ImageIdMarker {
const PREFIX: &'static str = "img";
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct McpServerIdMarker;
impl IdMarker for McpServerIdMarker {
const PREFIX: &'static str = "mcp";
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct SkillIdMarker;
impl IdMarker for SkillIdMarker {
const PREFIX: &'static str = "skill";
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct DeclarativeCapabilityIdMarker;
impl IdMarker for DeclarativeCapabilityIdMarker {
const PREFIX: &'static str = "cap";
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct TurnIdMarker;
impl IdMarker for TurnIdMarker {
const PREFIX: &'static str = "turn";
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct ExecIdMarker;
impl IdMarker for ExecIdMarker {
const PREFIX: &'static str = "exec";
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct ScheduleIdMarker;
impl IdMarker for ScheduleIdMarker {
const PREFIX: &'static str = "sched";
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct LeasedResourceIdMarker;
impl IdMarker for LeasedResourceIdMarker {
const PREFIX: &'static str = "resource";
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct AppIdMarker;
impl IdMarker for AppIdMarker {
const PREFIX: &'static str = "app";
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct AppChannelIdMarker;
impl IdMarker for AppChannelIdMarker {
const PREFIX: &'static str = "appchan";
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct NotificationIdMarker;
impl IdMarker for NotificationIdMarker {
const PREFIX: &'static str = "notification";
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct MemoryIdMarker;
impl IdMarker for MemoryIdMarker {
const PREFIX: &'static str = "mem";
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct WorkspaceIdMarker;
impl IdMarker for WorkspaceIdMarker {
const PREFIX: &'static str = "wsp";
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct EvalIdMarker;
impl IdMarker for EvalIdMarker {
const PREFIX: &'static str = "eval";
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct EvalCaseIdMarker;
impl IdMarker for EvalCaseIdMarker {
const PREFIX: &'static str = "evalcase";
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct EvalRunIdMarker;
impl IdMarker for EvalRunIdMarker {
const PREFIX: &'static str = "evalrun";
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct EvalDatasetIdMarker;
impl IdMarker for EvalDatasetIdMarker {
const PREFIX: &'static str = "evaldataset";
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct HealthCheckRunIdMarker;
impl IdMarker for HealthCheckRunIdMarker {
const PREFIX: &'static str = "healthcheck";
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct EvalResultIdMarker;
impl IdMarker for EvalResultIdMarker {
const PREFIX: &'static str = "evalresult";
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct ObserverIdMarker;
impl IdMarker for ObserverIdMarker {
const PREFIX: &'static str = "observer";
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct TraceScoreIdMarker;
impl IdMarker for TraceScoreIdMarker {
const PREFIX: &'static str = "score";
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct BudgetIdMarker;
impl IdMarker for BudgetIdMarker {
const PREFIX: &'static str = "bdgt";
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct PaymentAccountIdMarker;
impl IdMarker for PaymentAccountIdMarker {
const PREFIX: &'static str = "payacct";
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct PaymentPolicyIdMarker;
impl IdMarker for PaymentPolicyIdMarker {
const PREFIX: &'static str = "paypol";
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct PaymentAttemptIdMarker;
impl IdMarker for PaymentAttemptIdMarker {
const PREFIX: &'static str = "payatt";
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct LedgerEntryIdMarker;
impl IdMarker for LedgerEntryIdMarker {
const PREFIX: &'static str = "ledger";
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct KnowledgeBaseIdMarker;
impl IdMarker for KnowledgeBaseIdMarker {
const PREFIX: &'static str = "kb";
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct KnowledgeEntryIdMarker;
impl IdMarker for KnowledgeEntryIdMarker {
const PREFIX: &'static str = "kbe";
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct KnowledgeIndexIdMarker;
impl IdMarker for KnowledgeIndexIdMarker {
const PREFIX: &'static str = "kidx";
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct KnowledgeIndexDocumentIdMarker;
impl IdMarker for KnowledgeIndexDocumentIdMarker {
const PREFIX: &'static str = "kidoc";
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct KnowledgeIndexChunkIdMarker;
impl IdMarker for KnowledgeIndexChunkIdMarker {
const PREFIX: &'static str = "kchk";
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct ModelRouterIdMarker;
impl IdMarker for ModelRouterIdMarker {
const PREFIX: &'static str = "mrtr";
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct PluginMarketplaceIdMarker;
impl IdMarker for PluginMarketplaceIdMarker {
const PREFIX: &'static str = "plgmkt";
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct PluginInstallIdMarker;
impl IdMarker for PluginInstallIdMarker {
const PREFIX: &'static str = "plugin";
}
pub type OrgId = TypedId<OrgIdMarker>;
pub type AgentId = TypedId<AgentIdMarker>;
pub type AgentVersionId = TypedId<AgentVersionIdMarker>;
pub type HarnessId = TypedId<HarnessIdMarker>;
pub type AgentIdentityId = TypedId<AgentIdentityIdMarker>;
pub type TriggerId = TypedId<TriggerIdMarker>;
pub type PrincipalId = TypedId<PrincipalIdMarker>;
pub type SessionId = TypedId<SessionIdMarker>;
pub type SessionParticipantId = TypedId<SessionParticipantIdMarker>;
pub type MessageId = TypedId<MessageIdMarker>;
pub type EventId = TypedId<EventIdMarker>;
pub type ProviderId = TypedId<ProviderIdMarker>;
pub type ModelId = TypedId<ModelIdMarker>;
pub type ImageId = TypedId<ImageIdMarker>;
pub type McpServerId = TypedId<McpServerIdMarker>;
pub type SkillId = TypedId<SkillIdMarker>;
pub type DeclarativeCapabilityId = TypedId<DeclarativeCapabilityIdMarker>;
pub type TurnId = TypedId<TurnIdMarker>;
pub type ExecId = TypedId<ExecIdMarker>;
pub type ScheduleId = TypedId<ScheduleIdMarker>;
pub type LeasedResourceId = TypedId<LeasedResourceIdMarker>;
pub type AppId = TypedId<AppIdMarker>;
pub type AppChannelId = TypedId<AppChannelIdMarker>;
pub type NotificationId = TypedId<NotificationIdMarker>;
pub type MemoryId = TypedId<MemoryIdMarker>;
pub type WorkspaceId = TypedId<WorkspaceIdMarker>;
pub type EvalId = TypedId<EvalIdMarker>;
pub type EvalCaseId = TypedId<EvalCaseIdMarker>;
pub type EvalRunId = TypedId<EvalRunIdMarker>;
pub type EvalDatasetId = TypedId<EvalDatasetIdMarker>;
pub type HealthCheckRunId = TypedId<HealthCheckRunIdMarker>;
pub type EvalResultId = TypedId<EvalResultIdMarker>;
pub type ObserverId = TypedId<ObserverIdMarker>;
pub type TraceScoreId = TypedId<TraceScoreIdMarker>;
pub type BudgetId = TypedId<BudgetIdMarker>;
pub type PaymentAccountId = TypedId<PaymentAccountIdMarker>;
pub type PaymentPolicyId = TypedId<PaymentPolicyIdMarker>;
pub type PaymentAttemptId = TypedId<PaymentAttemptIdMarker>;
pub type LedgerEntryId = TypedId<LedgerEntryIdMarker>;
pub type KnowledgeBaseId = TypedId<KnowledgeBaseIdMarker>;
pub type KnowledgeEntryId = TypedId<KnowledgeEntryIdMarker>;
pub type KnowledgeIndexId = TypedId<KnowledgeIndexIdMarker>;
pub type KnowledgeIndexDocumentId = TypedId<KnowledgeIndexDocumentIdMarker>;
pub type KnowledgeIndexChunkId = TypedId<KnowledgeIndexChunkIdMarker>;
pub type ModelRouterId = TypedId<ModelRouterIdMarker>;
pub type PluginMarketplaceId = TypedId<PluginMarketplaceIdMarker>;
pub type PluginInstallId = TypedId<PluginInstallIdMarker>;
pub const DEFAULT_ORG_ID: OrgId = TypedId {
uuid: Uuid::from_u128(1),
_marker: PhantomData,
};
pub mod well_known {
use super::*;
pub const OPENAI_PROVIDER_ID: ProviderId = TypedId {
uuid: Uuid::from_u128(0x01933b5a_0000_7000_8000_000000000001),
_marker: PhantomData,
};
pub const ANTHROPIC_PROVIDER_ID: ProviderId = TypedId {
uuid: Uuid::from_u128(0x01933b5a_0000_7000_8000_000000000002),
_marker: PhantomData,
};
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new_agent_id() {
let id = AgentId::new();
let s = id.to_string();
assert!(s.starts_with("agent_"));
assert_eq!(s.len(), 38); }
#[test]
fn test_parse_agent_id() {
let id = AgentId::new();
let s = id.to_string();
let parsed = AgentId::parse(&s).unwrap();
assert_eq!(id, parsed);
}
#[test]
fn test_parse_invalid_prefix() {
let result = AgentId::parse("session_01933b5a00007000800000000000001");
assert!(matches!(result, Err(IdParseError::InvalidPrefix { .. })));
}
#[test]
fn test_parse_invalid_length() {
let result = AgentId::parse("agent_123");
assert!(matches!(result, Err(IdParseError::InvalidLength { .. })));
}
#[test]
fn test_parse_invalid_hex() {
let result = AgentId::parse("agent_GHIJKLMNOPQRSTUVWXYZ123456789012");
assert!(matches!(result, Err(IdParseError::InvalidHex(_))));
}
#[test]
fn test_from_seed() {
let id = AgentId::from_seed(1);
assert_eq!(id.to_string(), "agent_00000000000000000000000000000001");
}
#[test]
fn test_serde_roundtrip() {
let id = AgentId::new();
let json = serde_json::to_string(&id).unwrap();
let parsed: AgentId = serde_json::from_str(&json).unwrap();
assert_eq!(id, parsed);
}
#[test]
fn test_default_org_id() {
assert_eq!(
DEFAULT_ORG_ID.to_string(),
"org_00000000000000000000000000000001"
);
}
#[test]
fn test_well_known_provider_ids() {
assert_eq!(
well_known::OPENAI_PROVIDER_ID.to_string(),
"provider_01933b5a000070008000000000000001"
);
assert_eq!(
well_known::ANTHROPIC_PROVIDER_ID.to_string(),
"provider_01933b5a000070008000000000000002"
);
}
#[test]
fn test_from_uuid() {
let uuid = Uuid::now_v7();
let id = AgentId::from_uuid(uuid);
assert_eq!(id.uuid(), uuid);
}
#[test]
fn test_hash() {
use std::collections::HashSet;
let id1 = AgentId::new();
let id2 = AgentId::new();
let mut set = HashSet::new();
set.insert(id1);
set.insert(id2);
assert_eq!(set.len(), 2);
set.insert(id1);
assert_eq!(set.len(), 2); }
#[test]
fn test_message_id_is_random_v4() {
let id = MessageId::new();
assert_eq!(
id.uuid().get_version_num(),
4,
"MessageId::new() must be v4"
);
assert_eq!(
MessageId::new_random().uuid().get_version_num(),
4,
"MessageId::new_random() must be v4"
);
let s = id.to_string();
assert!(s.starts_with("message_"));
assert_eq!(s.len(), "message_".len() + 32);
assert_eq!(MessageId::parse(&s).unwrap(), id);
}
#[test]
fn test_default_id_class_stays_v7() {
assert_eq!(AgentId::new().uuid().get_version_num(), 7);
assert_eq!(SessionId::new().uuid().get_version_num(), 7);
assert_eq!(EventId::new().uuid().get_version_num(), 7);
assert_eq!(TurnId::new().uuid().get_version_num(), 7);
}
#[test]
fn test_message_id_parse_compat_legacy_and_random() {
let legacy_v7 = format!("message_{}", Uuid::now_v7().simple());
let new_v4 = format!("message_{}", Uuid::new_v4().simple());
for s in [legacy_v7, new_v4] {
let parsed = MessageId::parse(&s).expect("both id vintages must parse");
assert_eq!(parsed.to_string(), s);
}
}
}