Skip to main content

made_core/value_objects/
trace_id.rs

1use std::fmt;
2
3use serde::{Deserialize, Serialize};
4
5use crate::error::DomainError;
6
7const TRACE_ID_HEX_LEN: usize = 32;
8
9/// Validated W3C trace identity, without span-local context.
10#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
11#[serde(transparent)]
12pub struct TraceId(String);
13
14impl TraceId {
15    /// Validate a 16-byte, non-zero hexadecimal trace identity.
16    pub fn new(raw: impl Into<String>) -> Result<Self, DomainError> {
17        let raw = raw.into().to_ascii_lowercase();
18        if raw.len() != TRACE_ID_HEX_LEN {
19            return Err(DomainError::FieldTooLong {
20                field: "trace_id",
21                actual: raw.len(),
22                max: TRACE_ID_HEX_LEN,
23            });
24        }
25        if !raw.bytes().all(|byte| byte.is_ascii_hexdigit()) {
26            return Err(DomainError::InvalidCharacters { field: "trace_id" });
27        }
28        if raw.bytes().all(|byte| byte == b'0') {
29            return Err(DomainError::InvariantViolated {
30                reason: "trace_id must not be all zeros",
31            });
32        }
33        Ok(Self(raw))
34    }
35
36    #[must_use]
37    pub fn as_str(&self) -> &str {
38        &self.0
39    }
40}
41
42impl fmt::Display for TraceId {
43    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
44        formatter.write_str(self.as_str())
45    }
46}
47
48#[cfg(test)]
49mod tests {
50    use super::*;
51
52    #[test]
53    fn accepts_and_canonicalises_a_w3c_trace_id() {
54        let id = TraceId::new("0AF7651916CD43DD8448EB211C80319C").unwrap();
55        assert_eq!(id.as_str(), "0af7651916cd43dd8448eb211c80319c");
56    }
57
58    #[test]
59    fn rejects_invalid_and_zero_identities() {
60        assert!(TraceId::new("short").is_err());
61        assert!(TraceId::new("0af7651916cd43dd8448eb211c80319z").is_err());
62        assert!(TraceId::new("00000000000000000000000000000000").is_err());
63    }
64}