Struct Vc

Source
pub struct Vc<T>
where T: ?Sized,
{ /* private fields */ }
Expand description

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>:

let some_vc: Vc<T>;
let some_ref: ReadRef<T> = some_vc.await?;
some_ref.some_method_on_t();

Vcs are similar to a Future or a Promise with a few key differences:

  • The value pointed to by a Vc can be invalidated by changing dependencies or cache evicted, meaning that awaiting a Vc multiple times can give different results. A ReadRef is snapshot of the underlying cell at a point in time.

  • Reading (awaiting) Vcs 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 Futures are not. This works because Vcs 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.

  • Unlike futures (but like promises), the work that a Vc represents begins execution even if the Vc is not awaited.

For a more in-depth explanation of the concepts behind value cells, refer to the Turbopack book.

§Subtypes

There are a couple of explicit “subtypes” of Vc. These can both be cheaply converted back into a Vc.

  • ResolvedVc: (aka RawVc::TaskCell) 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 (allowing downcasting). This is stored as a combination of a task id, a type id, and a cell id.

  • OperationVc: (aka RawVc::TaskOutput) 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. OperationVcs must first be connected before being read.

ResolvedVc is almost always preferred over the more awkward OperationVc API, but OperationVc can be useful when dealing with collectibles, when you need to read the result of a function with strong consistency, or with State.

These many representations are stored internally using a type-erased RawVc. Type erasure reduces the monomorphization (and therefore binary size and compilation time) required to support Vc and its subtypes.

RepresentationEqualityDowncastingStrong ConsistencyCollectiblesNon-Local
VcOne of manyBroken⚠️ After resolution❌ Eventual❌ NoNo
ResolvedVcTask Id + Type Id + Cell Id✅ Yes*Yes, cheaply❌ Eventual❌ No✅ Yes
OperationVcTask Id✅ Yes*⚠️ After resolutionSupportedYes✅ Yes

* see the type’s documentation for details

§Execution Model

While task functions are expected to be side-effect free, their execution behavior is still important for performance reasons, or to code using collectibles to represent issues or side-effects.

Function calls are neither “eager”, nor “lazy”. Even if not awaited, they are guaranteed to execute (potentially emitting collectibles) before the root task finishes or before the completion of any strongly consistent read containing their call. However, the exact point when that execution begins is an implementation detail. Functions may execute more than once due to dirty task invalidation.

§Equality & Hashing

Because Vcs can be equivalent but have different representation, it’s not recommended to compare Vcs by equality. Instead, you should convert a Vc to an explicit subtype first (likely ResolvedVc). Future versions of Vc may not implement Eq, PartialEq, or Hash.

§Optimization: Local Outputs

In addition to the potentially-explicit “resolved” and “operation” representations of a Vc, there’s another internal representation of a Vc, known as a “Local Vc”, or RawVc::LocalOutput.

This is a special case of the synchronous return value of a turbo_tasks::function when some of its arguments have not yet been resolved. These are stored in task-local state that is freed after their parent non-local task exits.

We prevent potentially-local Vcs from escaping the lifetime of a function using the NonLocalValue marker trait alongside some fallback runtime checks. We do this to avoid some ergonomic challenges that would come from using lifetime annotations with Vc.

Implementations§

Source§

impl<T, Inner, Repr> Vc<T>
where T: VcValueType<Read = VcTransparentRead<T, Inner, Repr>>, Inner: Any + Send + Sync, Repr: VcValueType,

Source

pub fn cell(inner: Inner) -> Self

Source§

impl<T> Vc<T>
where T: ?Sized,

Source

pub async fn debug_identifier(vc: Self) -> Result<String>

Returns a debug identifier for this Vc.

Source

pub fn into_raw(vc: Self) -> RawVc

Returns the RawVc corresponding to this Vc.

Source

pub fn upcast<K>(vc: Self) -> Vc<K>
where T: Upcast<K>, K: VcValueTrait + ?Sized,

Upcasts the given Vc<T> to a Vc<Box<dyn K>>.

This is also available as an Into/From conversion.

Source

pub async fn resolve(self) -> Result<Vc<T>>

Do not use this: Use Vc::to_resolved instead. If you must have a resolved Vc type and not a ResolvedVc type, simply deref the result of Vc::to_resolved.

Source

pub async fn to_resolved(self) -> Result<ResolvedVc<T>>

