1use crate::{SpanId, TraceFlags, TraceId};
2use std::collections::VecDeque;
3use std::hash::Hash;
4use std::str::FromStr;
5use thiserror::Error;
6
7#[derive(Clone, Debug, Default, Eq, PartialEq, Hash)]
15pub struct TraceState(Option<VecDeque<(String, String)>>);
16
17const MAX_LIST_MEMBERS: usize = 32;
18
19impl TraceState {
20 pub const NONE: TraceState = TraceState(None);
22
23 fn valid_key(key: &str) -> bool {
27 if key.len() > 256 {
28 return false;
29 }
30
31 let allowed_special = |b: u8| b == b'_' || b == b'-' || b == b'*' || b == b'/';
32 let mut vendor_start = None;
33 for (i, &b) in key.as_bytes().iter().enumerate() {
34 if !(b.is_ascii_lowercase() || b.is_ascii_digit() || allowed_special(b) || b == b'@') {
35 return false;
36 }
37
38 if i == 0 && (!b.is_ascii_lowercase() && !b.is_ascii_digit()) {
39 return false;
40 } else if b == b'@' {
41 if vendor_start.is_some() || i + 14 < key.len() {
42 return false;
43 }
44 vendor_start = Some(i);
45 } else if let Some(start) = vendor_start {
46 if i == start + 1 && !(b.is_ascii_lowercase() || b.is_ascii_digit()) {
47 return false;
48 }
49 }
50 }
51
52 true
53 }
54
55 fn valid_value(value: &str) -> bool {
59 if value.len() > 256 {
60 return false;
61 }
62
63 !(value.contains(',') || value.contains('='))
64 }
65
66 pub fn from_key_value<T, K, V>(trace_state: T) -> TraceStateResult<Self>
85 where
86 T: IntoIterator<Item = (K, V)>,
87 K: ToString,
88 V: ToString,
89 {
90 let ordered_data = trace_state
91 .into_iter()
92 .take(MAX_LIST_MEMBERS)
93 .map(|(key, value)| {
94 let (key, value) = (key.to_string(), value.to_string());
95 if !TraceState::valid_key(key.as_str()) {
96 return Err(TraceStateError::Key(key));
97 }
98 if !TraceState::valid_value(value.as_str()) {
99 return Err(TraceStateError::Value(value));
100 }
101
102 Ok((key, value))
103 })
104 .collect::<Result<VecDeque<_>, TraceStateError>>()?;
105
106 if ordered_data.is_empty() {
107 Ok(TraceState(None))
108 } else {
109 Ok(TraceState(Some(ordered_data)))
110 }
111 }
112
113 pub fn get(&self, key: &str) -> Option<&str> {
115 self.0.as_ref().and_then(|kvs| {
116 kvs.iter().find_map(|item| {
117 if item.0.as_str() == key {
118 Some(item.1.as_str())
119 } else {
120 None
121 }
122 })
123 })
124 }
125
126 pub fn insert<K, V>(&self, key: K, value: V) -> TraceStateResult<TraceState>
136 where
137 K: Into<String>,
138 V: Into<String>,
139 {
140 let (key, value) = (key.into(), value.into());
141 if !TraceState::valid_key(key.as_str()) {
142 return Err(TraceStateError::Key(key));
143 }
144 if !TraceState::valid_value(value.as_str()) {
145 return Err(TraceStateError::Value(value));
146 }
147
148 let mut trace_state = self.delete_from_deque(&key);
149 let kvs = trace_state.0.get_or_insert(VecDeque::with_capacity(1));
150 if kvs.len() >= MAX_LIST_MEMBERS {
151 kvs.truncate(MAX_LIST_MEMBERS - 1);
152 }
153
154 kvs.push_front((key, value));
155
156 Ok(trace_state)
157 }
158
159 pub fn delete<K: Into<String>>(&self, key: K) -> TraceStateResult<TraceState> {
167 let key = key.into();
168 if !TraceState::valid_key(key.as_str()) {
169 return Err(TraceStateError::Key(key));
170 }
171
172 Ok(self.delete_from_deque(&key))
173 }
174
175 fn delete_from_deque(&self, key: &str) -> TraceState {
177 let mut owned = self.clone();
178 if let Some(kvs) = owned.0.as_mut() {
179 if let Some(index) = kvs.iter().position(|x| x.0 == key) {
180 kvs.remove(index);
181 }
182 }
183 owned
184 }
185
186 pub fn header(&self) -> String {
189 self.header_delimited("=", ",")
190 }
191
192 pub fn header_delimited(&self, entry_delimiter: &str, list_delimiter: &str) -> String {
194 self.0
195 .as_ref()
196 .map(|kvs| {
197 kvs.iter()
198 .map(|(key, value)| format!("{key}{entry_delimiter}{value}"))
199 .collect::<Vec<String>>()
200 .join(list_delimiter)
201 })
202 .unwrap_or_default()
203 }
204}
205
206impl FromStr for TraceState {
207 type Err = TraceStateError;
208
209 fn from_str(s: &str) -> Result<Self, Self::Err> {
210 let mut key_value_pairs: Vec<(String, String)> = Vec::new();
211
212 for list_member in s.split_terminator(',').take(MAX_LIST_MEMBERS) {
213 let list_member = list_member.trim_matches([' ', '\t']);
215 if list_member.is_empty() {
216 continue;
217 }
218
219 match list_member.find('=') {
220 None => return Err(TraceStateError::List(list_member.to_string())),
221 Some(separator_index) => {
222 let (key, value) = list_member.split_at(separator_index);
223 key_value_pairs
224 .push((key.to_string(), value.trim_start_matches('=').to_string()));
225 }
226 }
227 }
228
229 TraceState::from_key_value(key_value_pairs)
230 }
231}
232
233#[derive(Debug)]
235pub struct TraceStateIter<'a> {
236 inner: Option<std::collections::vec_deque::Iter<'a, (String, String)>>,
237}
238
239impl<'a> Iterator for TraceStateIter<'a> {
240 type Item = (&'a str, &'a str);
241
242 fn next(&mut self) -> Option<Self::Item> {
243 self.inner
244 .as_mut()?
245 .next()
246 .map(|(key, value)| (key.as_str(), value.as_str()))
247 }
248
249 fn size_hint(&self) -> (usize, Option<usize>) {
250 match &self.inner {
251 Some(iter) => iter.size_hint(),
252 None => (0, Some(0)),
253 }
254 }
255}
256
257impl ExactSizeIterator for TraceStateIter<'_> {
258 fn len(&self) -> usize {
259 match &self.inner {
260 Some(iter) => iter.len(),
261 None => 0,
262 }
263 }
264}
265
266impl<'a> IntoIterator for &'a TraceState {
267 type Item = (&'a str, &'a str);
268 type IntoIter = TraceStateIter<'a>;
269
270 fn into_iter(self) -> Self::IntoIter {
271 TraceStateIter {
272 inner: self.0.as_ref().map(|deque| deque.iter()),
273 }
274 }
275}
276
277type TraceStateResult<T> = Result<T, TraceStateError>;
279
280#[derive(Error, Debug)]
282#[non_exhaustive]
283pub enum TraceStateError {
284 #[error("{0} is not a valid key in TraceState, see https://www.w3.org/TR/trace-context-2/#key for more details")]
288 Key(String),
289
290 #[error("{0} is not a valid value in TraceState, see https://www.w3.org/TR/trace-context-2/#value for more details")]
294 Value(String),
295
296 #[error("{0} is not a valid list member in TraceState, see https://www.w3.org/TR/trace-context-2/#list for more details")]
300 List(String),
301}
302
303#[derive(Clone, Debug, PartialEq, Hash, Eq)]
313pub struct SpanContext {
314 trace_id: TraceId,
315 span_id: SpanId,
316 trace_flags: TraceFlags,
317 is_remote: bool,
318 trace_state: TraceState,
319}
320
321impl SpanContext {
322 pub const NONE: SpanContext = SpanContext {
324 trace_id: TraceId::INVALID,
325 span_id: SpanId::INVALID,
326 trace_flags: TraceFlags::NOT_SAMPLED,
327 is_remote: false,
328 trace_state: TraceState::NONE,
329 };
330
331 pub fn empty_context() -> Self {
333 SpanContext::NONE
334 }
335
336 pub fn new(
338 trace_id: TraceId,
339 span_id: SpanId,
340 trace_flags: TraceFlags,
341 is_remote: bool,
342 trace_state: TraceState,
343 ) -> Self {
344 SpanContext {
345 trace_id,
346 span_id,
347 trace_flags,
348 is_remote,
349 trace_state,
350 }
351 }
352
353 pub fn trace_id(&self) -> TraceId {
355 self.trace_id
356 }
357
358 pub fn span_id(&self) -> SpanId {
360 self.span_id
361 }
362
363 pub fn trace_flags(&self) -> TraceFlags {
368 self.trace_flags
369 }
370
371 pub fn is_valid(&self) -> bool {
374 self.trace_id != TraceId::INVALID && self.span_id != SpanId::INVALID
375 }
376
377 pub fn is_remote(&self) -> bool {
379 self.is_remote
380 }
381
382 pub fn is_sampled(&self) -> bool {
386 self.trace_flags.is_sampled()
387 }
388
389 pub fn trace_state(&self) -> &TraceState {
391 &self.trace_state
392 }
393}
394
395#[cfg(test)]
396mod tests {
397 use super::*;
398 use crate::{trace::TraceContextExt, Context};
399
400 #[rustfmt::skip]
401 fn trace_state_test_data() -> Vec<(TraceState, &'static str, &'static str)> {
402 vec![
403 (TraceState::from_key_value(vec![("foo", "bar")]).unwrap(), "foo=bar", "foo"),
404 (TraceState::from_key_value(vec![("foo", ""), ("apple", "banana")]).unwrap(), "foo=,apple=banana", "apple"),
405 (TraceState::from_key_value(vec![("foo", "bar"), ("apple", "banana")]).unwrap(), "foo=bar,apple=banana", "apple"),
406 ]
407 }
408
409 #[test]
410 fn test_trace_state() {
411 for test_case in trace_state_test_data() {
412 assert_eq!(test_case.0.clone().header(), test_case.1);
413
414 let new_key = format!("{}-{}", test_case.0.get(test_case.2).unwrap(), "test");
415
416 let updated_trace_state = test_case.0.insert(test_case.2, new_key.clone());
417 assert!(updated_trace_state.is_ok());
418 let updated_trace_state = updated_trace_state.unwrap();
419
420 let updated = format!("{}={}", test_case.2, new_key);
421
422 let index = updated_trace_state.clone().header().find(&updated);
423
424 assert!(index.is_some());
425 assert_eq!(index.unwrap(), 0);
426
427 let deleted_trace_state = updated_trace_state.delete(test_case.2.to_string());
428 assert!(deleted_trace_state.is_ok());
429
430 let deleted_trace_state = deleted_trace_state.unwrap();
431
432 assert!(deleted_trace_state.get(test_case.2).is_none());
433 }
434 }
435
436 #[test]
437 fn test_trace_state_key() {
438 let test_data: Vec<(&'static str, bool)> = vec![
439 ("123", true),
440 ("bar", true),
441 ("foo@bar", true),
442 ("foo@0123456789abcdef", false),
443 ("foo@012345678", true),
444 ("FOO@BAR", false),
445 ("你好", false),
446 ];
447
448 for (key, expected) in test_data {
449 assert_eq!(TraceState::valid_key(key), expected, "test key: {key:?}");
450 }
451 }
452
453 #[test]
454 fn test_trace_state_insert() {
455 let trace_state = TraceState::from_key_value(vec![("foo", "bar")]).unwrap();
456 let inserted_trace_state = trace_state.insert("testkey", "testvalue").unwrap();
457 assert!(trace_state.get("testkey").is_none()); assert_eq!(inserted_trace_state.get("testkey").unwrap(), "testvalue"); }
460
461 #[test]
462 fn test_context_span_debug() {
463 let cx = Context::current();
464 assert_eq!(
465 format!("{cx:?}"),
466 "Context { span: \"None\", entries count: 0, suppress_telemetry: false }"
467 );
468 let cx = Context::current().with_remote_span_context(SpanContext::NONE);
469 assert_eq!(
470 format!("{cx:?}"),
471 "Context { \
472 span: SpanContext { \
473 trace_id: 00000000000000000000000000000000, \
474 span_id: 0000000000000000, \
475 trace_flags: TraceFlags(0), \
476 is_remote: false, \
477 trace_state: TraceState(None) \
478 }, \
479 entries count: 1, suppress_telemetry: false \
480 }"
481 );
482 }
483
484 #[test]
485 fn test_tracestate_iter_empty() {
486 let ts = TraceState::NONE;
487 let mut iter = ts.into_iter();
488 assert_eq!(iter.next(), None);
489 assert_eq!(iter.size_hint(), (0, Some(0)));
490 assert_eq!(iter.len(), 0);
491 }
492
493 #[test]
494 fn test_tracestate_iter_single() {
495 let ts = TraceState::from_key_value(vec![("foo", "bar")]).unwrap();
496 let mut iter = ts.into_iter();
497 assert_eq!(iter.next(), Some(("foo", "bar")));
498 assert_eq!(iter.next(), None);
499 assert_eq!(iter.size_hint(), (0, Some(0)));
500 }
501
502 #[test]
503 fn test_tracestate_iter_multiple() {
504 let ts = TraceState::from_key_value(vec![("foo", "bar"), ("apple", "banana")]).unwrap();
505 let mut iter = ts.into_iter();
506 assert_eq!(iter.next(), Some(("foo", "bar")));
507 assert_eq!(iter.next(), Some(("apple", "banana")));
508 assert_eq!(iter.next(), None);
509 }
510
511 #[test]
512 fn test_tracestate_iter_size_hint_and_len() {
513 let ts = TraceState::from_key_value(vec![("foo", "bar"), ("apple", "banana")]).unwrap();
514 let iter = ts.into_iter();
515 assert_eq!(iter.size_hint(), (2, Some(2)));
516 assert_eq!(iter.len(), 2);
517 }
518
519 #[test]
520 fn test_tracestate_from_str_keeps_at_most_32_list_members() {
521 let header = (0..64)
522 .map(|i| format!("key{i}=value{i}"))
523 .collect::<Vec<_>>()
524 .join(",");
525 let trace_state = TraceState::from_str(&header).unwrap();
526
527 assert_eq!(trace_state.into_iter().count(), 32);
528 assert_eq!(trace_state.get("key0"), Some("value0"));
529 assert_eq!(trace_state.get("key31"), Some("value31"));
530 assert_eq!(trace_state.get("key32"), None);
531
532 let expected_header = (0..32)
533 .map(|i| format!("key{i}=value{i}"))
534 .collect::<Vec<_>>()
535 .join(",");
536 assert_eq!(trace_state.header(), expected_header);
537 }
538
539 #[test]
540 fn test_tracestate_from_str_allows_optional_whitespace_around_members() {
541 for header in [
542 "rojo=1, congo=2",
543 " rojo=1,\tcongo=2 \t",
544 "rojo=1 \t, congo=2",
545 ] {
546 let trace_state = TraceState::from_str(header).unwrap();
547
548 assert_eq!(trace_state.header(), "rojo=1,congo=2", "{header:?}");
549 }
550 }
551
552 #[test]
553 fn test_tracestate_from_str_preserves_leading_spaces_in_values() {
554 let trace_state = TraceState::from_str("rojo= 1 , congo= 2\t").unwrap();
555
556 assert_eq!(trace_state.get("rojo"), Some(" 1"));
557 assert_eq!(trace_state.get("congo"), Some(" 2"));
558 }
559
560 #[test]
561 fn test_tracestate_from_str_ignores_empty_members() {
562 let trace_state = TraceState::from_str("rojo=1, ,\t,congo=2").unwrap();
563
564 assert_eq!(trace_state.get("rojo"), Some("1"));
565 assert_eq!(trace_state.get("congo"), Some("2"));
566 assert_eq!(trace_state.into_iter().count(), 2);
567
568 assert_eq!(TraceState::from_str(" \t ").unwrap(), TraceState::NONE);
569 }
570 #[test]
571 fn test_tracestate_from_str_ignores_invalid_members_beyond_the_limit() {
572 let mut members: Vec<String> = (0..32).map(|i| format!("key{i}=value{i}")).collect();
573 members.push("invalid-no-separator".to_string());
574 let trace_state = TraceState::from_str(&members.join(",")).unwrap();
575
576 assert_eq!(trace_state.into_iter().count(), 32);
577 }
578 #[test]
579 fn test_tracestate_from_str_rejects_invalid_members_within_the_limit() {
580 let mut members: Vec<String> = (0..31).map(|i| format!("key{i}=value{i}")).collect();
581 members.push("invalid-no-separator".to_string());
582
583 assert!(TraceState::from_str(&members.join(",")).is_err());
584 }
585 #[test]
586 fn test_tracestate_from_key_value_keeps_at_most_32_list_members() {
587 let kvs: Vec<(String, String)> = (0..64)
588 .map(|i| (format!("key{i}"), format!("value{i}")))
589 .collect();
590 let trace_state = TraceState::from_key_value(kvs).unwrap();
591
592 assert_eq!(trace_state.into_iter().count(), 32);
593 assert_eq!(trace_state.get("key0"), Some("value0"));
594 assert_eq!(trace_state.get("key32"), None);
595 }
596 #[test]
597 fn test_tracestate_insert_keeps_at_most_32_list_members() {
598 let mut trace_state = TraceState::default();
599 for i in 0..64 {
600 trace_state = trace_state
601 .insert(format!("key{i}"), format!("value{i}"))
602 .unwrap();
603 }
604
605 assert_eq!(trace_state.into_iter().count(), 32);
606 assert_eq!(trace_state.get("key63"), Some("value63"));
607 assert_eq!(trace_state.get("key32"), Some("value32"));
608 assert_eq!(trace_state.get("key31"), None);
609 }
610 #[test]
611 fn test_tracestate_insert_of_an_existing_key_evicts_nothing() {
612 let mut trace_state = TraceState::default();
613 for i in 0..32 {
614 trace_state = trace_state
615 .insert(format!("key{i}"), format!("value{i}"))
616 .unwrap();
617 }
618 let updated = trace_state.insert("key20", "updated").unwrap();
619
620 assert_eq!(updated.into_iter().count(), 32);
621 assert_eq!(updated.get("key20"), Some("updated"));
622 assert_eq!(updated.get("key0"), Some("value0"));
623 }
624}