turbo_tasks/vc/
cell_mode.rs

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