Skip to content

Commit

Permalink
docs(turbopack): Better document the Vc type, with references to Reso…
Browse files Browse the repository at this point in the history
…lvedVc and VcOperation
  • Loading branch information
bgw committed Nov 8, 2024
1 parent 988e6fa commit 1bbe1da
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 18 deletions.
30 changes: 17 additions & 13 deletions turbopack/crates/turbo-tasks/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,29 @@
//! execution.
//!
//! It defines 4 primitives:
//! - functions: Unit of execution, invalidation and reexecution.
//! - values: Data created, stored and returned by functions.
//! - traits: Traits that define a set of functions on values.
//! - collectibles: Values emitted in functions that bubble up the call graph and can be collected
//! in parent functions.
//! - **[Functions][macro@crate::function]:** Units of execution, invalidation, and reexecution.
//! - **[Values][macro@crate::value]:** Data created, stored, and returned by functions.
//! - **[Traits][macro@crate::value_trait]:** Traits that define a set of functions on values.
//! - **[Collectibles][crate::TurboTasks::emit_collectible]:** Values emitted in functions that
//! bubble up the call graph and can be collected in parent functions.
//!
//! It also defines some derived elements from that:
//! - cells: The locations in functions where values are stored. The content of a cell can change
//! after the reexecution of a function.
//! - Vcs: A reference to a cell in a function or a return value of a function.
//! - task: An instance of a function together with its arguments.
//! - **[Tasks][book-tasks]:** An instance of a function together with its arguments.
//! - **[Cells][book-cells]:** The locations associated with tasks where values are stored. The
//! contents of a cell can change after the reexecution of a function.
//! - **[`Vc`s ("Value Cells")][Vc]:** A reference to a cell or a return value of a function.
//!
//! A Vc can be read to get a read-only reference to the stored data.
//! A [`Vc`] can be read to get [a read-only reference][ReadRef] to the stored data, representing a
//! snapshot of that cell at that point in time.
//!
//! On execution of functions, turbo-tasks will track which Vcs are read. Once
//! any of these change, turbo-tasks will invalidate the task created from the
//! function's execution and it will eventually be scheduled and reexecuted.
//! On execution of functions, `turbo-tasks` will track which [`Vc`]s are read. Once any of these
//! change, `turbo-tasks` will invalidate the task created from the function's execution and it will
//! eventually be scheduled and reexecuted.
//!
//! Collectibles go through a similar process.
//!
//! [book-cells]: https://turbopack-rust-docs.vercel.sh/turbo-engine/cells.html
//! [book-tasks]: https://turbopack-rust-docs.vercel.sh/turbo-engine/tasks.html

#![feature(trivial_bounds)]
#![feature(min_specialization)]
Expand Down
9 changes: 9 additions & 0 deletions turbopack/crates/turbo-tasks/src/raw_vc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,15 @@ impl Display for CellId {
}
}