Resolve the reference until it points to a cell directly, and wrap the result in a ResolvedVc, which statically guarantees that the Vc was resolved.

Source

pub fn is_resolved(self) -> bool

Returns true if the reference is resolved, meaning the underlying RawVc uses the RawVc::TaskCell representation.

If you need resolved Vc value, it’s typically better to use the ResolvedVc type to enforce your requirements statically instead of dynamically at runtime.

See also ResolvedVc::to_resolved and RawVc::is_resolved.

Source

pub fn is_local(self) -> bool

Returns true if the Vc was by a local function call (e.g. one who’s arguments were not fully resolved) and has not yet been resolved.

Aside from differences in caching, a function’s behavior should not be changed by using local or non-local cells, so this function is mostly useful inside tests and internally in turbo-tasks.

Source

pub async fn resolve_strongly_consistent(self) -> Result<Self>

Do not use this: Use OperationVc::resolve_strongly_consistent instead.

Source§

impl<T> Vc<T>
where T: VcValueTrait + ?Sized,

Source

pub async fn try_resolve_sidecast<K>( vc: Self, ) -> Result<Option<Vc<K>>, ResolveTypeError>
where K: VcValueTrait + ?Sized,

Attempts to sidecast the given Vc<Box<dyn T>> to a Vc<Box<dyn K>>. This operation also resolves the Vc.

Returns None if the underlying value type does not implement K.

Note: if the trait T is required to implement K, use Vc::upcast(vc).resolve() instead. This provides stronger guarantees, removing the need for a Result return type.

Source

pub async fn try_resolve_downcast<K>( vc: Self, ) -> Result<Option<Vc<K>>, ResolveTypeError>
where K: Upcast<T> + VcValueTrait + ?Sized,

Attempts to downcast the given Vc<Box<dyn T>> to a Vc<K>, where K is of the form Box<dyn L>, and L is a value trait. This operation also resolves the Vc.

Returns None if the underlying value type is not a K.

Source

pub async fn try_resolve_downcast_type<K>( vc: Self, ) -> Result<Option<Vc<K>>, ResolveTypeError>
where K: Upcast<T> + VcValueType,

Attempts to downcast the given Vc<Box<dyn T>> to a Vc<K>, where K is a value type. This operation also resolves the Vc.

Returns None if the underlying value type is not a K.

Source§

impl<T> Vc<T>
where T: VcValueType,

Source

pub fn strongly_consistent(self) -> ReadVcFuture<T>

Do not use this: Use OperationVc::read_strongly_consistent instead.

Source

pub fn untracked(self) -> ReadVcFuture<T>

Returns a untracked read of the value. This will not invalidate the current function when the read value changed.

Source

pub fn final_read_hint(self) -> ReadVcFuture<T>

Read the value with the hint that this is the final read of the value. This might drop the cell content. Future reads might need to recompute the value.

Source§

impl<T> Vc<T>
where T: VcValueType, <<T as VcValueType>::Read as VcRead<T>>::Target: Clone,

Source

pub fn owned(self) -> ReadOwnedVcFuture<T>

Read the value and returns a owned version of it. It might clone the value.

Trait Implementations§

Source§

impl<T> Clone for Vc<T>
where T: ?Sized,

Source§

fn clone(&self) -> Self

Returns a copy of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<T> Debug for Vc<T>
where T: ?Sized,

Generates an opaque debug representation of the Vc itself, but not the data inside of it.

This is implemented to allow types containing Vc to implement the synchronous Debug trait, but in most cases users should use the ValueDebug implementation to get a string representation of the contents of the cell.

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<T> Default for Vc<T>
where T: ValueDefault,

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl<'de, T> Deserialize<'de> for Vc<T>
where T: ?Sized,

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl<T> From<RawVc> for Vc<T>
where T: ?Sized,

Source§

fn from(node: RawVc) -> Self

Converts to this type from the input type.
Source§

impl<T> Hash for Vc<T>
where T: ?Sized,

Source§

fn hash<H: Hasher>(&self, state: &mut H)

Feeds this value into the given Hasher. Read more
1.3.0 · Source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where H: Hasher, Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
Source§

impl<T> IntoFuture for &Vc<T>
where T: VcValueType,

Source§

type Output = <ReadVcFuture<T> as Future>::Output

The output that the future will produce on completion.
Source§

type IntoFuture = ReadVcFuture<T>

Which kind of future are we turning this into?
Source§

fn into_future(self) -> Self::IntoFuture

Creates a future from a value. Read more
Source§

impl<T> IntoFuture for &mut Vc<T>
where T: VcValueType,

Source§

type Output = <ReadVcFuture<T> as Future>::Output

The output that the future will produce on completion.
Source§

type IntoFuture = ReadVcFuture<T>

Which kind of future are we turning this into?
Source§

fn into_future(self) -> Self::IntoFuture

Creates a future from a value. Read more
Source§

impl<T> IntoFuture for Vc<T>
where T: VcValueType,

Source§

type Output = <ReadVcFuture<T> as Future>::Output

The output that the future will produce on completion.
Source§

type IntoFuture = ReadVcFuture<T>

Which kind of future are we turning this into?
Source§

fn into_future(self) -> Self::IntoFuture

Creates a future from a value. Read more
Source§

impl<T> IntoTraitRef for Vc<T>
where T: VcValueTrait + ?Sized,

Source§

impl<T> PartialEq for Vc<T>
where T: ?Sized,

Source§

fn eq(&self, other: &Self) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl<T> Serialize for Vc<T>
where T: ?Sized,

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more
Source§

impl<T> TaskInput for Vc<T>
where T: Send + Sync + ?Sized,

Source§

fn is_resolved(&self) -> bool

Source§

fn is_transient(&self) -> bool

Source§

async fn resolve_input(&self) -> Result<Self>

Source§

impl<T> TaskOutput for Vc<T>
where T: Send + ?Sized,

Source§

impl<T> TraceRawVcs for Vc<T>
where T: ?Sized,

Source§

fn trace_raw_vcs(&self, trace_context: &mut TraceRawVcsContext)

Source§

fn get_raw_vcs(&self) -> Vec<RawVc>

Source§

impl<T> ValueDebugFormat for Vc<T>
where T: Upcast<Box<dyn ValueDebug>> + Send + Sync + ?Sized,

Source§

impl<T> Copy for Vc<T>
where T: ?Sized,

Source§

impl<T> Eq for Vc<T>
where T: ?Sized,

Source§

impl<T> Unpin for Vc<T>
where T: ?Sized,

Auto Trait Implementations§

§

impl<T> Freeze for Vc<T>
where T: ?Sized,

§

impl<T> RefUnwindSafe for Vc<T>
where T: RefUnwindSafe + ?Sized,

§

impl<T> Send for Vc<T>
where T: Send + ?Sized,

§

impl<T> Sync for Vc<T>
where T: Sync + ?Sized,

§

impl<T> UnwindSafe for Vc<T>
where T: UnwindSafe + ?Sized,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
§

impl<T> Any for T
where T: Any,

§

fn get_type_id(&self) -> TypeId

Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DynamicEqHash for T
where T: Any + PartialEq + Eq + Hash,

Source§

fn as_any(&self) -> &(dyn Any + 'static)

Source§

fn dyn_eq(&self, other: &(dyn Any + 'static)) -> bool

Source§

fn dyn_hash(&self, state: &mut dyn Hasher)

§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> MagicAny for T
where T: Debug + Eq + Hash + Send + Sync + TraceRawVcs + 'static,

Source§

fn magic_any_arc(self: Arc<T>) -> Arc<dyn Any + Sync + Send>

Source§

fn magic_debug(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Source§

fn magic_eq(&self, other: &(dyn MagicAny + 'static)) -> bool

Source§

fn magic_hash(&self, hasher: &mut dyn Hasher)

Source§

fn magic_trace_raw_vcs(&self, trace_context: &mut TraceRawVcsContext)

Source§

fn magic_type_name(&self) -> &'static str

§

impl<T> Pointable for T

§

const ALIGN: usize

The alignment of pointer.
§

type Init = T

The type for initializers.
§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<P, T> Receiver for P
where P: Deref<Target = T> + ?Sized, T: ?Sized,

Source§

type Target = T

🔬This is a nightly-only experimental API. (arbitrary_self_types)
The target type on which the method may be called.
Source§

impl<T> Serialize for T
where T: Serialize + ?Sized,

Source§

fn erased_serialize(&self, serializer: &mut dyn Serializer) -> Result<(), Error>

Source§

fn do_erased_serialize( &self, serializer: &mut dyn Serializer, ) -> Result<(), ErrorImpl>

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,