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}