From 226c204ee066a5b7257015ca492fbd45930c67df Mon Sep 17 00:00:00 2001 From: Cijo Thomas Date: Wed, 8 Nov 2023 13:42:32 -0800 Subject: [PATCH 1/2] Use HashMap instead of IndexMap in LogRecord --- opentelemetry/CHANGELOG.md | 15 + opentelemetry/Cargo.toml | 1 - opentelemetry/src/lib.rs | 4 - opentelemetry/src/logs/record.rs | 8 +- opentelemetry/src/order_map.rs | 670 ------------------------------- opentelemetry/src/trace/mod.rs | 4 - 6 files changed, 19 insertions(+), 683 deletions(-) delete mode 100644 opentelemetry/src/order_map.rs diff --git a/opentelemetry/CHANGELOG.md b/opentelemetry/CHANGELOG.md index d6d35a8616..9f305d4b0e 100644 --- a/opentelemetry/CHANGELOG.md +++ b/opentelemetry/CHANGELOG.md @@ -2,6 +2,21 @@ ## vNext +### Changed + +Modified `AnyValue.Map` to be backed by `HashMap` instead of custom `OrderMap`, +which internally used `IndexMap`. There was no requirement to maintain the order +of entries, so moving from `IndexMap` to `HashMap` offers slight performance +gains, and avoids `IndexMap` dependency. This affects `body` and `attributes` of +`LogRecord`. +[#1352](https://github.com/open-telemetry/opentelemetry-rust/pull/1352) + +### Removed + +Removed `OrderMap` type as there was no requirement to use this over regular +`HashMap`. +[#1352](https://github.com/open-telemetry/opentelemetry-rust/pull/1352) + ## [v0.21.0](https://github.com/open-telemetry/opentelemetry-rust/compare/v0.20.0...v0.21.0) This release should been seen as 1.0-rc4 following 1.0-rc3 in v0.20.0. Refer to CHANGELOG.md in individual creates for details on changes made in different creates. diff --git a/opentelemetry/Cargo.toml b/opentelemetry/Cargo.toml index 1ad3294da4..39ec98087f 100644 --- a/opentelemetry/Cargo.toml +++ b/opentelemetry/Cargo.toml @@ -23,7 +23,6 @@ rustdoc-args = ["--cfg", "docsrs"] [dependencies] futures-core = "0.3" futures-sink = "0.3" -indexmap = "2.0" once_cell = "1.12.0" pin-project-lite = { version = "0.2", optional = true } thiserror = "1.0.7" diff --git a/opentelemetry/src/lib.rs b/opentelemetry/src/lib.rs index cdc44372d4..9d2088f2ac 100644 --- a/opentelemetry/src/lib.rs +++ b/opentelemetry/src/lib.rs @@ -212,10 +212,6 @@ pub use context::{Context, ContextGuard}; mod common; -mod order_map; - -pub use order_map::OrderMap; - #[cfg(any(feature = "testing", test))] #[doc(hidden)] pub mod testing; diff --git a/opentelemetry/src/logs/record.rs b/opentelemetry/src/logs/record.rs index a65310be39..0bd7604aea 100644 --- a/opentelemetry/src/logs/record.rs +++ b/opentelemetry/src/logs/record.rs @@ -1,8 +1,8 @@ use crate::{ trace::{SpanContext, SpanId, TraceContextExt, TraceFlags, TraceId}, - Array, Key, OrderMap, StringValue, Value, + Array, Key, StringValue, Value, }; -use std::{borrow::Cow, time::SystemTime}; +use std::{borrow::Cow, collections::HashMap, time::SystemTime}; #[derive(Debug, Clone)] #[non_exhaustive] @@ -90,7 +90,7 @@ pub enum AnyValue { /// An array of `Any` values ListAny(Vec), /// A map of string keys to `Any` values, arbitrarily nested. - Map(OrderMap), + Map(HashMap), } macro_rules! impl_trivial_from { @@ -133,7 +133,7 @@ impl, V: Into> FromIterator<(K, V)> for AnyValue { /// Creates an [`AnyValue::Map`] value from a sequence of key-value pairs /// that can be converted into a `Key` and `AnyValue` respectively. fn from_iter>(iter: I) -> Self { - AnyValue::Map(OrderMap::from_iter( + AnyValue::Map(HashMap::from_iter( iter.into_iter().map(|(k, v)| (k.into(), v.into())), )) } diff --git a/opentelemetry/src/order_map.rs b/opentelemetry/src/order_map.rs deleted file mode 100644 index 46eb704a99..0000000000 --- a/opentelemetry/src/order_map.rs +++ /dev/null @@ -1,670 +0,0 @@ -use crate::{Key, KeyValue, Value}; -use indexmap::map::{ - Drain, Entry, IntoIter, IntoKeys, IntoValues, Iter, IterMut, Keys, Values, ValuesMut, -}; -use indexmap::{Equivalent, IndexMap}; -use std::collections::hash_map::RandomState; -use std::hash::{BuildHasher, Hash}; -use std::iter::FromIterator; -use std::ops::{Index, IndexMut, RangeBounds}; - -/// A hash table implementation that preserves insertion order across all operations. -/// -/// Entries will be returned according to their insertion order when iterating over the collection. -#[derive(Clone, Debug)] -pub struct OrderMap(IndexMap); - -impl OrderMap { - /// Create a new map. (Does not allocate) - #[inline] - pub fn new() -> Self { - Self(IndexMap::new()) - } - - /// Create a new map with capacity for `n` key-value pairs. (Does not - /// allocate if `n` is zero.) - /// - /// Computes in **O(n)** time. - #[inline] - pub fn with_capacity(n: usize) -> Self { - Self(IndexMap::with_capacity(n)) - } -} - -impl OrderMap { - /// Create a new map with capacity for `n` key-value pairs. (Does not - /// allocate if `n` is zero.) - /// - /// Computes in **O(n)** time. - #[inline] - pub fn with_capacity_and_hasher(n: usize, hash_builder: S) -> Self { - Self(IndexMap::with_capacity_and_hasher(n, hash_builder)) - } - - /// Create a new map with `hash_builder`. - /// - /// This function is `const`, so it - /// can be called in `static` contexts. - pub const fn with_hasher(hash_builder: S) -> Self { - Self(IndexMap::with_hasher(hash_builder)) - } - - /// Computes in **O(1)** time. - pub fn capacity(&self) -> usize { - self.0.capacity() - } - - /// Return a reference to the map's `BuildHasher`. - pub fn hasher(&self) -> &S { - self.0.hasher() - } - - /// Return the number of key-value pairs in the map. - /// - /// Computes in **O(1)** time. - #[inline] - pub fn len(&self) -> usize { - self.0.len() - } - - /// Returns true if the map contains no elements. - /// - /// Computes in **O(1)** time. - #[inline] - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } - - /// Return an iterator over the key-value pairs of the map, in their order - pub fn iter(&self) -> Iter<'_, K, V> { - self.0.iter() - } - - /// Return an iterator over the key-value pairs of the map, in their order - pub fn iter_mut(&mut self) -> IterMut<'_, K, V> { - self.0.iter_mut() - } - - /// Return an iterator over the keys of the map, in their order - pub fn keys(&self) -> Keys<'_, K, V> { - self.0.keys() - } - - /// Return an owning iterator over the keys of the map, in their order - pub fn into_keys(self) -> IntoKeys { - self.0.into_keys() - } - - /// Return an iterator over the values of the map, in their order - pub fn values(&self) -> Values<'_, K, V> { - self.0.values() - } - - /// Return an iterator over mutable references to the values of the map, - /// in their order - pub fn values_mut(&mut self) -> ValuesMut<'_, K, V> { - self.0.values_mut() - } - - /// Return an owning iterator over the values of the map, in their order - pub fn into_values(self) -> IntoValues { - self.0.into_values() - } - - /// Remove all key-value pairs in the map, while preserving its capacity. - /// - /// Computes in **O(n)** time. - pub fn clear(&mut self) { - self.0.clear(); - } - - /// Shortens the map, keeping the first `len` elements and dropping the rest. - /// - /// If `len` is greater than the map's current length, this has no effect. - pub fn truncate(&mut self, len: usize) { - self.0.truncate(len); - } - - /// Clears the `IndexMap` in the given index range, returning those - /// key-value pairs as a drain iterator. - /// - /// The range may be any type that implements `RangeBounds`, - /// including all of the `std::ops::Range*` types, or even a tuple pair of - /// `Bound` start and end values. To drain the map entirely, use `RangeFull` - /// like `map.drain(..)`. - /// - /// This shifts down all entries following the drained range to fill the - /// gap, and keeps the allocated memory for reuse. - /// - /// ***Panics*** if the starting point is greater than the end point or if - /// the end point is greater than the length of the map. - pub fn drain(&mut self, range: R) -> Drain<'_, K, V> - where - R: RangeBounds, - { - self.0.drain(range) - } - - /// Splits the collection into two at the given index. - /// - /// Returns a newly allocated map containing the elements in the range - /// `[at, len)`. After the call, the original map will be left containing - /// the elements `[0, at)` with its previous capacity unchanged. - /// - /// ***Panics*** if `at > len`. - pub fn split_off(&mut self, at: usize) -> Self - where - S: Clone, - { - Self(self.0.split_off(at)) - } -} - -impl OrderMap -where - K: Hash + Eq, - S: BuildHasher, -{ - /// Reserve capacity for `additional` more key-value pairs. - /// - /// Computes in **O(n)** time. - pub fn reserve(&mut self, additional: usize) { - self.0.reserve(additional) - } - - /// Shrink the capacity of the map as much as possible. - /// - /// Computes in **O(n)** time. - pub fn shrink_to_fit(&mut self) { - self.0.shrink_to_fit() - } - - /// Insert a key-value pair in the map. - /// - /// If an equivalent key already exists in the map: the key remains and - /// retains in its place in the order, its corresponding value is updated - /// with `value` and the older value is returned inside `Some(_)`. - /// - /// If no equivalent key existed in the map: the new key-value pair is - /// inserted, last in order, and `None` is returned. - /// - /// Computes in **O(1)** time (amortized average). - /// - /// See also [`entry`](#method.entry) if you you want to insert *or* modify - /// or if you need to get the index of the corresponding key-value pair. - pub fn insert(&mut self, key: K, value: V) -> Option { - self.0.insert(key, value) - } - - /// Insert a key-value pair in the map, and get their index. - /// - /// If an equivalent key already exists in the map: the key remains and - /// retains in its place in the order, its corresponding value is updated - /// with `value` and the older value is returned inside `(index, Some(_))`. - /// - /// If no equivalent key existed in the map: the new key-value pair is - /// inserted, last in order, and `(index, None)` is returned. - /// - /// Computes in **O(1)** time (amortized average). - /// - /// See also [`entry`](#method.entry) if you you want to insert *or* modify - /// or if you need to get the index of the corresponding key-value pair. - pub fn insert_full(&mut self, key: K, value: V) -> (usize, Option) { - self.0.insert_full(key, value) - } - - /// Get the given key’s corresponding entry in the map for insertion and/or - /// in-place manipulation. - /// - /// Computes in **O(1)** time (amortized average). - pub fn entry(&mut self, key: K) -> Entry<'_, K, V> { - self.0.entry(key) - } - - /// Return `true` if an equivalent to `key` exists in the map. - /// - /// Computes in **O(1)** time (average). - pub fn contains_key(&self, key: &Q) -> bool - where - Q: Hash + Equivalent, - { - self.0.contains_key(key) - } - - /// Return a reference to the value stored for `key`, if it is present, - /// else `None`. - /// - /// Computes in **O(1)** time (average). - pub fn get(&self, key: &Q) -> Option<&V> - where - Q: Hash + Equivalent, - { - self.0.get(key) - } - - /// Return references to the key-value pair stored for `key`, - /// if it is present, else `None`. - /// - /// Computes in **O(1)** time (average). - pub fn get_key_value(&self, key: &Q) -> Option<(&K, &V)> - where - Q: Hash + Equivalent, - { - self.0.get_key_value(key) - } - - /// Return item index, key and value - pub fn get_full(&self, key: &Q) -> Option<(usize, &K, &V)> - where - Q: Hash + Equivalent, - { - self.0.get_full(key) - } - - /// Return item index, if it exists in the map - /// - /// Computes in **O(1)** time (average). - pub fn get_index_of(&self, key: &Q) -> Option - where - Q: Hash + Equivalent, - { - self.0.get_index_of(key) - } - - /// Return a mutable reference to the element pointed at by `key`, if it exists. - pub fn get_mut(&mut self, key: &Q) -> Option<&mut V> - where - Q: Hash + Equivalent, - { - self.0.get_mut(key) - } - - /// Return a mutable reference to the element pointed at by `key`, if it exists. - /// It also returns the element's index and its key. - pub fn get_full_mut(&mut self, key: &Q) -> Option<(usize, &K, &mut V)> - where - Q: Hash + Equivalent, - { - self.0.get_full_mut(key) - } - - /// Remove the key-value pair equivalent to `key` and return - /// its value. - /// - /// Like `Vec::remove`, the pair is removed by shifting all of the - /// elements that follow it, preserving their relative order. - /// **This perturbs the index of all of those elements!** - /// - /// Return `None` if `key` is not in map. - /// - /// Computes in **O(n)** time (average). - pub fn shift_remove(&mut self, key: &Q) -> Option - where - Q: Hash + Equivalent, - { - self.0.shift_remove(key) - } - - /// Remove and return the key-value pair equivalent to `key`. - /// - /// Like `Vec::remove`, the pair is removed by shifting all of the - /// elements that follow it, preserving their relative order. - /// **This perturbs the index of all of those elements!** - /// - /// Return `None` if `key` is not in map. - /// - /// Computes in **O(n)** time (average). - pub fn shift_remove_entry(&mut self, key: &Q) -> Option<(K, V)> - where - Q: Hash + Equivalent, - { - self.0.shift_remove_entry(key) - } - - /// Remove the key-value pair equivalent to `key` and return it and - /// the index it had. - /// - /// Like `Vec::remove`, the pair is removed by shifting all of the - /// elements that follow it, preserving their relative order. - /// **This perturbs the index of all of those elements!** - /// - /// Return `None` if `key` is not in map. - /// - /// Computes in **O(n)** time (average). - pub fn shift_remove_full(&mut self, key: &Q) -> Option<(usize, K, V)> - where - Q: Hash + Equivalent, - { - self.0.shift_remove_full(key) - } - - /// Remove the last key-value pair - /// - /// This preserves the order of the remaining elements. - /// - /// Computes in **O(1)** time (average). - pub fn pop(&mut self) -> Option<(K, V)> { - self.0.pop() - } - - /// Scan through each key-value pair in the map and keep those where the - /// closure `keep` returns `true`. - /// - /// The elements are visited in order, and remaining elements keep their - /// order. - /// - /// Computes in **O(n)** time (average). - pub fn retain(&mut self, keep: F) - where - F: FnMut(&K, &mut V) -> bool, - { - self.0.retain(keep); - } -} - -impl OrderMap { - /// Get a key-value pair by index - /// - /// Valid indices are *0 <= index < self.len()* - /// - /// Computes in **O(1)** time. - pub fn get_index(&self, index: usize) -> Option<(&K, &V)> { - self.0.get_index(index) - } - - /// Get a key-value pair by index - /// - /// Valid indices are *0 <= index < self.len()* - /// - /// Computes in **O(1)** time. - pub fn get_index_mut(&mut self, index: usize) -> Option<(&K, &mut V)> { - self.0.get_index_mut(index) - } - - /// Get the first key-value pair - /// - /// Computes in **O(1)** time. - pub fn first(&self) -> Option<(&K, &V)> { - self.0.first() - } - - /// Get the first key-value pair, with mutable access to the value - /// - /// Computes in **O(1)** time. - pub fn first_mut(&mut self) -> Option<(&K, &mut V)> { - self.0.first_mut() - } - - /// Get the last key-value pair - /// - /// Computes in **O(1)** time. - pub fn last(&self) -> Option<(&K, &V)> { - self.0.last() - } - - /// Get the last key-value pair, with mutable access to the value - /// - /// Computes in **O(1)** time. - pub fn last_mut(&mut self) -> Option<(&K, &mut V)> { - self.0.last_mut() - } - - /// Remove the key-value pair by index - /// - /// Valid indices are *0 <= index < self.len()* - /// - /// Like `Vec::remove`, the pair is removed by shifting all of the - /// elements that follow it, preserving their relative order. - /// **This perturbs the index of all of those elements!** - /// - /// Computes in **O(n)** time (average). - pub fn shift_remove_index(&mut self, index: usize) -> Option<(K, V)> { - self.0.shift_remove_index(index) - } -} - -impl<'a, K, V, S> IntoIterator for &'a OrderMap { - type Item = (&'a K, &'a V); - type IntoIter = Iter<'a, K, V>; - fn into_iter(self) -> Self::IntoIter { - self.0.iter() - } -} - -impl<'a, K, V, S> IntoIterator for &'a mut OrderMap { - type Item = (&'a K, &'a mut V); - type IntoIter = IterMut<'a, K, V>; - fn into_iter(self) -> Self::IntoIter { - self.0.iter_mut() - } -} - -impl IntoIterator for OrderMap { - type Item = (K, V); - type IntoIter = IntoIter; - fn into_iter(self) -> Self::IntoIter { - self.0.into_iter() - } -} - -/// Access `OrderMap` values corresponding to a key. -/// -/// Panics if the value is missing. -impl Index<&Q> for OrderMap -where - Q: Hash + Equivalent, - K: Hash + Eq, - S: BuildHasher, -{ - type Output = V; - - /// Returns a reference to the value corresponding to the supplied `key`. - /// - /// ***Panics*** if `key` is not present in the map. - fn index(&self, key: &Q) -> &V { - self.0.index(key) - } -} - -/// Access `Ordermap` values corresponding to a key. -/// -/// Mutable indexing allows changing / updating values of key-value -/// pairs that are already present. -/// -/// You can **not** insert new pairs with index syntax, use `.insert()`. -impl IndexMut<&Q> for OrderMap -where - Q: Hash + Equivalent, - K: Hash + Eq, - S: BuildHasher, -{ - /// Returns a mutable reference to the value corresponding to the supplied `key`. - /// - /// ***Panics*** if `key` is not present in the map. - fn index_mut(&mut self, key: &Q) -> &mut V { - self.0.index_mut(key) - } -} - -/// Access `IndexMap` values at indexed positions. -/// -/// It panics if the index is out of bounds. -impl Index for OrderMap { - type Output = V; - - /// Returns a reference to the value at the supplied `index`. - /// - /// ***Panics*** if `index` is out of bounds. - fn index(&self, index: usize) -> &V { - self.0.index(index) - } -} - -/// Access `IndexMap` values at indexed positions. -/// -/// Mutable indexing allows changing / updating indexed values -/// that are already present. -/// -/// You can **not** insert new values with index syntax, use `.insert()`. -/// -/// # Examples -/// -/// ``` -/// use indexmap::IndexMap; -/// -/// let mut map = IndexMap::new(); -/// for word in "Lorem ipsum dolor sit amet".split_whitespace() { -/// map.insert(word.to_lowercase(), word.to_string()); -/// } -/// let lorem = &mut map[0]; -/// assert_eq!(lorem, "Lorem"); -/// lorem.retain(char::is_lowercase); -/// assert_eq!(map["lorem"], "orem"); -/// ``` -/// -/// ```should_panic -/// use indexmap::IndexMap; -/// -/// let mut map = IndexMap::new(); -/// map.insert("foo", 1); -/// map[10] = 1; // panics! -/// ``` -impl IndexMut for OrderMap { - /// Returns a mutable reference to the value at the supplied `index`. - /// - /// ***Panics*** if `index` is out of bounds. - fn index_mut(&mut self, index: usize) -> &mut V { - self.0.index_mut(index) - } -} - -impl FromIterator<(K, V)> for OrderMap -where - K: Hash + Eq, - S: BuildHasher + Default, -{ - /// Create an `OrderMap` from the sequence of key-value pairs in the - /// iterable. - /// - /// `from_iter` uses the same logic as `extend`. See - /// [`extend`](#method.extend) for more details. - fn from_iter>(iterable: I) -> Self { - Self(IndexMap::from_iter(iterable)) - } -} - -// todo: uncomment when the MSRV bumps -// impl From<[(K, V); N]> for OrderMap -// where -// K: Hash + Eq, -// { -// fn from(arr: [(K, V); N]) -> Self { -// Self(IndexMap::from(arr)) -// } -// } - -impl Extend<(K, V)> for OrderMap -where - K: Hash + Eq, - S: BuildHasher, -{ - /// Extend the map with all key-value pairs in the iterable. - /// - /// This is equivalent to calling [`insert`](#method.insert) for each of - /// them in order, which means that for keys that already existed - /// in the map, their value is updated but it keeps the existing order. - /// - /// New keys are inserted in the order they appear in the sequence. If - /// equivalents of a key occur more than once, the last corresponding value - /// prevails. - fn extend>(&mut self, iterable: I) { - self.0.extend(iterable) - } -} - -impl<'a, K, V, S> Extend<(&'a K, &'a V)> for OrderMap -where - K: 'a + Hash + Eq + Copy, - V: 'a + Copy, - S: BuildHasher, -{ - /// Extend the map with all key-value pairs in the iterable. - /// - /// See the first extend method for more details. - fn extend>(&mut self, iterable: I) { - self.0.extend(iterable) - } -} - -impl Default for OrderMap -where - S: Default, -{ - /// Return an empty `OrderMap` - fn default() -> Self { - Self(IndexMap::default()) - } -} - -impl PartialEq> for OrderMap -where - K: Hash + Eq, - V1: PartialEq, - S1: BuildHasher, - S2: BuildHasher, -{ - fn eq(&self, other: &OrderMap) -> bool { - self.0.eq(&other.0) - } -} - -impl Eq for OrderMap -where - K: Eq + Hash, - V: Eq, - S: BuildHasher, -{ -} - -impl FromIterator for OrderMap -where - S: BuildHasher + Default, -{ - /// Create an `OrderMap` from the sequence of key-value pairs in the - /// iterable. - /// - /// `from_iter` uses the same logic as `extend`. See - /// [`extend`](#method.extend) for more details. - fn from_iter>(iterable: I) -> Self { - Self(IndexMap::from_iter( - iterable.into_iter().map(|kv| (kv.key, kv.value)), - )) - } -} - -// todo: uncomment below when bumping MSRV -// impl From<[KeyValue; N]> for OrderMap { -// fn from(arr: [KeyValue; N]) -> Self { -// let arr = arr.map(|kv| (kv.key, kv.value)); -// Self(IndexMap::from(arr)) -// } -// } - -impl Extend for OrderMap -where - S: BuildHasher, -{ - /// Extend the map with all key-value pairs in the iterable. - /// - /// This is equivalent to calling [`insert`](#method.insert) for each of - /// them in order, which means that for keys that already existed - /// in the map, their value is updated but it keeps the existing order. - /// - /// New keys are inserted in the order they appear in the sequence. If - /// equivalents of a key occur more than once, the last corresponding value - /// prevails. - fn extend>(&mut self, iterable: I) { - self.0 - .extend(iterable.into_iter().map(|kv| (kv.key, kv.value))) - } -} diff --git a/opentelemetry/src/trace/mod.rs b/opentelemetry/src/trace/mod.rs index 2cd44f3059..038064ca49 100644 --- a/opentelemetry/src/trace/mod.rs +++ b/opentelemetry/src/trace/mod.rs @@ -183,12 +183,8 @@ pub use self::{ tracer_provider::TracerProvider, }; use crate::{ExportError, KeyValue}; -use std::collections::hash_map::RandomState; use std::sync::PoisonError; -/// re-export OrderMap to mitigate breaking change -pub type OrderMap = crate::order_map::OrderMap; - /// Describe the result of operations in tracing API. pub type TraceResult = Result; From 4d856a7ae4f790a35f998e44f19d58738cf0675f Mon Sep 17 00:00:00 2001 From: Cijo Thomas Date: Wed, 8 Nov 2023 13:49:53 -0800 Subject: [PATCH 2/2] poor job predicting PR number --- opentelemetry/CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/opentelemetry/CHANGELOG.md b/opentelemetry/CHANGELOG.md index 9f305d4b0e..078c0f315b 100644 --- a/opentelemetry/CHANGELOG.md +++ b/opentelemetry/CHANGELOG.md @@ -9,13 +9,13 @@ which internally used `IndexMap`. There was no requirement to maintain the order of entries, so moving from `IndexMap` to `HashMap` offers slight performance gains, and avoids `IndexMap` dependency. This affects `body` and `attributes` of `LogRecord`. -[#1352](https://github.com/open-telemetry/opentelemetry-rust/pull/1352) +[#1353](https://github.com/open-telemetry/opentelemetry-rust/pull/1353) ### Removed Removed `OrderMap` type as there was no requirement to use this over regular `HashMap`. -[#1352](https://github.com/open-telemetry/opentelemetry-rust/pull/1352) +[#1353](https://github.com/open-telemetry/opentelemetry-rust/pull/1353) ## [v0.21.0](https://github.com/open-telemetry/opentelemetry-rust/compare/v0.20.0...v0.21.0)