Skip to content

Commit

Permalink
modernize docs
Browse files Browse the repository at this point in the history
closes #229
  • Loading branch information
matklad committed May 23, 2023
1 parent 652015f commit 8c42266
Showing 1 changed file with 71 additions and 40 deletions.
111 changes: 71 additions & 40 deletions src/lib.rs
@@ -1,8 +1,10 @@
//! # Overview
//!
//! `once_cell` provides two new cell-like types, [`unsync::OnceCell`] and [`sync::OnceCell`]. A `OnceCell`
//! might store arbitrary non-`Copy` types, can be assigned to at most once and provides direct access
//! to the stored contents. The core API looks *roughly* like this (and there's much more inside, read on!):
//! `once_cell` provides two new cell-like types, [`unsync::OnceCell`] and
//! [`sync::OnceCell`]. A `OnceCell` might store arbitrary non-`Copy` types, can
//! be assigned to at most once and provides direct access to the stored
//! contents. The core API looks *roughly* like this (and there's much more
//! inside, read on!):
//!
//! ```rust,ignore
//! impl<T> OnceCell<T> {
Expand All @@ -12,11 +14,12 @@
//! }
//! ```
//!
//! Note that, like with [`RefCell`] and [`Mutex`], the `set` method requires only a shared reference.
//! Because of the single assignment restriction `get` can return a `&T` instead of `Ref<T>`
//! or `MutexGuard<T>`.
//! Note that, like with [`RefCell`] and [`Mutex`], the `set` method requires
//! only a shared reference. Because of the single assignment restriction `get`
//! can return a `&T` instead of `Ref<T>` or `MutexGuard<T>`.
//!
//! The `sync` flavor is thread-safe (that is, implements the [`Sync`] trait), while the `unsync` one is not.
//! The `sync` flavor is thread-safe (that is, implements the [`Sync`] trait),
//! while the `unsync` one is not.
//!
//! [`unsync::OnceCell`]: unsync/struct.OnceCell.html
//! [`sync::OnceCell`]: sync/struct.OnceCell.html
Expand Down Expand Up @@ -79,7 +82,8 @@
//! }
//! ```
//!
//! There are also the [`sync::Lazy`] and [`unsync::Lazy`] convenience types to streamline this pattern:
//! There are also the [`sync::Lazy`] and [`unsync::Lazy`] convenience types to
//! streamline this pattern:
//!
//! ```rust
//! use std::{sync::Mutex, collections::HashMap};
Expand Down Expand Up @@ -120,7 +124,8 @@
//! ```
//!
//! If you need a lazy field in a struct, you probably should use `OnceCell`
//! directly, because that will allow you to access `self` during initialization.
//! directly, because that will allow you to access `self` during
//! initialization.
//!
//! ```rust
//! use std::{fs, path::PathBuf};
Expand Down Expand Up @@ -156,7 +161,8 @@
//! }
//! ```
//!
//! This macro can be useful to avoid the "compile regex on every loop iteration" problem.
//! This macro can be useful to avoid the "compile regex on every loop
//! iteration" problem.
//!
//! ## Runtime `include_bytes!`
//!
Expand Down Expand Up @@ -243,7 +249,7 @@
//! let b = B::default();
//! a.b.init(&b);
//! b.a.init(&a);
//!
//!
//! let _a = &a.b.a.b.a;
//! }
//! ```
Expand All @@ -262,23 +268,28 @@
//! |`Mutex<T>` | `MutexGuard<T>` | may deadlock at runtime, may block the thread |
//! |`sync::OnceCell<T>` | `&T` | assignable only once, may block the thread |
//!
//! Technically, calling `get_or_init` will also cause a panic or a deadlock if it recursively calls
//! itself. However, because the assignment can happen only once, such cases should be more rare than
//! equivalents with `RefCell` and `Mutex`.
//! Technically, calling `get_or_init` will also cause a panic or a deadlock if
//! it recursively calls itself. However, because the assignment can happen only
//! once, such cases should be more rare than equivalents with `RefCell` and
//! `Mutex`.
//!
//! # Minimum Supported `rustc` Version
//!
//! This crate's minimum supported `rustc` version is `1.56.0`.
//!
//! If only the `std` feature is enabled, MSRV will be updated conservatively, supporting at least latest 8 versions of the compiler.
//! When using other features, like `parking_lot`, MSRV might be updated more frequently, up to the latest stable.
//! In both cases, increasing MSRV is *not* considered a semver-breaking change.
//! If only the `std` feature is enabled, MSRV will be updated conservatively,
//! supporting at least latest 8 versions of the compiler. When using other
//! features, like `parking_lot`, MSRV might be updated more frequently, up to
//! the latest stable. In both cases, increasing MSRV is *not* considered a
//! semver-breaking change.
//!
//! # Implementation details
//!
//! The implementation is based on the [`lazy_static`](https://github.com/rust-lang-nursery/lazy-static.rs/)
//! and [`lazy_cell`](https://github.com/indiv0/lazycell/) crates and [`std::sync::Once`]. In some sense,
//! `once_cell` just streamlines and unifies those APIs.
//! The implementation is based on the
//! [`lazy_static`](https://github.com/rust-lang-nursery/lazy-static.rs/) and
//! [`lazy_cell`](https://github.com/indiv0/lazycell/) crates and
//! [`std::sync::Once`]. In some sense, `once_cell` just streamlines and unifies
//! those APIs.
//!
//! To implement a sync flavor of `OnceCell`, this crates uses either a custom
//! re-implementation of `std::sync::Once` or `parking_lot::Mutex`. This is
Expand All @@ -292,46 +303,66 @@
//!
//! # F.A.Q.
//!
//! **Should I use lazy_static or once_cell?**
//! **Should I use the sync or unsync flavor?**
//!
//! To the first approximation, `once_cell` is both more flexible and more convenient than `lazy_static`
//! and should be preferred.
//! Because Rust compiler checks thread safety for you, it's impossible to
//! accidentally use `unsync` where `sync` is required. So, use `unsync` in
//! single-threaded code and `sync` in multi-threaded. It's easy to switch
//! between the two if code becomes multi-threaded later.
//!
//! Unlike `once_cell`, `lazy_static` supports spinlock-based implementation of blocking which works with
//! `#![no_std]`.
//! At the moment, `unsync` has an additional benefit that reentrant
//! initialization causes a panic, which might be easier to debug than a
//! deadlock.
//!
//! `lazy_static` has received significantly more real world testing, but `once_cell` is also a widely
//! used crate.
//! **Does this crate support async?**
//!
//! **Should I use the sync or unsync flavor?**
//! No, but you can use
//! [`async_once_cell`](https://crates.io/crates/async_once_cell) instead.
//!
//! Because Rust compiler checks thread safety for you, it's impossible to accidentally use `unsync` where
//! `sync` is required. So, use `unsync` in single-threaded code and `sync` in multi-threaded. It's easy
//! to switch between the two if code becomes multi-threaded later.
//! **Does this crate support `no_std`?**
//!
//! At the moment, `unsync` has an additional benefit that reentrant initialization causes a panic, which
//! might be easier to debug than a deadlock.
//! Yes, but with caveats. `OnceCell` is a synchronization primitive which
//! _semantically_ relies on blocking. `OnceCell` guarantees that at most one
//! `f` will be called to compute the value. If two threads of execution call
//! `get_or_init` concurrently, one of them has to wait.
//!
//! **Does this crate support async?**
//! Waiting fundamentally requires OS support. Execution environment needs to
//! understand who waits on whom to prevent deadlocks due to priority inversion.
//! You _could_ make code to compile by blindly using pure spinlocks, but the
//! runtime behavior would be subtly wrong.
//!
//! No, but you can use [`async_once_cell`](https://crates.io/crates/async_once_cell) instead.
//! Given these constraints, `once_cell` provides the following options:
//!
//! - The `race` module provides similar, but distinct synchronization primitive
//! which is compatible with `no_std`. With `race`, the `f` function can be
//! called multiple times by different threads, but only one thread will win
//! to install the value.
//! - `critical-section` feature (with a `-`, not `_`) uses `critical_section`
//! to implement blocking.
//!
//! **Can I bring my own mutex?**
//!
//! There is [generic_once_cell](https://crates.io/crates/generic_once_cell) to allow just that.
//! There is [generic_once_cell](https://crates.io/crates/generic_once_cell) to
//! allow just that.
//!
//! **Should I use `std::cell::OnceCell`, `once_cell`, or `lazy_static`?**
//!
//! If you can use `std` version (your MSRV is at least 1.70, and you don't need
//! extra features `once_cell` provides), use `std`. Otherwise, use `once_cell`.
//! Don't use `lazy_static`.
//!
//! # Related crates
//!
//! * Most of this crate's functionality is available in `std` starting with
//! Rust 1.70. See `std::cell::OnceCell` and `std::sync::OnceLock`.
//! * [double-checked-cell](https://github.com/niklasf/double-checked-cell)
//! * [lazy-init](https://crates.io/crates/lazy-init)
//! * [lazycell](https://crates.io/crates/lazycell)
//! * [mitochondria](https://crates.io/crates/mitochondria)
//! * [lazy_static](https://crates.io/crates/lazy_static)
//! * [async_once_cell](https://crates.io/crates/async_once_cell)
//! * [generic_once_cell](https://crates.io/crates/generic_once_cell) (bring your own mutex)
//!
//! Most of this crate's functionality is available in `std` in nightly Rust.
//! See the [tracking issue](https://github.com/rust-lang/rust/issues/74465).
//! * [generic_once_cell](https://crates.io/crates/generic_once_cell) (bring
//! your own mutex)

#![cfg_attr(not(feature = "std"), no_std)]

Expand Down

0 comments on commit 8c42266

Please sign in to comment.