zipkin_types/
trace_id.rs

1//  Copyright 2017 Palantir Technologies, Inc.
2//
3//  Licensed under the Apache License, Version 2.0 (the "License");
4//  you may not use this file except in compliance with the License.
5//  You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9//  Unless required by applicable law or agreed to in writing, software
10//  distributed under the License is distributed on an "AS IS" BASIS,
11//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//  See the License for the specific language governing permissions and
13//  limitations under the License.
14
15//! Trace IDs.
16use data_encoding::{DecodeError, HEXLOWER_PERMISSIVE};
17use std::error::Error;
18use std::fmt;
19use std::str::FromStr;
20
21#[derive(Copy, Clone, Debug, PartialEq, Eq)]
22enum Inner {
23    Short([u8; 8]),
24    Long([u8; 16]),
25}
26
27/// The ID of a trace.
28///
29/// Trace IDs are either 8 or 16 bytes, and are serialized as hexadecimal
30/// strings.
31#[derive(Copy, Clone, Debug, PartialEq, Eq)]
32pub struct TraceId(Inner);
33
34impl fmt::Display for TraceId {
35    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
36        for b in self.bytes() {
37            write!(fmt, "{:02x}", b)?;
38        }
39        Ok(())
40    }
41}
42
43impl FromStr for TraceId {
44    type Err = TraceIdParseError;
45
46    fn from_str(s: &str) -> Result<TraceId, TraceIdParseError> {
47        let inner = match HEXLOWER_PERMISSIVE.decode_len(s.len()) {
48            Ok(8) => {
49                let mut buf = [0; 8];
50                HEXLOWER_PERMISSIVE
51                    .decode_mut(s.as_bytes(), &mut buf)
52                    .map_err(|e| TraceIdParseError(Some(e.error)))?;
53                Inner::Short(buf)
54            }
55            Ok(16) => {
56                let mut buf = [0; 16];
57                HEXLOWER_PERMISSIVE
58                    .decode_mut(s.as_bytes(), &mut buf)
59                    .map_err(|e| TraceIdParseError(Some(e.error)))?;
60                Inner::Long(buf)
61            }
62            _ => return Err(TraceIdParseError(None)),
63        };
64
65        Ok(TraceId(inner))
66    }
67}
68
69#[cfg(feature = "serde")]
70mod serde {
71    use crate::trace_id::TraceId;
72    use serde::de::{Error, Unexpected, Visitor};
73    use serde::{Deserialize, Deserializer, Serialize, Serializer};
74    use std::fmt;
75
76    impl Serialize for TraceId {
77        fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
78        where
79            S: Serializer,
80        {
81            s.collect_str(self)
82        }
83    }
84
85    impl<'de> Deserialize<'de> for TraceId {
86        fn deserialize<D>(d: D) -> Result<TraceId, D::Error>
87        where
88            D: Deserializer<'de>,
89        {
90            d.deserialize_str(V)
91        }
92    }
93
94    struct V;
95
96    impl<'de> Visitor<'de> for V {
97        type Value = TraceId;
98
99        fn expecting(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
100            fmt.write_str("a hex-encoded trace ID")
101        }
102
103        fn visit_str<E>(self, v: &str) -> Result<TraceId, E>
104        where
105            E: Error,
106        {
107            v.parse()
108                .map_err(|_| Error::invalid_value(Unexpected::Str(v), &self))
109        }
110    }
111}
112
113impl TraceId {
114    /// Returns the byte representation of the trace ID.
115    #[inline]
116    pub fn bytes(&self) -> &[u8] {
117        match self.0 {
118            Inner::Short(ref buf) => buf,
119            Inner::Long(ref buf) => buf,
120        }
121    }
122}
123
124impl From<[u8; 8]> for TraceId {
125    #[inline]
126    fn from(bytes: [u8; 8]) -> TraceId {
127        TraceId(Inner::Short(bytes))
128    }
129}
130
131impl From<[u8; 16]> for TraceId {
132    #[inline]
133    fn from(bytes: [u8; 16]) -> TraceId {
134        TraceId(Inner::Long(bytes))
135    }
136}
137
138/// The error returned when parsing a `TraceId` from a string.
139#[derive(Debug)]
140pub struct TraceIdParseError(Option<DecodeError>);
141
142impl fmt::Display for TraceIdParseError {
143    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
144        fmt.write_str("error parsing trace ID: ")?;
145        match self.0 {
146            Some(ref err) => write!(fmt, "{}", err),
147            None => fmt.write_str("invalid length"),
148        }
149    }
150}
151
152impl Error for TraceIdParseError {
153    fn source(&self) -> Option<&(dyn Error + 'static)> {
154        self.0.as_ref().map(|e| e as _)
155    }
156}