Skip to main content

turbo_tasks/
dyn_task_inputs.rs

1use std::{
2    any::{Any, type_name},
3    fmt::Debug,
4    hash::Hash,
5};
6
7use turbo_dyn_eq_hash::{
8    DynEq, DynHash, impl_eq_for_dyn, impl_hash_for_dyn, impl_partial_eq_for_dyn,
9};
10
11use crate::trace::TraceRawVcs;
12
13pub trait DynTaskInputs: Debug + DynEq + DynHash + TraceRawVcs + Send + Sync + 'static {
14    #[cfg(debug_assertions)]
15    fn dyn_type_name(&self) -> &'static str;
16}
17
18impl<T> DynTaskInputs for T
19where
20    T: Debug + Eq + Hash + Send + Sync + TraceRawVcs + 'static,
21{
22    #[cfg(debug_assertions)]
23    fn dyn_type_name(&self) -> &'static str {
24        std::any::type_name::<T>()
25    }
26}
27
28impl_partial_eq_for_dyn!(dyn DynTaskInputs);
29impl_eq_for_dyn!(dyn DynTaskInputs);
30impl_hash_for_dyn!(dyn DynTaskInputs);
31
32pub fn any_as_encode<T: Any>(this: &dyn Any) -> &T {
33    if let Some(enc) = this.downcast_ref::<T>() {
34        return enc;
35    }
36    unreachable!(
37        "any_as_encode::<{}> called with invalid type",
38        type_name::<T>()
39    );
40}
41
42/// A trait for task arguments that may reside on the stack.
43///
44/// This enables deferred boxing: on the cache-hit path (~85%), we only borrow
45/// the argument via [`as_ref`](StackDynTaskInputs::as_ref) for hash/equality lookups,
46/// avoiding any heap allocation. On cache miss, [`take_box`](StackDynTaskInputs::take_box)
47/// moves the value into a `Box` with zero clones.
48pub trait StackDynTaskInputs {
49    /// Borrow the argument as a type-erased reference (for cache lookup).
50    fn as_ref(&self) -> &dyn DynTaskInputs;
51    /// Move the argument out into a heap-allocated Box (panics if already taken).
52    fn take_box(&mut self) -> Box<dyn DynTaskInputs>;
53    /// Downcast to `&mut dyn Any` for concrete type recovery without boxing.
54    fn as_any_mut(&mut self) -> &mut dyn Any;
55}
56
57/// Stack-resident slot wrapping a concrete typed value.
58///
59/// Created by macro-generated callsites. The value starts in `Some` on the
60/// stack; [`take_box`](StackDynTaskInputs::take_box) moves it to the heap on cache miss.
61#[repr(transparent)]
62pub struct StackDynTaskInputsSlot<T> {
63    slot: Option<T>,
64}
65
66impl<T> StackDynTaskInputsSlot<T> {
67    #[inline]
68    pub fn new(value: T) -> Self {
69        Self { slot: Some(value) }
70    }
71
72    #[inline]
73    pub fn take(&mut self) -> T {
74        self.slot
75            .take()
76            .expect("StackDynTaskInputsSlot::take called after value was already taken")
77    }
78}
79
80impl<T: DynTaskInputs> StackDynTaskInputs for StackDynTaskInputsSlot<T> {
81    #[inline]
82    fn as_ref(&self) -> &dyn DynTaskInputs {
83        self.slot
84            .as_ref()
85            .expect("StackDynTaskInputsSlot::as_ref called after take_box")
86    }
87
88    #[inline]
89    fn take_box(&mut self) -> Box<dyn DynTaskInputs> {
90        Box::new(
91            self.slot
92                .take()
93                .expect("StackDynTaskInputsSlot::take_box called twice"),
94        )
95    }
96
97    #[inline]
98    fn as_any_mut(&mut self) -> &mut dyn Any {
99        self
100    }
101}
102
103/// Adapter for an already-boxed value (e.g., from async resolution tasks).
104pub struct OwnedStackDynTaskInputs {
105    slot: Option<Box<dyn DynTaskInputs>>,
106}
107
108impl OwnedStackDynTaskInputs {
109    #[inline]
110    pub fn new(value: Box<dyn DynTaskInputs>) -> Self {
111        Self { slot: Some(value) }
112    }
113}
114
115impl StackDynTaskInputs for OwnedStackDynTaskInputs {
116    #[inline]
117    fn as_ref(&self) -> &dyn DynTaskInputs {
118        &**self
119            .slot
120            .as_ref()
121            .expect("OwnedStackDynTaskInputs::as_ref called after take_box")
122    }
123
124    #[inline]
125    fn take_box(&mut self) -> Box<dyn DynTaskInputs> {
126        self.slot
127            .take()
128            .expect("OwnedStackDynTaskInputs::take_box called twice")
129    }
130
131    #[inline]
132    fn as_any_mut(&mut self) -> &mut dyn Any {
133        self
134    }
135}