summaryrefslogtreecommitdiffstats
path: root/vendor/tracing-subscriber/src/registry/extensions.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/tracing-subscriber/src/registry/extensions.rs')
-rw-r--r--vendor/tracing-subscriber/src/registry/extensions.rs274
1 files changed, 274 insertions, 0 deletions
diff --git a/vendor/tracing-subscriber/src/registry/extensions.rs b/vendor/tracing-subscriber/src/registry/extensions.rs
new file mode 100644
index 000000000..ff76fb599
--- /dev/null
+++ b/vendor/tracing-subscriber/src/registry/extensions.rs
@@ -0,0 +1,274 @@
+// taken from https://github.com/hyperium/http/blob/master/src/extensions.rs.
+
+use crate::sync::{RwLockReadGuard, RwLockWriteGuard};
+use std::{
+ any::{Any, TypeId},
+ collections::HashMap,
+ fmt,
+ hash::{BuildHasherDefault, Hasher},
+};
+
+#[allow(warnings)]
+type AnyMap = HashMap<TypeId, Box<dyn Any + Send + Sync>, BuildHasherDefault<IdHasher>>;
+
+/// With TypeIds as keys, there's no need to hash them. They are already hashes
+/// themselves, coming from the compiler. The IdHasher holds the u64 of
+/// the TypeId, and then returns it, instead of doing any bit fiddling.
+#[derive(Default, Debug)]
+struct IdHasher(u64);
+
+impl Hasher for IdHasher {
+ fn write(&mut self, _: &[u8]) {
+ unreachable!("TypeId calls write_u64");
+ }
+
+ #[inline]
+ fn write_u64(&mut self, id: u64) {
+ self.0 = id;
+ }
+
+ #[inline]
+ fn finish(&self) -> u64 {
+ self.0
+ }
+}
+
+/// An immutable, read-only reference to a Span's extensions.
+#[derive(Debug)]
+#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
+pub struct Extensions<'a> {
+ inner: RwLockReadGuard<'a, ExtensionsInner>,
+}
+
+impl<'a> Extensions<'a> {
+ #[cfg(feature = "registry")]
+ pub(crate) fn new(inner: RwLockReadGuard<'a, ExtensionsInner>) -> Self {
+ Self { inner }
+ }
+
+ /// Immutably borrows a type previously inserted into this `Extensions`.
+ pub fn get<T: 'static>(&self) -> Option<&T> {
+ self.inner.get::<T>()
+ }
+}
+
+/// An mutable reference to a Span's extensions.
+#[derive(Debug)]
+#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
+pub struct ExtensionsMut<'a> {
+ inner: RwLockWriteGuard<'a, ExtensionsInner>,
+}
+
+impl<'a> ExtensionsMut<'a> {
+ #[cfg(feature = "registry")]
+ pub(crate) fn new(inner: RwLockWriteGuard<'a, ExtensionsInner>) -> Self {
+ Self { inner }
+ }
+
+ /// Insert a type into this `Extensions`.
+ ///
+ /// Note that extensions are _not_
+ /// `Layer`-specific—they are _span_-specific. This means that
+ /// other layers can access and mutate extensions that
+ /// a different Layer recorded. For example, an application might
+ /// have a layer that records execution timings, alongside a layer
+ /// that reports spans and events to a distributed
+ /// tracing system that requires timestamps for spans.
+ /// Ideally, if one layer records a timestamp _x_, the other layer
+ /// should be able to reuse timestamp _x_.
+ ///
+ /// Therefore, extensions should generally be newtypes, rather than common
+ /// types like [`String`](std::string::String), to avoid accidental
+ /// cross-`Layer` clobbering.
+ ///
+ /// ## Panics
+ ///
+ /// If `T` is already present in `Extensions`, then this method will panic.
+ pub fn insert<T: Send + Sync + 'static>(&mut self, val: T) {
+ assert!(self.replace(val).is_none())
+ }
+
+ /// Replaces an existing `T` into this extensions.
+ ///
+ /// If `T` is not present, `Option::None` will be returned.
+ pub fn replace<T: Send + Sync + 'static>(&mut self, val: T) -> Option<T> {
+ self.inner.insert(val)
+ }
+
+ /// Get a mutable reference to a type previously inserted on this `ExtensionsMut`.
+ pub fn get_mut<T: 'static>(&mut self) -> Option<&mut T> {
+ self.inner.get_mut::<T>()
+ }
+
+ /// Remove a type from this `Extensions`.
+ ///
+ /// If a extension of this type existed, it will be returned.
+ pub fn remove<T: Send + Sync + 'static>(&mut self) -> Option<T> {
+ self.inner.remove::<T>()
+ }
+}
+
+/// A type map of span extensions.
+///
+/// [ExtensionsInner] is used by `SpanData` to store and
+/// span-specific data. A given `Layer` can read and write
+/// data that it is interested in recording and emitting.
+#[derive(Default)]
+pub(crate) struct ExtensionsInner {
+ map: AnyMap,
+}
+
+impl ExtensionsInner {
+ /// Create an empty `Extensions`.
+ #[cfg(any(test, feature = "registry"))]
+ #[inline]
+ #[cfg(any(test, feature = "registry"))]
+ pub(crate) fn new() -> ExtensionsInner {
+ ExtensionsInner {
+ map: AnyMap::default(),
+ }
+ }
+
+ /// Insert a type into this `Extensions`.
+ ///
+ /// If a extension of this type already existed, it will
+ /// be returned.
+ pub(crate) fn insert<T: Send + Sync + 'static>(&mut self, val: T) -> Option<T> {
+ self.map
+ .insert(TypeId::of::<T>(), Box::new(val))
+ .and_then(|boxed| {
+ #[allow(warnings)]
+ {
+ (boxed as Box<Any + 'static>)
+ .downcast()
+ .ok()
+ .map(|boxed| *boxed)
+ }
+ })
+ }
+
+ /// Get a reference to a type previously inserted on this `Extensions`.
+ pub(crate) fn get<T: 'static>(&self) -> Option<&T> {
+ self.map
+ .get(&TypeId::of::<T>())
+ .and_then(|boxed| (&**boxed as &(dyn Any + 'static)).downcast_ref())
+ }
+
+ /// Get a mutable reference to a type previously inserted on this `Extensions`.
+ pub(crate) fn get_mut<T: 'static>(&mut self) -> Option<&mut T> {
+ self.map
+ .get_mut(&TypeId::of::<T>())
+ .and_then(|boxed| (&mut **boxed as &mut (dyn Any + 'static)).downcast_mut())
+ }
+
+ /// Remove a type from this `Extensions`.
+ ///
+ /// If a extension of this type existed, it will be returned.
+ pub(crate) fn remove<T: Send + Sync + 'static>(&mut self) -> Option<T> {
+ self.map.remove(&TypeId::of::<T>()).and_then(|boxed| {
+ #[allow(warnings)]
+ {
+ (boxed as Box<Any + 'static>)
+ .downcast()
+ .ok()
+ .map(|boxed| *boxed)
+ }
+ })
+ }
+
+ /// Clear the `ExtensionsInner` in-place, dropping any elements in the map but
+ /// retaining allocated capacity.
+ ///
+ /// This permits the hash map allocation to be pooled by the registry so
+ /// that future spans will not need to allocate new hashmaps.
+ #[cfg(any(test, feature = "registry"))]
+ pub(crate) fn clear(&mut self) {
+ self.map.clear();
+ }
+}
+
+impl fmt::Debug for ExtensionsInner {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("Extensions")
+ .field("len", &self.map.len())
+ .field("capacity", &self.map.capacity())
+ .finish()
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[derive(Debug, PartialEq)]
+ struct MyType(i32);
+
+ #[test]
+ fn test_extensions() {
+ let mut extensions = ExtensionsInner::new();
+
+ extensions.insert(5i32);
+ extensions.insert(MyType(10));
+
+ assert_eq!(extensions.get(), Some(&5i32));
+ assert_eq!(extensions.get_mut(), Some(&mut 5i32));
+
+ assert_eq!(extensions.remove::<i32>(), Some(5i32));
+ assert!(extensions.get::<i32>().is_none());
+
+ assert_eq!(extensions.get::<bool>(), None);
+ assert_eq!(extensions.get(), Some(&MyType(10)));
+ }
+
+ #[test]
+ fn clear_retains_capacity() {
+ let mut extensions = ExtensionsInner::new();
+ extensions.insert(5i32);
+ extensions.insert(MyType(10));
+ extensions.insert(true);
+
+ assert_eq!(extensions.map.len(), 3);
+ let prev_capacity = extensions.map.capacity();
+ extensions.clear();
+
+ assert_eq!(
+ extensions.map.len(),
+ 0,
+ "after clear(), extensions map should have length 0"
+ );
+ assert_eq!(
+ extensions.map.capacity(),
+ prev_capacity,
+ "after clear(), extensions map should retain prior capacity"
+ );
+ }
+
+ #[test]
+ fn clear_drops_elements() {
+ use std::sync::Arc;
+ struct DropMePlease(Arc<()>);
+ struct DropMeTooPlease(Arc<()>);
+
+ let mut extensions = ExtensionsInner::new();
+ let val1 = DropMePlease(Arc::new(()));
+ let val2 = DropMeTooPlease(Arc::new(()));
+
+ let val1_dropped = Arc::downgrade(&val1.0);
+ let val2_dropped = Arc::downgrade(&val2.0);
+ extensions.insert(val1);
+ extensions.insert(val2);
+
+ assert!(val1_dropped.upgrade().is_some());
+ assert!(val2_dropped.upgrade().is_some());
+
+ extensions.clear();
+ assert!(
+ val1_dropped.upgrade().is_none(),
+ "after clear(), val1 should be dropped"
+ );
+ assert!(
+ val2_dropped.upgrade().is_none(),
+ "after clear(), val2 should be dropped"
+ );
+ }
+}