Skip to content

Commit

Permalink
core: remove vendored lazy_static on no-std (#2173)
Browse files Browse the repository at this point in the history
Currently, `no_std` targets use a vendored version of `lazy_static` that
uses the `spin` crate's `Once` type, while the `std` target uses the
`once_cell` crate's `Lazy` type. This is unfortunate, as the
`lazy_static` macro has a different interface from the `Lazy` cell type.
This increases the amount of code that differs based on whether or not
`std` is enabled.

This branch removes the vendored `lazy_static` macro and replaces it
with a reimplementation of `once_cell::sync::Lazy` that uses
`spin::Once` rather than `once_cell::sync::OnceCell` as the inner "once
type". Now, all code can be written against a `Lazy` struct with the
same interface, regardless of whether or not `std` is enabled.

Signed-off-by: Eliza Weisman <eliza@buoyant.io>
  • Loading branch information
hawkw committed Jun 22, 2022
1 parent 67cfb5f commit f7966bd
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 164 deletions.
13 changes: 3 additions & 10 deletions tracing-core/src/callsite.rs
Expand Up @@ -111,6 +111,7 @@ use crate::stdlib::{
};
use crate::{
dispatcher::Dispatch,
lazy::Lazy,
metadata::{LevelFilter, Metadata},
subscriber::Interest,
};
Expand Down Expand Up @@ -253,14 +254,7 @@ static CALLSITES: Callsites = Callsites {

static DISPATCHERS: Dispatchers = Dispatchers::new();

#[cfg(feature = "std")]
static LOCKED_CALLSITES: once_cell::sync::Lazy<Mutex<Vec<&'static dyn Callsite>>> =
once_cell::sync::Lazy::new(Default::default);

#[cfg(not(feature = "std"))]
crate::lazy_static! {
static ref LOCKED_CALLSITES: Mutex<Vec<&'static dyn Callsite>> = Mutex::new(Vec::new());
}
static LOCKED_CALLSITES: Lazy<Mutex<Vec<&'static dyn Callsite>>> = Lazy::new(Default::default);

struct Callsites {
list_head: AtomicPtr<DefaultCallsite>,
Expand Down Expand Up @@ -514,8 +508,7 @@ mod private {

#[cfg(feature = "std")]
mod dispatchers {
use crate::dispatcher;
use once_cell::sync::Lazy;
use crate::{dispatcher, lazy::Lazy};
use std::sync::{
atomic::{AtomicBool, Ordering},
RwLock, RwLockReadGuard, RwLockWriteGuard,
Expand Down
76 changes: 76 additions & 0 deletions tracing-core/src/lazy.rs
@@ -0,0 +1,76 @@
#[cfg(feature = "std")]
pub(crate) use once_cell::sync::Lazy;

#[cfg(not(feature = "std"))]
pub(crate) use self::spin::Lazy;

#[cfg(not(feature = "std"))]
mod spin {
//! This is the `once_cell::sync::Lazy` type, but modified to use our
//! `spin::Once` type rather than `OnceCell`. This is used to replace
//! `once_cell::sync::Lazy` on `no-std` builds.
use crate::spin::Once;
use core::{cell::Cell, fmt, ops::Deref};

/// Re-implementation of `once_cell::sync::Lazy` on top of `spin::Once`
/// rather than `OnceCell`.
///
/// This is used when the standard library is disabled.
pub(crate) struct Lazy<T, F = fn() -> T> {
cell: Once<T>,
init: Cell<Option<F>>,
}

impl<T: fmt::Debug, F> fmt::Debug for Lazy<T, F> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Lazy")
.field("cell", &self.cell)
.field("init", &"..")
.finish()
}
}

// We never create a `&F` from a `&Lazy<T, F>` so it is fine to not impl
// `Sync` for `F`. We do create a `&mut Option<F>` in `force`, but this is
// properly synchronized, so it only happens once so it also does not
// contribute to this impl.
unsafe impl<T, F: Send> Sync for Lazy<T, F> where Once<T>: Sync {}
// auto-derived `Send` impl is OK.

impl<T, F> Lazy<T, F> {
/// Creates a new lazy value with the given initializing function.
pub(crate) const fn new(init: F) -> Lazy<T, F> {
Lazy {
cell: Once::new(),
init: Cell::new(Some(init)),
}
}
}

impl<T, F: FnOnce() -> T> Lazy<T, F> {
/// Forces the evaluation of this lazy value and returns a reference to
/// the result.
///
/// This is equivalent to the `Deref` impl, but is explicit.
pub(crate) fn force(this: &Lazy<T, F>) -> &T {
this.cell.call_once(|| match this.init.take() {
Some(f) => f(),
None => panic!("Lazy instance has previously been poisoned"),
})
}
}

impl<T, F: FnOnce() -> T> Deref for Lazy<T, F> {
type Target = T;
fn deref(&self) -> &T {
Lazy::force(self)
}
}

impl<T: Default> Default for Lazy<T> {
/// Creates a new lazy value using `Default` as the initializing function.
fn default() -> Lazy<T> {
Lazy::new(T::default)
}
}
}
26 changes: 0 additions & 26 deletions tracing-core/src/lazy_static/LICENSE

This file was deleted.

30 changes: 0 additions & 30 deletions tracing-core/src/lazy_static/core_lazy.rs

This file was deleted.

89 changes: 0 additions & 89 deletions tracing-core/src/lazy_static/mod.rs

This file was deleted.

5 changes: 1 addition & 4 deletions tracing-core/src/lib.rs
Expand Up @@ -254,10 +254,7 @@ macro_rules! metadata {
};
}

// Facade module: `no_std` uses spinlocks, `std` uses the mutexes in the standard library
#[cfg(not(feature = "std"))]
#[macro_use]
mod lazy_static;
pub(crate) mod lazy;

// Trimmed-down vendored version of spin 0.5.2 (0387621)
// Dependency of no_std lazy_static, not required in a std build
Expand Down
10 changes: 5 additions & 5 deletions tracing-core/src/stdlib.rs
Expand Up @@ -64,11 +64,11 @@ mod no_std {
}

impl<T> Mutex<T> {
pub(crate) fn new(data: T) -> Self {
Self {
inner: crate::spin::Mutex::new(data),
}
}
// pub(crate) fn new(data: T) -> Self {
// Self {
// inner: crate::spin::Mutex::new(data),
// }
// }

pub(crate) fn lock(&self) -> Result<MutexGuard<'_, T>, ()> {
Ok(self.inner.lock())
Expand Down

0 comments on commit f7966bd

Please sign in to comment.