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, manager::find_cell_by_type,
6    task::shared_reference::TypedSharedReference,
7};
8
9type VcReadTarget<T> = <<T as VcValueType>::Read as VcRead<T>>::Target;
10type VcReadRepr<T> = <<T as VcValueType>::Read as VcRead<T>>::Repr;
11
12/// Trait that controls the behavior of [`Vc::cell`] based on the value type's
13/// [`VcValueType::CellMode`].
14///
15/// This trait must remain sealed within this crate.
16pub trait VcCellMode<T>
17where
18    T: VcValueType,
19{
20    /// Create a new cell.
21    fn cell(value: VcReadTarget<T>) -> Vc<T>;
22
23    /// Create a type-erased [`RawVc`] cell given a pre-existing type-erased
24    /// [`SharedReference`][crate::task::SharedReference].
25    ///
26    /// This is used in APIs that already have a `SharedReference`, such as in
27    /// [`ReadRef::cell`][crate::ReadRef::cell] or in [`Vc::resolve`] when
28    /// resolving a local [`Vc`]. This avoids unnecessary cloning.
29    fn raw_cell(value: TypedSharedReference) -> RawVc;
30}
31
32/// Mode that always updates the cell's content.
33pub struct VcCellNewMode<T> {
34    _phantom: PhantomData<T>,
35}
36
37impl<T> VcCellMode<T> for VcCellNewMode<T>
38where
39    T: VcValueType,
40{
41    fn cell(inner: VcReadTarget<T>) -> Vc<T> {
42        let cell = find_cell_by_type(T::get_value_type_id());
43        cell.update(
44            <T::Read as VcRead<T>>::target_to_value(inner),
45            VerificationMode::Skip,
46        );
47        Vc {
48            node: cell.into(),
49            _t: PhantomData,
50        }
51    }
52
53    fn raw_cell(content: TypedSharedReference) -> RawVc {
54        debug_assert_repr::<T>(&content);
55        let cell = find_cell_by_type(content.type_id);
56        cell.update_with_shared_reference(content.reference, VerificationMode::Skip);
57        cell.into()
58    }
59}
60
61/// Mode that compares the cell's content with the new value and only updates
62/// if the new value is different.
63pub struct VcCellCompareMode<T> {
64    _phantom: PhantomData<T>,
65}
66
67impl<T> VcCellMode<T> for VcCellCompareMode<T>
68where
69    T: VcValueType + PartialEq,
70{
71    fn cell(inner: VcReadTarget<T>) -> Vc<T> {
72        let cell = find_cell_by_type(T::get_value_type_id());
73        cell.compare_and_update(<T::Read as VcRead<T>>::target_to_value(inner));
74        Vc {
75            node: cell.into(),
76            _t: PhantomData,
77        }
78    }
79
80    fn raw_cell(content: TypedSharedReference) -> RawVc {
81        debug_assert_repr::<T>(&content);
82        let cell = find_cell_by_type(content.type_id);
83        cell.compare_and_update_with_shared_reference::<T>(content.reference);
84        cell.into()
85    }
86}
87
88fn debug_assert_repr<T: VcValueType>(content: &TypedSharedReference) {
89    debug_assert!(
90        (*content.reference.0).is::<VcReadRepr<T>>(),
91        "SharedReference for type {} must use representation type {}",
92        type_name::<T>(),
93        type_name::<VcReadRepr<T>>(),
94    );
95}