Skip to content

[utils]: Clean up or remove LazyCache #3535

@iostat

Description

@iostat

Follow-up to #3522

From the start of src/utils/lazy_cache.rs:

#![allow(unsafe_code)]
//! Polyfill of the `LazyLock` type in the std library as of Rust 1.80.
//!
//! The current file should be deleted soon, as we now support Rust 1.81 and
//! use the official `LazyLock`, and [`LazyCache`] as a wrapper around `LazyLock`
//! to allow for custom serialization definitions.

We're on 1.90 now. Opening this as a follow-up to #3522.

  pub enum LazyCache<T: Send + Sync + 'static> {
      #[cfg(feature = "std")]
      Lazy(std::sync::LazyLock<T, Box<dyn FnOnce() -> T + Send + Sync>>),
      Preinit(T),
  }

Then the impl becomes trivial with no #[cfg] variants all over the place:

  impl<T: Send + Sync + 'static> LazyCache<T> {
      #[cfg(feature = "std")]
      pub fn new<F: FnOnce() -> T + Send + Sync + 'static>(f: F) -> Self {
          Self::Lazy(LazyLock::new(Box::new(f)))
      }

      pub fn preinit(value: T) -> Self {
          Self::Preinit(value)
      }

      pub fn get(&self) -> &T {
          match self {
              #[cfg(feature = "std")]
              Self::Lazy(lock) => lock,
              Self::Preinit(v) => v,
          }
      }
  }

What you gain:

  • Zero unsafe — LazyLock handles all the synchronization
  • No UnsafeCell, no Once, no manual Send/Sync impls
  • cfg only on the variant + match arm, not scattered across every field and method
  • try_initialize and the error types probably go away entirely — LazyLock panics propagate naturally, and try_get_or_err can just
    match on self.get() if T = Result<V, E>

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions