Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions opentelemetry/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Released 2025-Sep-25

- *Breaking* Change return type of `opentelemetry::global::set_tracer_provider` to Unit to align with metrics counterpart
- Add `get_all` method to `opentelemetry::propagation::Extractor` to return all values of the given propagation key and provide a default implementation.
- Add an `IntoIterator` implementation for `opentelemetry::trace::TraceState` to allow iterating through its key-value pair collection.

## 0.30.0

Expand Down
79 changes: 79 additions & 0 deletions opentelemetry/src/trace/span_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,50 @@ impl FromStr for TraceState {
}
}

/// Iterator over TraceState key-value pairs as (&str, &str)
#[derive(Debug)]
pub struct TraceStateIter<'a> {
inner: Option<std::collections::vec_deque::Iter<'a, (String, String)>>,
}

impl<'a> Iterator for TraceStateIter<'a> {
type Item = (&'a str, &'a str);

fn next(&mut self) -> Option<Self::Item> {
self.inner
.as_mut()?
.next()
.map(|(key, value)| (key.as_str(), value.as_str()))
}

fn size_hint(&self) -> (usize, Option<usize>) {
match &self.inner {
Some(iter) => iter.size_hint(),
None => (0, Some(0)),
}
}
}

impl ExactSizeIterator for TraceStateIter<'_> {
fn len(&self) -> usize {
match &self.inner {
Some(iter) => iter.len(),
None => 0,
}
}
}

impl<'a> IntoIterator for &'a TraceState {
type Item = (&'a str, &'a str);
type IntoIter = TraceStateIter<'a>;

fn into_iter(self) -> Self::IntoIter {
TraceStateIter {
inner: self.0.as_ref().map(|deque| deque.iter()),
}
}
}

/// A specialized `Result` type for trace state operations.
type TraceStateResult<T> = Result<T, TraceStateError>;

Expand Down Expand Up @@ -417,4 +461,39 @@ mod tests {
}"
);
}

#[test]
fn test_tracestate_iter_empty() {
let ts = TraceState::NONE;
let mut iter = ts.into_iter();
assert_eq!(iter.next(), None);
assert_eq!(iter.size_hint(), (0, Some(0)));
assert_eq!(iter.len(), 0);
}

#[test]
fn test_tracestate_iter_single() {
let ts = TraceState::from_key_value(vec![("foo", "bar")]).unwrap();
let mut iter = ts.into_iter();
assert_eq!(iter.next(), Some(("foo", "bar")));
assert_eq!(iter.next(), None);
assert_eq!(iter.size_hint(), (0, Some(0)));
}

#[test]
fn test_tracestate_iter_multiple() {
let ts = TraceState::from_key_value(vec![("foo", "bar"), ("apple", "banana")]).unwrap();
let mut iter = ts.into_iter();
assert_eq!(iter.next(), Some(("foo", "bar")));
assert_eq!(iter.next(), Some(("apple", "banana")));
assert_eq!(iter.next(), None);
}

#[test]
fn test_tracestate_iter_size_hint_and_len() {
let ts = TraceState::from_key_value(vec![("foo", "bar"), ("apple", "banana")]).unwrap();
let iter = ts.into_iter();
assert_eq!(iter.size_hint(), (2, Some(2)));
assert_eq!(iter.len(), 2);
}
}
Loading