1use std::{fmt, str::FromStr};
2
3use serde::{Deserialize, Serialize};
4use uuid::Uuid;
5
6macro_rules! define_id {
7 ($name:ident, $docs:literal) => {
8 #[doc = $docs]
9 #[derive(
10 Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize,
11 )]
12 #[serde(transparent)]
13 pub struct $name(Uuid);
14
15 impl $name {
16 pub fn new() -> Self {
18 Self(Uuid::now_v7())
19 }
20
21 pub const fn from_uuid(value: Uuid) -> Self {
23 Self(value)
24 }
25
26 pub const fn as_uuid(self) -> Uuid {
28 self.0
29 }
30 }
31
32 impl FromStr for $name {
33 type Err = uuid::Error;
34
35 fn from_str(value: &str) -> Result<Self, Self::Err> {
36 Uuid::parse_str(value).map(Self)
37 }
38 }
39
40 impl From<Uuid> for $name {
41 fn from(value: Uuid) -> Self {
42 Self::from_uuid(value)
43 }
44 }
45
46 impl From<$name> for Uuid {
47 fn from(value: $name) -> Self {
48 value.as_uuid()
49 }
50 }
51
52 impl Default for $name {
53 fn default() -> Self {
54 Self::new()
55 }
56 }
57
58 impl fmt::Display for $name {
59 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
60 self.0.fmt(formatter)
61 }
62 }
63 };
64}
65
66define_id!(RunId, "A globally unique run identifier.");
67define_id!(EventId, "A globally unique event identifier.");
68define_id!(EffectId, "A globally unique effect identifier.");
69define_id!(CapabilityId, "A globally unique capability identifier.");
70define_id!(InvocationId, "A globally unique invocation identifier.");
71define_id!(CheckpointId, "A globally unique checkpoint identifier.");
72
73#[cfg(test)]
74mod tests {
75 use super::{CapabilityId, RunId};
76
77 #[test]
78 fn generated_ids_are_distinct_and_v7() {
79 let first = RunId::new();
80 let second = RunId::new();
81
82 assert_ne!(first, second);
83 assert_eq!(first.as_uuid().get_version_num(), 7);
84 }
85
86 #[test]
87 fn stable_ids_round_trip_through_configuration_strings() {
88 let configured = "018f6f7e-6f1d-7f2a-9c40-7f4f8f0a3d21";
89
90 let parsed: CapabilityId = configured.parse().expect("configured UUID is valid");
91
92 assert_eq!(parsed.to_string(), configured);
93 }
94}