Skip to main content

saddle_core/
context.rs

1use std::{fmt, sync::Arc};
2
3macro_rules! string_id {
4    ($name:ident) => {
5        #[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
6        pub struct $name(Arc<str>);
7
8        impl $name {
9            pub fn new(value: impl Into<Arc<str>>) -> Self {
10                Self(value.into())
11            }
12
13            pub fn as_str(&self) -> &str {
14                &self.0
15            }
16        }
17
18        impl From<&str> for $name {
19            fn from(value: &str) -> Self {
20                Self::new(value)
21            }
22        }
23
24        impl From<String> for $name {
25            fn from(value: String) -> Self {
26                Self::new(value)
27            }
28        }
29
30        impl fmt::Display for $name {
31            fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
32                formatter.write_str(&self.0)
33            }
34        }
35    };
36}
37
38string_id!(ApplicationId);
39string_id!(ModuleId);
40string_id!(ServiceId);
41string_id!(OperationId);
42
43#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
44pub struct TraceId(u128);
45
46impl TraceId {
47    pub const fn from_u128(value: u128) -> Self {
48        Self(value)
49    }
50
51    pub const fn as_u128(self) -> u128 {
52        self.0
53    }
54}
55
56impl fmt::Display for TraceId {
57    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
58        write!(formatter, "{:032x}", self.0)
59    }
60}
61
62#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
63pub struct SpanId(u64);
64
65impl SpanId {
66    pub const fn from_u64(value: u64) -> Self {
67        Self(value)
68    }
69
70    pub const fn as_u64(self) -> u64 {
71        self.0
72    }
73}
74
75impl fmt::Display for SpanId {
76    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
77        write!(formatter, "{:016x}", self.0)
78    }
79}
80
81/// The minimum identity propagated through Service, DB and Observability in V1.
82///
83/// Deadline, cancellation and resource-budget fields are deliberately absent
84/// until a version explicitly defines their behavior.
85#[derive(Clone, Debug, Eq, PartialEq)]
86pub struct CallContext {
87    application: ApplicationId,
88    module: ModuleId,
89    service: ServiceId,
90    operation: OperationId,
91    trace_id: TraceId,
92    span_id: SpanId,
93}
94
95impl CallContext {
96    pub fn new(
97        application: ApplicationId,
98        module: ModuleId,
99        service: ServiceId,
100        operation: OperationId,
101        trace_id: TraceId,
102        span_id: SpanId,
103    ) -> Self {
104        Self {
105            application,
106            module,
107            service,
108            operation,
109            trace_id,
110            span_id,
111        }
112    }
113
114    pub fn application(&self) -> &ApplicationId {
115        &self.application
116    }
117
118    pub fn module(&self) -> &ModuleId {
119        &self.module
120    }
121
122    pub fn service(&self) -> &ServiceId {
123        &self.service
124    }
125
126    pub fn operation(&self) -> &OperationId {
127        &self.operation
128    }
129
130    pub const fn trace_id(&self) -> TraceId {
131        self.trace_id
132    }
133
134    pub const fn span_id(&self) -> SpanId {
135        self.span_id
136    }
137}
138
139#[cfg(test)]
140mod tests {
141    use super::*;
142
143    #[test]
144    fn identifiers_have_stable_display_forms() {
145        assert_eq!(TraceId::from_u128(42).to_string().len(), 32);
146        assert_eq!(SpanId::from_u64(42).to_string().len(), 16);
147        assert_eq!(ServiceId::from("orders").to_string(), "orders");
148    }
149}