diff --git a/opentelemetry-sdk/src/attributes/set.rs b/opentelemetry-sdk/src/attributes/set.rs index 06490879a1..ae5d5a4a73 100644 --- a/opentelemetry-sdk/src/attributes/set.rs +++ b/opentelemetry-sdk/src/attributes/set.rs @@ -1,3 +1,4 @@ +use std::collections::hash_map::DefaultHasher; use std::collections::HashSet; use std::{ cmp::Ordering, @@ -104,13 +105,13 @@ impl Eq for HashKeyValue {} /// /// This must implement [Hash], [PartialEq], and [Eq] so it may be used as /// HashMap keys and other de-duplication methods. -#[derive(Clone, Default, Debug, Hash, PartialEq, Eq)] -pub struct AttributeSet(Vec); +#[derive(Clone, Default, Debug, PartialEq, Eq)] +pub struct AttributeSet(Vec, u64); impl From<&[KeyValue]> for AttributeSet { fn from(values: &[KeyValue]) -> Self { let mut seen_keys = HashSet::with_capacity(values.len()); - let mut vec = values + let vec = values .iter() .rev() .filter_map(|kv| { @@ -121,25 +122,34 @@ impl From<&[KeyValue]> for AttributeSet { } }) .collect::>(); - vec.sort_unstable(); - AttributeSet(vec) + AttributeSet::new(vec) } } impl From<&Resource> for AttributeSet { fn from(values: &Resource) -> Self { - let mut vec = values + let vec = values .iter() .map(|(key, value)| HashKeyValue(KeyValue::new(key.clone(), value.clone()))) .collect::>(); - vec.sort_unstable(); - AttributeSet(vec) + AttributeSet::new(vec) } } impl AttributeSet { + fn new(mut values: Vec) -> Self { + values.sort_unstable(); + let mut hasher = DefaultHasher::new(); + values.iter().fold(&mut hasher, |mut hasher, item| { + item.hash(&mut hasher); + hasher + }); + + AttributeSet(values, hasher.finish()) + } + /// Returns the number of elements in the set. pub fn len(&self) -> usize { self.0.len() @@ -163,3 +173,9 @@ impl AttributeSet { self.0.iter().map(|kv| (&kv.0.key, &kv.0.value)) } } + +impl Hash for AttributeSet { + fn hash(&self, state: &mut H) { + state.write_u64(self.1) + } +}