/// A type-erased representation of [`Vc`].
///
/// Type erasure reduces the [monomorphization] (and therefore binary size and compilation time)
/// required to support `Vc`.
///
/// This type is heavily used within the [`Backend`][crate::backend::Backend] trait, but should
/// otherwise be treated as an internal implementation detail of `turbo-tasks`.
///
/// [monomorphization]: https://doc.rust-lang.org/book/ch10-01-syntax.html#performance-of-code-using-generics
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum RawVc {
TaskOutput(TaskId),
Expand Down
90 changes: 85 additions & 5 deletions turbopack/crates/turbo-tasks/src/vc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,98 @@ use crate::{
CellId, RawVc, ResolveTypeError, SharedReference, ShrinkToFit,
};

/// A Value Cell (`Vc` for short) is a reference to a memoized computation
/// result stored on the heap or in persistent cache, depending on the
/// Turbo Engine backend implementation.
/// A "Value Cell" (`Vc` for short) is a reference to a memoized computation result stored on the
/// heap or in persistent cache, depending on the Turbo Engine backend implementation.
///
/// In order to get a reference to the pointed value, you need to `.await` the
/// [`Vc<T>`] to get a [`ReadRef<T>`][crate::ReadRef]:
/// In order to get a reference to the pointed value, you need to `.await` the [`Vc<T>`] to get a
/// [`ReadRef<T>`][`ReadRef`]:
///
/// ```
/// let some_vc: Vc<T>;
/// let some_ref: ReadRef<T> = some_vc.await?;
/// some_ref.some_method_on_t();
/// ```
///
/// `Vc`s are similar to a [`Future`] or a Promise with a few key differences:
///
/// - Unlike futures (but like promises), the work that a `Vc` represents begins execution
/// immediately, even if the `Vc` is not `await`ed.
///
/// - The value pointed to by a `Vc` can be invalidated by changing dependencies or cache evicted,
/// meaning that `await`ing a `Vc` multiple times can give different results. A [`ReadRef`] is
/// snapshot of the underlying cell at a point in time.
///
/// - Reading (`await`ing) `Vc`s causes the current task to be tracked a dependent of the `Vc`'s
/// task or task cell. When the read task or task cell changes, the current task may be
/// re-executed.
///
/// - `Vc` types are always [`Copy`]. Most [`Future`]s are not. This works because `Vc`s are
/// represented as a few ids or indicies into data structures managed by the `turbo-tasks`
/// framework. `Vc` types are not reference counted, but do support [tracing] for a hypothetical
/// (unimplemented) garbage collector.
///
/// Internally, a `Vc` can have a number of representations:
///
/// - **Operation:** The synchronous return value of a [`turbo_tasks::function`]. Internally, this
/// is stored using a task id. Exact type information of trait types (i.e. `Vc<Box<dyn Trait>>`)
/// is not known because the function may not have finished execution yet. For this reason,
/// operations cannot be downcast or sidecast without first being resolved.
///
/// - **Resolved Cell:** A reference to a cell constructed within a task, as part of a [`Vc::cell`]
/// or `value_type.cell()` constructor. As the cell has been constructed at least once, the
/// concrete type of the cell is known. This is stored as a combination of a task id, a type id,
/// and a cell id.
///
/// - **Local Operation or Cell:** Same as above, but these values are stored in task-local state
/// that is freed after their parent non-local task exits. These values are sometimes created when
/// calling a [`turbo_tasks::function`].
///
/// <div class="warning">
/// <p>
/// Local <code>Vc</code>s are not valid outside of their parent task, so they must be implicitly
/// (e.g. as an argument or return type) or explicitly (e.g. via <a
/// href="#method.to_resolved"><code>Vc::to_resolved</code></a>) be converted to a non-local <a
/// href="struct.ResolvedVc.html"><code>ResolvedVc</code></a> or <a
/// href="struct.VcOperation.html"><code>VcOperation</code></a> before crossing task boundaries.
/// </p>
///
/// <p>
/// For this reason, <code>Vc</code> types (which are potentially local) will be disallowed as
/// fields in <a href="attr.value.html"><code>turbo_tasks::value</code></a>s in the future.
/// </p>
/// </div>
///
/// These internal representations are stored using a type-erased [`RawVc`]. Type erasure reduces
/// the [monomorphization] (and therefore binary size and compilation time) required to support
/// `Vc`.
///
/// Because `Vc`s can be equivalent but have different representation, it's not recommended to
/// compare `Vc`s by equality. Instead, you should convert a `Vc` to an explicit subtype first.
///
/// There are a couple of "subtypes" of `Vc`, both of which implement [`Deref<Target =
/// Vc<T>>`][Deref]:
///
/// | | Representation? | Non-Local? | Equality? | Can be Downcast? |
/// |-----------------|-----------------------------|------------|--------------------|---------------------|
/// | [`Vc`] | One of many | ⚠️ Maybe | ❌ Not recommended | ⚠️ After resolution |
/// | [`ResolvedVc`] | Task Id + Type Id + Cell Id | ✅ Yes | ✅ Yes | ✅ Yes |
/// | [`VcOperation`] | Task Id | ✅ Yes | ✅ Yes | ⚠️ After resolution |
///
/// [`ResolvedVc`] is typically preferred over [`VcOperation`], in part because any [`Vc`] can be
/// converted to a [`ResolvedVc`] using [`Vc::to_resolved`], but not every [`Vc`] can be converted
/// to a [`VcOperation`].
///
/// See the documentation for [`ResolvedVc`] and [`VcOperation`] for more details about these
/// subtypes.
///
/// For a more in-depth explanation of the concepts behind value cells, [refer to the Turbopack
/// book][book-cells].
///
/// [tracing]: crate::trace::TraceRawVcs
/// [`ReadRef`]: crate::ReadRef
/// [`turbo_tasks::function`]: crate::function
/// [monomorphization]: https://doc.rust-lang.org/book/ch10-01-syntax.html#performance-of-code-using-generics
/// [book-cells]: https://turbopack-rust-docs.vercel.sh/turbo-engine/cells.html
#[must_use]
#[derive(Serialize, Deserialize)]
#[serde(transparent, bound = "")]
Expand Down

0 comments on commit 1bbe1da

Please sign in to comment.