turbo_tasks/vc/mod.rs
1pub(crate) mod cast;
2mod cell_mode;
3pub(crate) mod default;
4mod local;
5pub(crate) mod operation;
6mod read;
7pub(crate) mod resolved;
8mod traits;
9
10use std::{
11 any::Any,
12 fmt::Debug,
13 future::{Future, IntoFuture},
14 hash::{Hash, Hasher},
15 marker::PhantomData,
16 ops::Deref,
17};
18
19use anyhow::Result;
20use serde::{Deserialize, Serialize};
21use shrink_to_fit::ShrinkToFit;
22
23pub use self::{
24 cast::{VcCast, VcValueTraitCast, VcValueTypeCast},
25 cell_mode::{VcCellMode, VcCellNewMode, VcCellSharedMode},
26 default::ValueDefault,
27 local::NonLocalValue,
28 operation::{OperationValue, OperationVc},
29 read::{ReadOwnedVcFuture, ReadVcFuture, VcDefaultRead, VcRead, VcTransparentRead},
30 resolved::ResolvedVc,
31 traits::{Dynamic, TypedForInput, Upcast, VcValueTrait, VcValueType},
32};
33use crate::{
34 CellId, RawVc, ResolveTypeError,
35 debug::{ValueDebug, ValueDebugFormat, ValueDebugFormatString},
36 registry,
37 trace::{TraceRawVcs, TraceRawVcsContext},
38};
39
40type VcReadTarget<T> = <<T as VcValueType>::Read as VcRead<T>>::Target;
41
42/// A "Value Cell" (`Vc` for short) is a reference to a memoized computation result stored on the
43/// heap or in persistent cache, depending on the Turbo Engine backend implementation.
44///
45/// In order to get a reference to the pointed value, you need to `.await` the [`Vc<T>`] to get a
46/// [`ReadRef<T>`][`ReadRef`]:
47///
48/// ```
49/// let some_vc: Vc<T>;
50/// let some_ref: ReadRef<T> = some_vc.await?;
51/// some_ref.some_method_on_t();
52/// ```
53///
54/// `Vc`s are similar to a [`Future`] or a Promise with a few key differences:
55///
56/// - The value pointed to by a `Vc` can be invalidated by changing dependencies or cache evicted,
57/// meaning that `await`ing a `Vc` multiple times can give different results. A [`ReadRef`] is
58/// snapshot of the underlying cell at a point in time.
59///
60/// - Reading (`await`ing) `Vc`s causes the current task to be tracked a dependent of the `Vc`'s
61/// task or task cell. When the read task or task cell changes, the current task may be
62/// re-executed.
63///
64/// - `Vc` types are always [`Copy`]. Most [`Future`]s are not. This works because `Vc`s are
65/// represented as a few ids or indicies into data structures managed by the `turbo-tasks`
66/// framework. `Vc` types are not reference counted, but do support [tracing] for a hypothetical
67/// (unimplemented) garbage collector.
68///
69/// - Unlike futures (but like promises), the work that a `Vc` represents [begins execution even if
70/// the `Vc` is not `await`ed](#execution-model).
71///
72/// For a more in-depth explanation of the concepts behind value cells, [refer to the Turbopack
73/// book][book-cells].
74///
75///
76/// ## Subtypes
77///
78/// There are a couple of explicit "subtypes" of `Vc`. These can both be cheaply converted back into
79/// a `Vc`.
80///
81/// - **[`ResolvedVc`]:** *(aka [`RawVc::TaskCell`])* A reference to a cell constructed within a
82/// task, as part of a [`Vc::cell`] or `value_type.cell()` constructor. As the cell has been
83/// constructed at least once, the concrete type of the cell is known (allowing
84/// [downcasting][ResolvedVc::try_downcast]). This is stored as a combination of a task id, a type
85/// id, and a cell id.
86///
87/// - **[`OperationVc`]:** *(aka [`RawVc::TaskOutput`])* The synchronous return value of a
88/// [`turbo_tasks::function`]. Internally, this is stored using a task id. Exact type information
89/// of trait types (i.e. `Vc<Box<dyn Trait>>`) is not known because the function may not have
90/// finished execution yet. [`OperationVc`]s must first be [`connect`][OperationVc::connect]ed
91/// before being read.
92///
93/// [`ResolvedVc`] is almost always preferred over the more awkward [`OperationVc`] API, but
94/// [`OperationVc`] can be useful when dealing with [collectibles], when you need to [read the
95/// result of a function with strong consistency][OperationVc::read_strongly_consistent], or with
96/// [`State`].
97///
98/// These many representations are stored internally using a type-erased [`RawVc`]. Type erasure
99/// reduces the [monomorphization] (and therefore binary size and compilation time) required to
100/// support `Vc` and its subtypes.
101///
102/// | | Representation | Equality | Downcasting | Strong Consistency | Collectibles | [Non-Local] |
103/// |-----------------|------------------------------------|-----------------|----------------------------|------------------------|-------------------|--------------|
104/// | [`Vc`] | [One of many][RawVc] | ❌ [Broken][eq] | ⚠️ After resolution | ❌ Eventual | ❌ No | ❌ [No][loc] |
105/// | [`ResolvedVc`] | [Task Id + Type Id + Cell Id][rtc] | ✅ Yes\* | ✅ [Yes, cheaply][resolve] | ❌ Eventual | ❌ No | ✅ Yes |
106/// | [`OperationVc`] | [Task Id][rto] | ✅ Yes\* | ⚠️ After resolution | ✅ [Supported][strong] | ✅ [Yes][collect] | ✅ Yes |
107///
108/// *\* see the type's documentation for details*
109///
110/// [Non-Local]: NonLocalValue
111/// [rtc]: RawVc::TaskCell
112/// [rto]: RawVc::TaskOutput
113/// [loc]: #optimization-local-outputs
114/// [eq]: #equality--hashing
115/// [resolve]: ResolvedVc::try_downcast
116/// [strong]: OperationVc::read_strongly_consistent
117/// [collect]: crate::CollectiblesSource
118///
119///
120/// ## Execution Model
121///
122/// While task functions are expected to be side-effect free, their execution behavior is still
123/// important for performance reasons, or to code using [collectibles] to represent issues or
124/// side-effects.
125///
126/// Function calls are neither "eager", nor "lazy". Even if not awaited, they are guaranteed to
127/// execute (potentially emitting collectibles) before the root task finishes or before the
128/// completion of any strongly consistent read containing their call. However, the exact point when
129/// that execution begins is an implementation detail. Functions may execute more than once due to
130/// dirty task invalidation.
131///
132///
133/// ## Equality & Hashing
134///
135/// Because `Vc`s can be equivalent but have different representation, it's not recommended to
136/// compare `Vc`s by equality. Instead, you should convert a `Vc` to an explicit subtype first
137/// (likely [`ResolvedVc`]). Future versions of `Vc` may not implement [`Eq`], [`PartialEq`], or
138/// [`Hash`].
139///
140///
141/// ## Optimization: Local Outputs
142///
143/// In addition to the potentially-explicit "resolved" and "operation" representations of a `Vc`,
144/// there's another internal representation of a `Vc`, known as a "Local `Vc`", or
145/// [`RawVc::LocalOutput`].
146///
147/// This is a special case of the synchronous return value of a [`turbo_tasks::function`] when some
148/// of its arguments have not yet been resolved. These are stored in task-local state that is freed
149/// after their parent non-local task exits.
150///
151/// We prevent potentially-local `Vc`s from escaping the lifetime of a function using the
152/// [`NonLocalValue`] marker trait alongside some fallback runtime checks. We do this to avoid some
153/// ergonomic challenges that would come from using lifetime annotations with `Vc`.
154///
155///
156/// [tracing]: crate::trace::TraceRawVcs
157/// [`ReadRef`]: crate::ReadRef
158/// [`turbo_tasks::function`]: crate::function
159/// [monomorphization]: https://doc.rust-lang.org/book/ch10-01-syntax.html#performance-of-code-using-generics
160/// [`State`]: crate::State
161/// [book-cells]: https://turbopack-rust-docs.vercel.sh/turbo-engine/cells.html
162/// [collectibles]: crate::CollectiblesSource
163#[must_use]
164#[derive(Serialize, Deserialize)]
165#[serde(transparent, bound = "")]
166#[repr(transparent)]
167pub struct Vc<T>
168where
169 T: ?Sized,
170{
171 pub(crate) node: RawVc,
172 #[doc(hidden)]
173 pub(crate) _t: PhantomData<T>,
174}
175
176/// This only exists to satisfy the Rust type system. However, this struct can
177/// never actually be instantiated, as dereferencing a `Vc<T>` will result in a
178/// linker error. See the implementation of `Deref` for `Vc<T>`.
179pub struct VcDeref<T>
180where
181 T: ?Sized,
182{
183 _t: PhantomData<T>,
184}
185
186macro_rules! do_not_use_or_you_will_be_fired {
187 ($($name:ident)*) => {
188 impl<T> VcDeref<T>
189 where
190 T: ?Sized,
191 {
192 $(
193 #[doc(hidden)]
194 #[allow(unused)]
195 #[allow(clippy::wrong_self_convention)]
196 #[deprecated = "This is not the method you are looking for."]
197 pub fn $name(self) {}
198 )*
199 }
200 };
201}
202
203// Hide raw pointer methods on `Vc<T>`. This is an artifact of having
204// implement `Deref<Target = *const T>` on `Vc<T>` for `arbitrary_self_types` to
205// do its thing. This can be removed once the `Receiver` trait no longer depends
206// on `Deref`.
207do_not_use_or_you_will_be_fired!(
208 add
209 addr
210 align_offset
211 as_mut
212 as_mut_ptr
213 as_ptr
214 as_ref
215 as_uninit_mut
216 as_uninit_ref
217 as_uninit_slice
218 as_uninit_slice_mut
219 byte_add
220 byte_offset
221 byte_offset_from
222 byte_sub
223 cast
224 cast_const
225 cast_mut
226 copy_from
227 copy_from_nonoverlapping
228 copy_to
229 copy_to_nonoverlapping
230 drop_in_place
231 expose_addr
232 from_bits
233 get_unchecked
234 get_unchecked_mut
235 guaranteed_eq
236 guaranteed_ne
237 is_aligned
238 is_aligned_to
239 is_empty
240 is_null
241 len
242 map_addr
243 mask
244 offset
245 offset_from
246 read
247 read_unaligned
248 read_volatile
249 replace
250 split_at_mut
251 split_at_mut_unchecked
252 sub
253 sub_ptr
254 swap
255 to_bits
256 to_raw_parts
257 with_addr
258 with_metadata_of
259 wrapping_add
260 wrapping_byte_add
261 wrapping_byte_offset
262 wrapping_byte_sub
263 wrapping_offset
264 wrapping_sub
265 write
266 write_bytes
267 write_unaligned
268 write_volatile
269);
270
271// Call this macro for all the applicable methods above:
272
273#[doc(hidden)]
274impl<T> Deref for VcDeref<T>
275where
276 T: ?Sized,
277{
278 // `*const T` or `*mut T` would be enough here, but from an abundance of
279 // caution, we use `*const *mut *const T` to make sure there will never be an
280 // applicable method.
281 type Target = *const *mut *const T;
282
283 fn deref(&self) -> &Self::Target {
284 unsafe extern "C" {
285 #[link_name = "\n\nERROR: you tried to dereference a `Vc<T>`\n"]
286 fn trigger() -> !;
287 }
288
289 unsafe { trigger() };
290 }
291}
292
293// This is the magic that makes `Vc<T>` accept `self: Vc<Self>` methods through
294// `arbitrary_self_types`, while not allowing any other receiver type:
295// * `Vc<T>` dereferences to `*const *mut *const T`, which means that it is valid under the
296// `arbitrary_self_types` rules.
297// * `*const *mut *const T` is not a valid receiver for any attribute access on `T`, which means
298// that the only applicable items will be the methods declared on `self: Vc<Self>`.
299//
300// If we had used `type Target = T` instead, `vc_t.some_attr_defined_on_t` would
301// have been accepted by the compiler.
302#[doc(hidden)]
303impl<T> Deref for Vc<T>
304where
305 T: ?Sized,
306{
307 type Target = VcDeref<T>;
308
309 fn deref(&self) -> &Self::Target {
310 unsafe extern "C" {
311 #[link_name = "\n\nERROR: you tried to dereference a `Vc<T>`\n"]
312 fn trigger() -> !;
313 }
314
315 unsafe { trigger() };
316 }
317}
318
319impl<T> Copy for Vc<T> where T: ?Sized {}
320
321impl<T> Clone for Vc<T>
322where
323 T: ?Sized,
324{
325 fn clone(&self) -> Self {
326 *self
327 }
328}
329
330impl<T> Hash for Vc<T>
331where
332 T: ?Sized,
333{
334 fn hash<H: Hasher>(&self, state: &mut H) {
335 self.node.hash(state);
336 }
337}
338
339impl<T> PartialEq<Vc<T>> for Vc<T>
340where
341 T: ?Sized,
342{
343 fn eq(&self, other: &Self) -> bool {
344 self.node == other.node
345 }
346}
347
348impl<T> Eq for Vc<T> where T: ?Sized {}
349
350/// Generates an opaque debug representation of the [`Vc`] itself, but not the data inside of it.
351///
352/// This is implemented to allow types containing [`Vc`] to implement the synchronous [`Debug`]
353/// trait, but in most cases users should use the [`ValueDebug`] implementation to get a string
354/// representation of the contents of the cell.
355impl<T> Debug for Vc<T>
356where
357 T: ?Sized,
358{
359 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
360 f.debug_struct("Vc").field("node", &self.node).finish()
361 }
362}
363
364impl<T> Vc<T>
365where
366 T: VcValueType,
367{
368 // called by the `.cell()` method generated by the `#[turbo_tasks::value]` macro
369 #[doc(hidden)]
370 pub fn cell_private(mut inner: <T::Read as VcRead<T>>::Target) -> Self {
371 // cell contents are immutable, so go ahead and shrink the cell's contents
372 ShrinkToFit::shrink_to_fit(<T::Read as VcRead<T>>::target_to_value_mut_ref(&mut inner));
373 <T::CellMode as VcCellMode<T>>::cell(inner)
374 }
375}
376
377impl<T, Inner, Repr> Vc<T>
378where
379 T: VcValueType<Read = VcTransparentRead<T, Inner, Repr>>,
380 Inner: Any + Send + Sync,
381 Repr: VcValueType,
382{
383 pub fn cell(inner: Inner) -> Self {
384 Self::cell_private(inner)
385 }
386}
387
388impl<T> Vc<T>
389where
390 T: ?Sized,
391{
392 /// Returns a debug identifier for this `Vc`.
393 pub async fn debug_identifier(vc: Self) -> Result<String> {
394 let resolved = vc.resolve().await?;
395 let raw_vc: RawVc = resolved.node;
396 if let RawVc::TaskCell(task_id, CellId { type_id, index }) = raw_vc {
397 let value_ty = registry::get_value_type(type_id);
398 Ok(format!("{}#{}: {}", value_ty.name, index, task_id))
399 } else {
400 unreachable!()
401 }
402 }
403
404 /// Returns the `RawVc` corresponding to this `Vc`.
405 pub fn into_raw(vc: Self) -> RawVc {
406 vc.node
407 }
408
409 /// Upcasts the given `Vc<T>` to a `Vc<Box<dyn K>>`.
410 ///
411 /// This is also available as an `Into`/`From` conversion.
412 #[inline(always)]
413 pub fn upcast<K>(vc: Self) -> Vc<K>
414 where
415 T: Upcast<K>,
416 K: VcValueTrait + ?Sized,
417 {
418 Vc {
419 node: vc.node,
420 _t: PhantomData,
421 }
422 }
423
424 /// Do not use this: Use [`Vc::to_resolved`] instead. If you must have a resolved [`Vc`] type
425 /// and not a [`ResolvedVc`] type, simply deref the result of [`Vc::to_resolved`].
426 pub async fn resolve(self) -> Result<Vc<T>> {
427 Ok(Self {
428 node: self.node.resolve().await?,
429 _t: PhantomData,
430 })
431 }
432
433 /// Resolve the reference until it points to a cell directly, and wrap the
434 /// result in a [`ResolvedVc`], which statically guarantees that the
435 /// [`Vc`] was resolved.
436 pub async fn to_resolved(self) -> Result<ResolvedVc<T>> {
437 Ok(ResolvedVc {
438 node: self.resolve().await?,
439 })
440 }
441
442 /// Returns `true` if the reference is resolved, meaning the underlying [`RawVc`] uses the
443 /// [`RawVc::TaskCell`] representation.
444 ///
445 /// If you need resolved [`Vc`] value, it's typically better to use the [`ResolvedVc`] type to
446 /// enforce your requirements statically instead of dynamically at runtime.
447 ///
448 /// See also [`ResolvedVc::to_resolved`] and [`RawVc::is_resolved`].
449 pub fn is_resolved(self) -> bool {
450 self.node.is_resolved()
451 }
452
453 /// Returns `true` if the `Vc` was by a local function call (e.g. one who's arguments were not
454 /// fully resolved) and has not yet been resolved.
455 ///
456 /// Aside from differences in caching, a function's behavior should not be changed by using
457 /// local or non-local cells, so this function is mostly useful inside tests and internally in
458 /// turbo-tasks.
459 pub fn is_local(self) -> bool {
460 self.node.is_local()
461 }
462
463 /// Do not use this: Use [`OperationVc::resolve_strongly_consistent`] instead.
464 #[cfg(feature = "non_operation_vc_strongly_consistent")]
465 pub async fn resolve_strongly_consistent(self) -> Result<Self> {
466 Ok(Self {
467 node: self.node.resolve_strongly_consistent().await?,
468 _t: PhantomData,
469 })
470 }
471}
472
473impl<T> Vc<T>
474where
475 T: VcValueTrait + ?Sized,
476{
477 /// Attempts to sidecast the given `Vc<Box<dyn T>>` to a `Vc<Box<dyn K>>`.
478 /// This operation also resolves the `Vc`.
479 ///
480 /// Returns `None` if the underlying value type does not implement `K`.
481 ///
482 /// **Note:** if the trait T is required to implement K, use
483 /// `Vc::upcast(vc).resolve()` instead. This provides stronger guarantees,
484 /// removing the need for a `Result` return type.
485 pub async fn try_resolve_sidecast<K>(vc: Self) -> Result<Option<Vc<K>>, ResolveTypeError>
486 where
487 K: VcValueTrait + ?Sized,
488 {
489 let raw_vc: RawVc = vc.node;
490 let raw_vc = raw_vc
491 .resolve_trait(<K as VcValueTrait>::get_trait_type_id())
492 .await?;
493 Ok(raw_vc.map(|raw_vc| Vc {
494 node: raw_vc,
495 _t: PhantomData,
496 }))
497 }
498
499 /// Attempts to downcast the given `Vc<Box<dyn T>>` to a `Vc<K>`, where `K`
500 /// is of the form `Box<dyn L>`, and `L` is a value trait.
501 /// This operation also resolves the `Vc`.
502 ///
503 /// Returns `None` if the underlying value type is not a `K`.
504 pub async fn try_resolve_downcast<K>(vc: Self) -> Result<Option<Vc<K>>, ResolveTypeError>
505 where
506 K: Upcast<T> + VcValueTrait + ?Sized,
507 {
508 let raw_vc: RawVc = vc.node;
509 let raw_vc = raw_vc
510 .resolve_trait(<K as VcValueTrait>::get_trait_type_id())
511 .await?;
512 Ok(raw_vc.map(|raw_vc| Vc {
513 node: raw_vc,
514 _t: PhantomData,
515 }))
516 }
517
518 /// Attempts to downcast the given `Vc<Box<dyn T>>` to a `Vc<K>`, where `K`
519 /// is a value type.
520 /// This operation also resolves the `Vc`.
521 ///
522 /// Returns `None` if the underlying value type is not a `K`.
523 pub async fn try_resolve_downcast_type<K>(vc: Self) -> Result<Option<Vc<K>>, ResolveTypeError>
524 where
525 K: Upcast<T> + VcValueType,
526 {
527 let raw_vc: RawVc = vc.node;
528 let raw_vc = raw_vc
529 .resolve_value(<K as VcValueType>::get_value_type_id())
530 .await?;
531 Ok(raw_vc.map(|raw_vc| Vc {
532 node: raw_vc,
533 _t: PhantomData,
534 }))
535 }
536}
537
538impl<T> From<RawVc> for Vc<T>
539where
540 T: ?Sized,
541{
542 fn from(node: RawVc) -> Self {
543 Self {
544 node,
545 _t: PhantomData,
546 }
547 }
548}
549
550impl<T> TraceRawVcs for Vc<T>
551where
552 T: ?Sized,
553{
554 fn trace_raw_vcs(&self, trace_context: &mut TraceRawVcsContext) {
555 TraceRawVcs::trace_raw_vcs(&self.node, trace_context);
556 }
557}
558
559impl<T> ValueDebugFormat for Vc<T>
560where
561 T: Upcast<Box<dyn ValueDebug>> + Send + Sync + ?Sized,
562{
563 fn value_debug_format(&self, depth: usize) -> ValueDebugFormatString {
564 ValueDebugFormatString::Async(Box::pin(async move {
565 Ok({
566 let vc_value_debug = Vc::upcast::<Box<dyn ValueDebug>>(*self);
567 vc_value_debug.dbg_depth(depth).await?.to_string()
568 })
569 }))
570 }
571}
572
573macro_rules! into_future {
574 ($ty:ty) => {
575 impl<T> IntoFuture for $ty
576 where
577 T: VcValueType,
578 {
579 type Output = <ReadVcFuture<T> as Future>::Output;
580 type IntoFuture = ReadVcFuture<T>;
581 fn into_future(self) -> Self::IntoFuture {
582 self.node.into_read().into()
583 }
584 }
585 };
586}
587
588into_future!(Vc<T>);
589into_future!(&Vc<T>);
590into_future!(&mut Vc<T>);
591
592impl<T> Vc<T>
593where
594 T: VcValueType,
595{
596 /// Do not use this: Use [`OperationVc::read_strongly_consistent`] instead.
597 #[cfg(feature = "non_operation_vc_strongly_consistent")]
598 #[must_use]
599 pub fn strongly_consistent(self) -> ReadVcFuture<T> {
600 self.node.into_read().strongly_consistent().into()
601 }
602
603 /// Returns a untracked read of the value. This will not invalidate the current function when
604 /// the read value changed.
605 #[must_use]
606 pub fn untracked(self) -> ReadVcFuture<T> {
607 self.node.into_read().untracked().into()
608 }
609
610 /// Read the value with the hint that this is the final read of the value. This might drop the
611 /// cell content. Future reads might need to recompute the value.
612 #[must_use]
613 pub fn final_read_hint(self) -> ReadVcFuture<T> {
614 self.node.into_read().final_read_hint().into()
615 }
616}
617
618impl<T> Vc<T>
619where
620 T: VcValueType,
621 VcReadTarget<T>: Clone,
622{
623 /// Read the value and returns a owned version of it. It might clone the value.
624 pub fn owned(self) -> ReadOwnedVcFuture<T> {
625 let future: ReadVcFuture<T> = self.node.into_read().into();
626 future.owned()
627 }
628}
629
630impl<T> Unpin for Vc<T> where T: ?Sized {}
631
632impl<T> Default for Vc<T>
633where
634 T: ValueDefault,
635{
636 fn default() -> Self {
637 T::value_default()
638 }
639}
640
641pub trait OptionVcExt<T>
642where
643 T: VcValueType,
644{
645 fn to_resolved(self) -> impl Future<Output = Result<Option<ResolvedVc<T>>>> + Send;
646}
647
648impl<T> OptionVcExt<T> for Option<Vc<T>>
649where
650 T: VcValueType,
651{
652 async fn to_resolved(self) -> Result<Option<ResolvedVc<T>>> {
653 if let Some(vc) = self {
654 Ok(Some(vc.to_resolved().await?))
655 } else {
656 Ok(None)
657 }
658 }
659}