core: remove vendored lazy_static on no-std (#2173)

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>
This commit is contained in:
Eliza Weisman 2022-06-22 15:43:25 -07:00 committed by GitHub
parent 67cfb5f352
commit f7966bde76
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 85 additions and 164 deletions

View File

@ -111,6 +111,7 @@ use crate::stdlib::{
};
use crate::{
dispatcher::Dispatch,
lazy::Lazy,
metadata::{LevelFilter, Metadata},
subscriber::Interest,
};
@ -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>,
@ -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,

76
tracing-core/src/lazy.rs Normal file
View File

@ -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)
}
}
}

View File

@ -1,26 +0,0 @@
Copyright (c) 2010 The Rust Project Developers
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

View File

@ -1,30 +0,0 @@
// Copyright 2016 lazy-static.rs Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
use crate::spin::Once;
pub(crate) struct Lazy<T: Sync>(Once<T>);
impl<T: Sync> Lazy<T> {
pub(crate) const INIT: Self = Lazy(Once::INIT);
#[inline(always)]
pub(crate) fn get<F>(&'static self, builder: F) -> &T
where
F: FnOnce() -> T,
{
self.0.call_once(builder)
}
}
#[macro_export]
#[doc(hidden)]
macro_rules! __lazy_static_create {
($NAME:ident, $T:ty) => {
static $NAME: $crate::lazy_static::lazy::Lazy<$T> = $crate::lazy_static::lazy::Lazy::INIT;
};
}

View File

@ -1,89 +0,0 @@
// Copyright 2016 lazy-static.rs Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
/*!
A macro for declaring lazily evaluated statics.
Using this macro, it is possible to have `static`s that require code to be
executed at runtime in order to be initialized.
This includes anything requiring heap allocations, like vectors or hash maps,
as well as anything that requires function calls to be computed.
*/
#[path = "core_lazy.rs"]
pub(crate) mod lazy;
#[doc(hidden)]
pub(crate) use core::ops::Deref as __Deref;
#[macro_export]
#[doc(hidden)]
macro_rules! __lazy_static_internal {
// optional visibility restrictions are wrapped in `()` to allow for
// explicitly passing otherwise implicit information about private items
($(#[$attr:meta])* ($($vis:tt)*) static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => {
$crate::__lazy_static_internal!(@MAKE TY, $(#[$attr])*, ($($vis)*), $N);
$crate::__lazy_static_internal!(@TAIL, $N : $T = $e);
$crate::lazy_static!($($t)*);
};
(@TAIL, $N:ident : $T:ty = $e:expr) => {
impl $crate::lazy_static::__Deref for $N {
type Target = $T;
fn deref(&self) -> &$T {
#[inline(always)]
fn __static_ref_initialize() -> $T { $e }
#[inline(always)]
fn __stability() -> &'static $T {
$crate::__lazy_static_create!(LAZY, $T);
LAZY.get(__static_ref_initialize)
}
__stability()
}
}
impl $crate::lazy_static::LazyStatic for $N {
fn initialize(lazy: &Self) {
let _ = &**lazy;
}
}
};
// `vis` is wrapped in `()` to prevent parsing ambiguity
(@MAKE TY, $(#[$attr:meta])*, ($($vis:tt)*), $N:ident) => {
#[allow(missing_copy_implementations)]
#[allow(non_camel_case_types)]
#[allow(dead_code)]
$(#[$attr])*
$($vis)* struct $N {__private_field: ()}
#[doc(hidden)]
$($vis)* static $N: $N = $N {__private_field: ()};
};
() => ()
}
#[macro_export]
#[doc(hidden)]
macro_rules! lazy_static {
($(#[$attr:meta])* static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => {
// use `()` to explicitly forward the information about private items
$crate::__lazy_static_internal!($(#[$attr])* () static ref $N : $T = $e; $($t)*);
};
($(#[$attr:meta])* pub static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => {
$crate::__lazy_static_internal!($(#[$attr])* (pub) static ref $N : $T = $e; $($t)*);
};
($(#[$attr:meta])* pub ($($vis:tt)+) static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => {
$crate::__lazy_static_internal!($(#[$attr])* (pub ($($vis)+)) static ref $N : $T = $e; $($t)*);
};
() => ()
}
/// Support trait for enabling a few common operation on lazy static values.
///
/// This is implemented by each defined lazy static, and
/// used by the free functions in this crate.
pub(crate) trait LazyStatic {
#[doc(hidden)]
fn initialize(lazy: &Self);
}

View File

@ -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

View File

@ -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())