@@ -38,18 +38,127 @@ use crate::{
3838 CellId , CollectiblesSource , RawVc , ResolveTypeError , SharedReference , ShrinkToFit ,
3939} ;
4040
41- /// A Value Cell (`Vc` for short) is a reference to a memoized computation
42- /// result stored on the heap or in persistent cache, depending on the
43- /// Turbo Engine backend implementation.
41+ /// A "Value Cell" (`Vc` for short) is a reference to a memoized computation result stored on the
42+ /// heap or in persistent cache, depending on the Turbo Engine backend implementation.
4443///
45- /// In order to get a reference to the pointed value, you need to `.await` the
46- /// [`Vc <T>`] to get a [`ReadRef<T>`][crate::ReadRef ]:
44+ /// In order to get a reference to the pointed value, you need to `.await` the [`Vc<T>`] to get a
45+ /// [`ReadRef <T>`][`ReadRef` ]:
4746///
4847/// ```
4948/// let some_vc: Vc<T>;
5049/// let some_ref: ReadRef<T> = some_vc.await?;
5150/// some_ref.some_method_on_t();
5251/// ```
52+ ///
53+ /// `Vc`s are similar to a [`Future`] or a Promise with a few key differences:
54+ ///
55+ /// - The value pointed to by a `Vc` can be invalidated by changing dependencies or cache evicted,
56+ /// meaning that `await`ing a `Vc` multiple times can give different results. A [`ReadRef`] is
57+ /// snapshot of the underlying cell at a point in time.
58+ ///
59+ /// - Reading (`await`ing) `Vc`s causes the current task to be tracked a dependent of the `Vc`'s
60+ /// task or task cell. When the read task or task cell changes, the current task may be
61+ /// re-executed.
62+ ///
63+ /// - `Vc` types are always [`Copy`]. Most [`Future`]s are not. This works because `Vc`s are
64+ /// represented as a few ids or indicies into data structures managed by the `turbo-tasks`
65+ /// framework. `Vc` types are not reference counted, but do support [tracing] for a hypothetical
66+ /// (unimplemented) garbage collector.
67+ ///
68+ /// - Unlike futures (but like promises), the work that a `Vc` represents [begins execution even if
69+ /// the `Vc` is not `await`ed](#execution-model).
70+ ///
71+ /// For a more in-depth explanation of the concepts behind value cells, [refer to the Turbopack
72+ /// book][book-cells].
73+ ///
74+ ///
75+ /// ## Subtypes
76+ ///
77+ /// There are a couple of "subtypes" of `Vc`. These can both be cheaply converted back into a `Vc`.
78+ ///
79+ /// - **[`ResolvedVc`]:** A reference to a cell constructed within a task, as part of a [`Vc::cell`]
80+ /// or `value_type.cell()` constructor. As the cell has been constructed at least once, the
81+ /// concrete type of the cell is known (allowing [downcasting][ResolvedVc::try_downcast]). This is
82+ /// stored as a combination of a task id, a type id, and a cell id.
83+ ///
84+ /// - **[`OperationVc`]:** The synchronous return value of a [`turbo_tasks::function`]. Internally,
85+ /// this is stored using a task id. Exact type information of trait types (i.e. `Vc<Box<dyn
86+ /// Trait>>`) is not known because the function may not have finished execution yet. Operations
87+ /// must first be [`connected`][OperationVc::connect]ed before being read.
88+ ///
89+ /// [`ResolvedVc`] is almost always preferred over the more awkward [`OperationVc`] API, but
90+ /// [`OperationVc`] can be useful inside of [`State`] or when dealing with [collectibles].
91+ ///
92+ /// In addition to these potentially-explicit representations of a `Vc`, there's another internal
93+ /// representation of a `Vc`, known as a "Local `Vc`".
94+ ///
95+ /// - **Local Operation or Cell:** Same as [`ResolvedVc`] or [`OperationVc`], but these values are
96+ /// stored in task-local state that is freed after their parent non-local task exits. These values
97+ /// are sometimes created when calling a [`turbo_tasks::function`] as an optimization. [Converting
98+ /// a local `Vc` to a `ResolvedVc`][Vc::to_resolved] will construct a new
99+ /// [non-local][NonLocalValue] cell.
100+ ///
101+ /// These many representations are stored internally using a type-erased [`RawVc`]. Type erasure
102+ /// reduces the [monomorphization] (and therefore binary size and compilation time) required to
103+ /// support `Vc` and its subtypes.
104+ ///
105+ /// <div class="warning">
106+ /// <p>
107+ /// Local <code>Vc</code>s are not valid outside of their parent task, so they must be implicitly
108+ /// (e.g. as an argument or return type) or explicitly (e.g. via <a
109+ /// href="#method.to_resolved"><code>Vc::to_resolved</code></a>) be converted to a non-local <a
110+ /// href="struct.ResolvedVc.html"><code>ResolvedVc</code></a> or <a
111+ /// href="struct.VcOperation.html"><code>VcOperation</code></a> before crossing task boundaries.
112+ /// </p>
113+ /// <p>
114+ /// For this reason, <code>Vc</code> types (which are potentially local) will be disallowed as
115+ /// fields in <a href="attr.value.html"><code>turbo_tasks::value</code></a>s in the future.
116+ /// </p>
117+ /// </div>
118+ ///
119+ /// | | Representation? | [Non-Local?] | Equality? | Can be Downcast? |
120+ /// |-----------------|-----------------------------|--------------|-------------------------|----------------------------|
121+ /// | [`Vc`] | One of many | ⚠️ Maybe | ❌ Not recommended | ⚠️ After resolution |
122+ /// | [`ResolvedVc`] | Task Id + Type Id + Cell Id | ✅ Yes | ✅ Yes, [see docs][rvc] | ✅ [Yes, cheaply][resolve] |
123+ /// | [`OperationVc`] | Task Id | ✅ Yes | ✅ Yes, [see docs][ovc] | ⚠️ After resolution |
124+ ///
125+ /// [Non-Local]: NonLocalValue
126+ /// [rvc]: ResolvedVc
127+ /// [ovc]: ResolvedVc
128+ /// [resolve]: ResolvedVc::try_downcast
129+ ///
130+ /// See the documentation for [`ResolvedVc`] and [`OperationVc`] for more details about these
131+ /// subtypes.
132+ ///
133+ ///
134+ /// ## Execution Model
135+ ///
136+ /// While task functions are expected to be side-effect free, their execution behavior is still
137+ /// important for performance reasons, or to code using [collectibles] to represent issues or
138+ /// side-effects.
139+ ///
140+ /// Function calls are neither "eager", nor "lazy". Even if not awaited, they are guaranteed to
141+ /// execute (potentially emitting collectibles) before the root task finishes or before the
142+ /// completion of any strongly consistent read containing their call. However, the exact point when
143+ /// that execution begins is an implementation detail. Functions may execute more than once due to
144+ /// dirty task invalidation.
145+ ///
146+ ///
147+ /// ## Equality & Hashing
148+ ///
149+ /// Because `Vc`s can be equivalent but have different representation, it's not recommended to
150+ /// compare `Vc`s by equality. Instead, you should convert a `Vc` to an explicit subtype first
151+ /// (likely [`ResolvedVc`]). Future versions of `Vc` may not implement [`Eq`], [`PartialEq`], or
152+ /// [`Hash`].
153+ ///
154+ ///
155+ /// [tracing]: crate::trace::TraceRawVcs
156+ /// [`ReadRef`]: crate::ReadRef
157+ /// [`turbo_tasks::function`]: crate::function
158+ /// [monomorphization]: https://doc.rust-lang.org/book/ch10-01-syntax.html#performance-of-code-using-generics
159+ /// [`State`]: crate::State
160+ /// [book-cells]: https://turbopack-rust-docs.vercel.sh/turbo-engine/cells.html
161+ /// [collectibles]: CollectiblesSource
53162#[ must_use]
54163#[ derive( Serialize , Deserialize ) ]
55164#[ serde( transparent, bound = "" ) ]
0 commit comments