@@ -38,18 +38,127 @@ use crate::{
38
38
CellId , CollectiblesSource , RawVc , ResolveTypeError , SharedReference , ShrinkToFit ,
39
39
} ;
40
40
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.
44
43
///
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` ]:
47
46
///
48
47
/// ```
49
48
/// let some_vc: Vc<T>;
50
49
/// let some_ref: ReadRef<T> = some_vc.await?;
51
50
/// some_ref.some_method_on_t();
52
51
/// ```
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
53
162
#[ must_use]
54
163
#[ derive( Serialize , Deserialize ) ]
55
164
#[ serde( transparent, bound = "" ) ]
0 commit comments