Skip to main content

turbo_tasks/vc/
cell_mode.rs

1use std::{any::type_name, marker::PhantomData};
2
3use turbo_tasks_hash::DeterministicHash;
4
5use super::{read::VcRead, traits::VcValueType};
6use crate::{
7    RawVc, Vc, backend::VerificationMode, keyed::KeyedEq, manager::find_cell_by_type,
8    task::shared_reference::TypedSharedReference,
9};
10
11type VcReadTarget<T> = <<T as VcValueType>::Read as VcRead<T>>::Target;
12
13/// Trait that controls the behavior of [`Vc::cell`] based on the value type's
14/// [`VcValueType::CellMode`].
15///
16/// This trait must remain sealed within this crate.
17pub trait VcCellMode<T>
18where
19    T: VcValueType,
20{
21    /// Create a new cell.
22    fn cell(value: VcReadTarget<T>) -> Vc<T>;
23
24    /// Create a type-erased [`RawVc`] cell given a pre-existing type-erased
25    /// [`SharedReference`][crate::task::SharedReference].
26    ///
27    /// This is used in APIs that already have a `SharedReference`, such as in
28    /// [`ReadRef::cell`][crate::ReadRef::cell] or in [`Vc::to_resolved`] when
29    /// resolving a local [`Vc`]. This avoids unnecessary cloning.
30    fn raw_cell(value: TypedSharedReference) -> RawVc;
31}
32
33/// Mode that always updates the cell's content.
34pub struct VcCellNewMode<T> {
35    _phantom: PhantomData<T>,
36}
37
38impl<T> VcCellMode<T> for VcCellNewMode<T>
39where
40    T: VcValueType,
41{
42    fn cell(inner: VcReadTarget<T>) -> Vc<T> {
43        let cell = find_cell_by_type::<T>();
44        cell.update(
45            <T::Read as VcRead<T>>::target_to_value(inner),
46            VerificationMode::Skip,
47        );
48        Vc {
49            node: cell.into(),
50            _t: PhantomData,
51        }
52    }
53
54    fn raw_cell(content: TypedSharedReference) -> RawVc {
55        debug_assert_type::<T>(&content);
56        let cell = find_cell_by_type::<T>();
57        cell.update_with_shared_reference(content.reference, VerificationMode::Skip);
58        cell.into()
59    }
60}
61
62/// Mode that compares the cell's content with the new value and only updates
63/// if the new value is different.
64pub struct VcCellCompareMode<T> {
65    _phantom: PhantomData<T>,
66}
67
68impl<T> VcCellMode<T> for VcCellCompareMode<T>
69where
70    T: VcValueType + PartialEq,
71{
72    fn cell(inner: VcReadTarget<T>) -> Vc<T> {
73        let cell = find_cell_by_type::<T>();
74        cell.compare_and_update(<T::Read as VcRead<T>>::target_to_value(inner));
75        Vc {
76            node: cell.into(),
77            _t: PhantomData,
78        }
79    }
80
81    fn raw_cell(content: TypedSharedReference) -> RawVc {
82        debug_assert_type::<T>(&content);
83        let cell = find_cell_by_type::<T>();
84        cell.compare_and_update_with_shared_reference::<T>(content.reference);
85        cell.into()
86    }
87}
88
89/// Mode that compares the cell's content with the new value key by key and only updates
90/// individual keys if the new value is different.
91pub struct VcCellKeyedCompareMode<T> {
92    _phantom: PhantomData<T>,
93}
94
95impl<T> VcCellMode<T> for VcCellKeyedCompareMode<T>
96where
97    T: VcValueType + PartialEq,
98    VcReadTarget<T>: KeyedEq,
99    <VcReadTarget<T> as KeyedEq>::Key: std::hash::Hash,
100{
101    fn cell(inner: VcReadTarget<T>) -> Vc<T> {
102        let cell = find_cell_by_type::<T>();
103        cell.keyed_compare_and_update(<T::Read as VcRead<T>>::target_to_value(inner));
104        Vc {
105            node: cell.into(),
106            _t: PhantomData,
107        }
108    }
109
110    fn raw_cell(content: TypedSharedReference) -> RawVc {
111        debug_assert_type::<T>(&content);
112        let cell = find_cell_by_type::<T>();
113        cell.keyed_compare_and_update_with_shared_reference::<T>(content.reference);
114        cell.into()
115    }
116}
117
118fn debug_assert_type<T: VcValueType>(content: &TypedSharedReference) {
119    debug_assert!(
120        (*content.reference.0).is::<T>(),
121        "SharedReference for type {} must contain data matching that type",
122        type_name::<T>(),
123    );
124}
125
126/// Mode that compares the cell's content with the new value and only updates
127/// if the new value is different, using both PartialEq (when old content is available)
128/// and a stored hash (when old content has been evicted from memory) for comparison.
129pub struct VcCellHashedCompareMode<T> {
130    _phantom: PhantomData<T>,
131}
132
133impl<T> VcCellMode<T> for VcCellHashedCompareMode<T>
134where
135    T: VcValueType + PartialEq + DeterministicHash,
136{
137    fn cell(inner: VcReadTarget<T>) -> Vc<T> {
138        let cell = find_cell_by_type::<T>();
139        cell.hashed_compare_and_update(<T::Read as VcRead<T>>::target_to_value(inner));
140        Vc {
141            node: cell.into(),
142            _t: PhantomData,
143        }
144    }
145
146    fn raw_cell(content: TypedSharedReference) -> RawVc {
147        debug_assert_type::<T>(&content);
148        let cell = find_cell_by_type::<T>();
149        cell.hashed_compare_and_update_with_shared_reference::<T>(content.reference);
150        cell.into()
151    }
152}