turbo_tasks/vc/
cell_mode.rs

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