Skip to content

Commit b54fa84

Browse files
iunanualalitbcijothomas
authored
feat: add an Iterator for opentelemetry::trace::TraceState key-value pairs (#3164)
Co-authored-by: Lalit Kumar Bhasin <[email protected]> Co-authored-by: Cijo Thomas <[email protected]>
1 parent c54d2b8 commit b54fa84

File tree

2 files changed

+80
-0
lines changed

2 files changed

+80
-0
lines changed

opentelemetry/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ Released 2025-Sep-25
1010

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

1415
## 0.30.0
1516

opentelemetry/src/trace/span_context.rs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,50 @@ impl FromStr for TraceState {
211211
}
212212
}
213213

214+
/// Iterator over TraceState key-value pairs as (&str, &str)
215+
#[derive(Debug)]
216+
pub struct TraceStateIter<'a> {
217+
inner: Option<std::collections::vec_deque::Iter<'a, (String, String)>>,
218+
}
219+
220+
impl<'a> Iterator for TraceStateIter<'a> {
221+
type Item = (&'a str, &'a str);
222+
223+
fn next(&mut self) -> Option<Self::Item> {
224+
self.inner
225+
.as_mut()?
226+
.next()
227+
.map(|(key, value)| (key.as_str(), value.as_str()))
228+
}
229+
230+
fn size_hint(&self) -> (usize, Option<usize>) {
231+
match &self.inner {
232+
Some(iter) => iter.size_hint(),
233+
None => (0, Some(0)),
234+
}
235+
}
236+
}
237+
238+
impl ExactSizeIterator for TraceStateIter<'_> {
239+
fn len(&self) -> usize {
240+
match &self.inner {
241+
Some(iter) => iter.len(),
242+
None => 0,
243+
}
244+
}
245+
}
246+
247+
impl<'a> IntoIterator for &'a TraceState {
248+
type Item = (&'a str, &'a str);
249+
type IntoIter = TraceStateIter<'a>;
250+
251+
fn into_iter(self) -> Self::IntoIter {
252+
TraceStateIter {
253+
inner: self.0.as_ref().map(|deque| deque.iter()),
254+
}
255+
}
256+
}
257+
214258
/// A specialized `Result` type for trace state operations.
215259
type TraceStateResult<T> = Result<T, TraceStateError>;
216260

@@ -417,4 +461,39 @@ mod tests {
417461
}"
418462
);
419463
}
464+
465+
#[test]
466+
fn test_tracestate_iter_empty() {
467+
let ts = TraceState::NONE;
468+
let mut iter = ts.into_iter();
469+
assert_eq!(iter.next(), None);
470+
assert_eq!(iter.size_hint(), (0, Some(0)));
471+
assert_eq!(iter.len(), 0);
472+
}
473+
474+
#[test]
475+
fn test_tracestate_iter_single() {
476+
let ts = TraceState::from_key_value(vec![("foo", "bar")]).unwrap();
477+
let mut iter = ts.into_iter();
478+
assert_eq!(iter.next(), Some(("foo", "bar")));
479+
assert_eq!(iter.next(), None);
480+
assert_eq!(iter.size_hint(), (0, Some(0)));
481+
}
482+
483+
#[test]
484+
fn test_tracestate_iter_multiple() {
485+
let ts = TraceState::from_key_value(vec![("foo", "bar"), ("apple", "banana")]).unwrap();
486+
let mut iter = ts.into_iter();
487+
assert_eq!(iter.next(), Some(("foo", "bar")));
488+
assert_eq!(iter.next(), Some(("apple", "banana")));
489+
assert_eq!(iter.next(), None);
490+
}
491+
492+
#[test]
493+
fn test_tracestate_iter_size_hint_and_len() {
494+
let ts = TraceState::from_key_value(vec![("foo", "bar"), ("apple", "banana")]).unwrap();
495+
let iter = ts.into_iter();
496+
assert_eq!(iter.size_hint(), (2, Some(2)));
497+
assert_eq!(iter.len(), 2);
498+
}
420499
}

0 commit comments

Comments
 (0)