Skip to content

Commit 0335f73

Browse files
authored
Refactor TraceState for fewer allocations (#238)
1 parent c5297d2 commit 0335f73

File tree

1 file changed

+31
-17
lines changed

1 file changed

+31
-17
lines changed

src/api/trace/span_context.rs

+31-17
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ impl SpanId {
126126
/// [W3C specification]: https://www.w3.org/TR/trace-context/#tracestate-header
127127
#[cfg_attr(feature = "serialize", derive(Deserialize, Serialize))]
128128
#[derive(Clone, Debug, Default, Eq, PartialEq)]
129-
pub struct TraceState(VecDeque<(String, String)>);
129+
pub struct TraceState(Option<VecDeque<(String, String)>>);
130130

131131
impl TraceState {
132132
/// Validates that the given `TraceState` list-member key is valid per the [W3 Spec]['spec'].
@@ -170,7 +170,7 @@ impl TraceState {
170170
K: ToString,
171171
V: ToString,
172172
{
173-
let ordered_data: Result<VecDeque<(String, String)>, ()> = trace_state
173+
let ordered_data = trace_state
174174
.into_iter()
175175
.map(|(key, value)| {
176176
let (key, value) = (key.to_string(), value.to_string());
@@ -181,19 +181,25 @@ impl TraceState {
181181

182182
Ok((key, value))
183183
})
184-
.collect();
184+
.collect::<Result<VecDeque<_>, ()>>()?;
185185

186-
ordered_data.map(TraceState)
186+
if ordered_data.is_empty() {
187+
Ok(TraceState(None))
188+
} else {
189+
Ok(TraceState(Some(ordered_data)))
190+
}
187191
}
188192

189193
/// Retrieves a value for a given key from the `TraceState` if it exists.
190194
pub fn get(&self, key: &str) -> Option<&str> {
191-
self.0.iter().find_map(|item| {
192-
if item.0.as_str() == key {
193-
Some(item.1.as_str())
194-
} else {
195-
None
196-
}
195+
self.0.as_ref().and_then(|kvs| {
196+
kvs.iter().find_map(|item| {
197+
if item.0.as_str() == key {
198+
Some(item.1.as_str())
199+
} else {
200+
None
201+
}
202+
})
197203
})
198204
}
199205

@@ -209,8 +215,9 @@ impl TraceState {
209215
}
210216

211217
let mut trace_state = self.delete(key.clone())?;
218+
let kvs = trace_state.0.get_or_insert(VecDeque::with_capacity(1));
212219

213-
trace_state.0.push_front((key, value));
220+
kvs.push_front((key, value));
214221

215222
Ok(trace_state)
216223
}
@@ -226,9 +233,12 @@ impl TraceState {
226233
}
227234

228235
let mut owned = self.clone();
236+
let kvs = owned.0.as_mut().ok_or(())?;
229237

230-
if let Some(index) = owned.0.iter().position(|x| *x.0 == *key) {
231-
owned.0.remove(index);
238+
if let Some(index) = kvs.iter().position(|x| *x.0 == *key) {
239+
kvs.remove(index);
240+
} else {
241+
return Err(());
232242
}
233243

234244
Ok(owned)
@@ -243,10 +253,14 @@ impl TraceState {
243253
/// Creates a new `TraceState` header string, with the given key/value delimiter and entry delimiter.
244254
pub fn header_delimited(&self, entry_delimiter: &str, list_delimiter: &str) -> String {
245255
self.0
246-
.iter()
247-
.map(|(key, value)| format!("{}{}{}", key, entry_delimiter, value))
248-
.collect::<Vec<String>>()
249-
.join(list_delimiter)
256+
.as_ref()
257+
.map(|kvs| {
258+
kvs.iter()
259+
.map(|(key, value)| format!("{}{}{}", key, entry_delimiter, value))
260+
.collect::<Vec<String>>()
261+
.join(list_delimiter)
262+
})
263+
.unwrap_or_default()
250264
}
251265
}
252266

0 commit comments

Comments
 (0)