1use core::fmt;
17use core::str::FromStr;
18
19#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Default)]
28pub struct ProcessId(u128);
29
30impl ProcessId {
31 pub fn random(rng: &mut impl rand::Rng) -> Self {
33 Self(rng.random())
34 }
35
36 pub const fn from_raw(raw: u128) -> Self {
42 Self(raw)
43 }
44
45 pub fn to_raw(self) -> u128 {
47 self.0
48 }
49}
50
51impl fmt::Display for ProcessId {
52 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
53 write!(f, "{:032x}", self.0)
54 }
55}
56
57impl FromStr for ProcessId {
58 type Err = core::num::ParseIntError;
59
60 fn from_str(s: &str) -> Result<Self, Self::Err> {
61 u128::from_str_radix(s, 16).map(ProcessId)
62 }
63}
64
65impl serde::Serialize for ProcessId {
66 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
67 where
68 S: serde::Serializer,
69 {
70 let mut hex_bytes = [0u8; size_of::<u128>() * 2];
71 hex::encode_to_slice(self.0.to_le_bytes(), &mut hex_bytes).unwrap();
72
73 serializer.serialize_str(str::from_utf8(&hex_bytes).unwrap())
74 }
75}
76
77impl<'de> serde::Deserialize<'de> for ProcessId {
78 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
79 where
80 D: serde::Deserializer<'de>,
81 {
82 let bytes: [u8; size_of::<u128>()] = hex::serde::deserialize(deserializer)?;
83
84 Ok(ProcessId(u128::from_le_bytes(bytes)))
85 }
86}
87
88#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
90pub struct SpanId(pub u64);
91
92#[cfg(feature = "enable")]
93impl SpanId {
94 #[inline]
95 #[doc(hidden)]
96 pub fn next_id() -> Self {
98 use core::sync::atomic;
99 static COUNTER: atomic::AtomicU64 = atomic::AtomicU64::new(1);
100 SpanId(COUNTER.fetch_add(1, atomic::Ordering::Relaxed))
101 }
102}
103
104impl fmt::Display for SpanId {
105 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106 write!(f, "{:016x}", self.0)
107 }
108}
109
110impl FromStr for SpanId {
111 type Err = core::num::ParseIntError;
112
113 fn from_str(s: &str) -> Result<Self, Self::Err> {
114 u64::from_str_radix(s, 16).map(SpanId)
115 }
116}
117
118impl serde::Serialize for SpanId {
119 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
120 where
121 S: serde::Serializer,
122 {
123 let mut hex_bytes = [0u8; size_of::<u64>() * 2];
124 hex::encode_to_slice(self.0.to_le_bytes(), &mut hex_bytes).unwrap();
125
126 serializer.serialize_str(str::from_utf8(&hex_bytes).unwrap())
127 }
128}
129
130impl<'de> serde::Deserialize<'de> for SpanId {
131 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
132 where
133 D: serde::Deserializer<'de>,
134 {
135 let bytes: [u8; size_of::<u64>()] = hex::serde::deserialize(deserializer)?;
136
137 Ok(SpanId(u64::from_le_bytes(bytes)))
138 }
139}
140
141#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
143pub struct SpanContext {
144 pub process_id: ProcessId,
146 pub span_id: SpanId,
148}
149
150impl SpanContext {
151 pub fn new(process_id: ProcessId, span_id: SpanId) -> Self {
161 Self {
162 process_id,
163 span_id,
164 }
165 }
166
167 pub fn current() -> Option<Self> {
182 #[cfg(not(feature = "enable"))]
183 {
184 None
185 }
186
187 #[cfg(feature = "enable")]
188 {
189 crate::span::CURRENT_SPAN
190 .get()
191 .map(|span_id| Self::new(crate::collector::get_collector().process_id(), span_id))
192 }
193 }
194}
195
196impl fmt::Display for SpanContext {
197 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
198 let Self {
199 process_id,
200 span_id,
201 } = self;
202 write!(f, "{process_id}:{span_id}")
203 }
204}
205
206#[derive(Clone, Debug)]
208pub enum ParseSpanContextError {
209 MissingSeparator,
211
212 InvalidProcessId(core::num::ParseIntError),
214
215 InvalidSpanId(core::num::ParseIntError),
217}
218
219impl fmt::Display for ParseSpanContextError {
220 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
221 match self {
222 Self::MissingSeparator => f.write_str("missing ':' separator"),
223 Self::InvalidProcessId(_) => f.write_str("failed to parse process id"),
224 Self::InvalidSpanId(_) => f.write_str("failed to parse span id"),
225 }
226 }
227}
228
229impl core::error::Error for ParseSpanContextError {
230 fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
231 match self {
232 Self::MissingSeparator => None,
233 Self::InvalidProcessId(error) => Some(error),
234 Self::InvalidSpanId(error) => Some(error),
235 }
236 }
237}
238
239impl FromStr for SpanContext {
240 type Err = ParseSpanContextError;
241
242 fn from_str(s: &str) -> Result<Self, Self::Err> {
243 let Some((process_id, span_id)) = s.split_once(":") else {
244 return Err(ParseSpanContextError::MissingSeparator);
245 };
246 let process_id =
247 ProcessId::from_str(process_id).map_err(ParseSpanContextError::InvalidProcessId)?;
248 let span_id = SpanId::from_str(span_id).map_err(ParseSpanContextError::InvalidSpanId)?;
249 Ok(Self {
250 process_id,
251 span_id,
252 })
253 }
254}
255
256impl serde::Serialize for SpanContext {
257 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
258 where
259 S: serde::Serializer,
260 {
261 let mut bytes = [0u8; 49];
262
263 hex::encode_to_slice(self.process_id.to_raw().to_le_bytes(), &mut bytes[..32]).unwrap();
264 bytes[32] = b':';
265 hex::encode_to_slice(self.span_id.0.to_le_bytes(), &mut bytes[33..]).unwrap();
266
267 serializer.serialize_str(str::from_utf8(&bytes).unwrap())
268 }
269}
270
271impl<'de> serde::Deserialize<'de> for SpanContext {
272 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
273 where
274 D: serde::Deserializer<'de>,
275 {
276 use serde::de::Error;
277
278 let string = <&str>::deserialize(deserializer)?;
279
280 if string.len() != 49 {
281 return Err(D::Error::invalid_length(
282 string.len(),
283 &"expected 49 byte string",
284 ));
285 }
286
287 let bytes = string.as_bytes();
288
289 if bytes[32] != b':' {
290 return Err(D::Error::invalid_value(
291 serde::de::Unexpected::Str(string),
292 &"expected : separator at byte 32",
293 ));
294 }
295
296 let mut process = [0; 16];
297 hex::decode_to_slice(&bytes[..32], &mut process).map_err(D::Error::custom)?;
298
299 let mut span = [0; 8];
300 hex::decode_to_slice(&bytes[33..], &mut span).map_err(D::Error::custom)?;
301
302 Ok(Self {
303 process_id: ProcessId::from_raw(u128::from_le_bytes(process)),
304 span_id: SpanId(u64::from_le_bytes(span)),
305 })
306 }
307}
308
309#[cfg(all(test, feature = "std"))]
310mod tests {
311 use std::collections::HashSet;
312 use std::format;
313 use std::string::String;
314 use std::vec::Vec;
315
316 use super::*;
317
318 #[test]
319 #[cfg(not(miri))] #[allow(clippy::needless_collect)]
321 fn unique_id() {
322 let handles = std::iter::repeat_with(|| {
323 std::thread::spawn(|| {
324 std::iter::repeat_with(SpanId::next_id)
325 .take(1000)
326 .collect::<Vec<_>>()
327 })
328 })
329 .take(32)
330 .collect::<Vec<_>>();
331
332 let k = handles
333 .into_iter()
334 .flat_map(|h| h.join().unwrap())
335 .collect::<HashSet<_>>();
336
337 assert_eq!(k.len(), 32 * 1000);
338 }
339
340 #[test]
341 fn span_id_formatting() {
342 assert_eq!(format!("{}", SpanId(0)), "0000000000000000");
343 assert_eq!(format!("{}", SpanId(u64::MAX)), "ffffffffffffffff");
344 assert_eq!(
345 format!("{}", SpanId(0xFEDCBA9876543210)),
346 "fedcba9876543210"
347 );
348 assert_eq!(format!("{}", SpanId(0x123)), "0000000000000123");
349 }
350
351 #[test]
352 fn span_id_from_str() {
353 assert_eq!(
354 "fedcba9876543210".parse::<SpanId>().unwrap(),
355 SpanId(0xFEDCBA9876543210)
356 );
357 assert_eq!(
358 "FEDCBA9876543210".parse::<SpanId>().unwrap(),
359 SpanId(0xFEDCBA9876543210)
360 );
361 assert_eq!("0000000000000000".parse::<SpanId>().unwrap(), SpanId(0));
362 assert_eq!(
363 "ffffffffffffffff".parse::<SpanId>().unwrap(),
364 SpanId(u64::MAX)
365 );
366 assert_eq!("123".parse::<SpanId>().unwrap(), SpanId(0x123));
367
368 assert!("xyz".parse::<SpanId>().is_err());
369 assert!("".parse::<SpanId>().is_err());
370 }
371
372 #[test]
373 fn span_id_format_from_str_roundtrip() {
374 let test_cases = [0u64, 1, 0x123, 0xFEDCBA9876543210, u64::MAX, u64::MAX - 1];
375
376 for value in test_cases {
377 let span_id = SpanId(value);
378 let formatted = format!("{span_id}");
379 let parsed = formatted.parse::<SpanId>().unwrap();
380 assert_eq!(span_id, parsed, "Failed roundtrip for value {value:#x}");
381 }
382 }
383
384 #[test]
385 fn span_id_serde_roundtrip() {
386 let test_cases = [
387 SpanId(0),
388 SpanId(1),
389 SpanId(0x123),
390 SpanId(0xFEDCBA9876543210),
391 SpanId(u64::MAX),
392 SpanId(u64::MAX - 1),
393 ];
394
395 for original in test_cases {
396 let json = serde_json::to_string(&original).unwrap();
397 let deserialized: SpanId = serde_json::from_str(&json).unwrap();
398 assert_eq!(
399 original, deserialized,
400 "JSON roundtrip failed for {:#x}",
401 original.0
402 );
403 }
404 }
405
406 #[test]
407 fn span_context_serde_roundtrip() {
408 let test_cases = [
409 SpanContext::new(ProcessId::from_raw(0), SpanId(0)),
410 SpanContext::new(
411 ProcessId::from_raw(0x123456789ABCDEF0FEDCBA9876543210),
412 SpanId(0xFEDCBA9876543210),
413 ),
414 SpanContext::new(ProcessId::from_raw(u128::MAX), SpanId(u64::MAX)),
415 SpanContext::new(ProcessId::from_raw(1), SpanId(1)),
416 ];
417
418 for original in test_cases {
419 let json = serde_json::to_string(&original).unwrap();
420 let deserialized: SpanContext = serde_json::from_str(&json).unwrap();
421 assert_eq!(
422 original.process_id, deserialized.process_id,
423 "JSON roundtrip failed for process_id"
424 );
425 assert_eq!(
426 original.span_id, deserialized.span_id,
427 "JSON roundtrip failed for span_id"
428 );
429 }
430 }
431
432 #[test]
433 fn span_id_serialization_format() {
434 let span_id = SpanId(0xFEDCBA9876543210);
435 let json = serde_json::to_string(&span_id).unwrap();
436
437 let expected_le_bytes = 0xFEDCBA9876543210u64.to_le_bytes();
438 let mut expected_hex = String::new();
439 for byte in &expected_le_bytes {
440 expected_hex.push_str(&format!("{byte:02x}"));
441 }
442 let expected_json = format!("\"{expected_hex}\"");
443
444 assert_eq!(json, expected_json);
445 }
446
447 #[test]
448 fn span_context_new_and_fields() {
449 let process_id = ProcessId::from_raw(0x123);
450 let span_id = SpanId(0x456);
451 let context = SpanContext::new(process_id, span_id);
452
453 assert_eq!(context.process_id, process_id);
454 assert_eq!(context.span_id, span_id);
455 }
456
457 #[test]
458 fn process_id_format_from_str_roundtrip() {
459 let test_cases = [
460 0u128,
461 1,
462 0x123,
463 0xFEDCBA9876543210,
464 0x123456789ABCDEF0FEDCBA9876543210,
465 u128::MAX,
466 u128::MAX - 1,
467 ];
468
469 for value in test_cases {
470 let process_id = ProcessId::from_raw(value);
471 let formatted = format!("{process_id}");
472 let parsed = formatted.parse::<ProcessId>().unwrap();
473 assert_eq!(process_id, parsed, "Failed roundtrip for value {value:#x}");
474 }
475 }
476
477 #[test]
478 fn process_id_serde_roundtrip() {
479 let test_cases = [
480 ProcessId::from_raw(0),
481 ProcessId::from_raw(1),
482 ProcessId::from_raw(0x123),
483 ProcessId::from_raw(0xFEDCBA9876543210),
484 ProcessId::from_raw(0x123456789ABCDEF0FEDCBA9876543210),
485 ProcessId::from_raw(u128::MAX),
486 ProcessId::from_raw(u128::MAX - 1),
487 ];
488
489 for original in test_cases {
490 let json = serde_json::to_string(&original).unwrap();
491 let deserialized: ProcessId = serde_json::from_str(&json).unwrap();
492 assert_eq!(
493 original,
494 deserialized,
495 "JSON roundtrip failed for {:#x}",
496 original.to_raw()
497 );
498 }
499 }
500
501 #[test]
502 fn span_context_format_from_str_roundtrip() {
503 let test_cases = [
504 SpanContext::new(ProcessId::from_raw(0), SpanId(0)),
505 SpanContext::new(
506 ProcessId::from_raw(0x123456789ABCDEF0FEDCBA9876543210),
507 SpanId(0xFEDCBA9876543210),
508 ),
509 SpanContext::new(ProcessId::from_raw(u128::MAX), SpanId(u64::MAX)),
510 SpanContext::new(ProcessId::from_raw(1), SpanId(1)),
511 ];
512
513 for context in test_cases {
514 let formatted = format!("{context}");
515 let parsed = formatted.parse::<SpanContext>().unwrap();
516 assert_eq!(
517 context,
518 parsed,
519 "Failed roundtrip for {:#x}:{:#x}",
520 context.process_id.to_raw(),
521 context.span_id.0
522 );
523 }
524 }
525
526 #[test]
527 fn span_id_next_id_produces_non_zero_values() {
528 let ids: Vec<SpanId> = (0..100).map(|_| SpanId::next_id()).collect();
529
530 for id in &ids {
531 assert_ne!(id.0, 0, "SpanId::next_id() should not produce zero values");
532 }
533
534 let mut unique_ids = HashSet::new();
535 for id in &ids {
536 assert!(
537 unique_ids.insert(id.0),
538 "SpanId::next_id() should produce unique values"
539 );
540 }
541 }
542}