1use serde::{Deserialize, Serialize};
2
3use crate::error::{OtellError, Result};
4
5#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
6pub struct TraceId(String);
7
8#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
9pub struct SpanId(String);
10
11impl TraceId {
12 pub fn parse(input: &str) -> Result<Self> {
13 if input.len() != 32 || !input.chars().all(|c| c.is_ascii_hexdigit()) {
14 return Err(OtellError::Parse(format!("invalid trace id: {input}")));
15 }
16 Ok(Self(input.to_ascii_lowercase()))
17 }
18
19 pub fn as_str(&self) -> &str {
20 &self.0
21 }
22}
23
24impl SpanId {
25 pub fn parse(input: &str) -> Result<Self> {
26 if input.len() != 16 || !input.chars().all(|c| c.is_ascii_hexdigit()) {
27 return Err(OtellError::Parse(format!("invalid span id: {input}")));
28 }
29 Ok(Self(input.to_ascii_lowercase()))
30 }
31
32 pub fn as_str(&self) -> &str {
33 &self.0
34 }
35}
36
37#[cfg(test)]
38mod tests {
39 use super::*;
40
41 #[test]
42 fn parses_ids() {
43 let trace = TraceId::parse("4bf92f3577b34da6a3ce929d0e0e4736").unwrap();
44 let span = SpanId::parse("00f067aa0ba902b7").unwrap();
45 assert_eq!(trace.as_str(), "4bf92f3577b34da6a3ce929d0e0e4736");
46 assert_eq!(span.as_str(), "00f067aa0ba902b7");
47 }
48
49 #[test]
50 fn rejects_bad_ids() {
51 assert!(TraceId::parse("abc").is_err());
52 assert!(SpanId::parse("zzzzzzzzzzzzzzzz").is_err());
53 }
54}