turbo_tasks/task/
local_task.rs

1use std::{fmt, sync::Arc};
2
3use anyhow::{Result, anyhow};
4
5use crate::{
6    MagicAny, OutputContent, RawVc, TaskExecutionReason, TaskPersistence, TraitMethod,
7    TurboTasksBackendApi, ValueTypeId,
8    backend::{Backend, TaskExecutionSpec, TypedCellContent},
9    event::Event,
10    macro_helpers::NativeFunction,
11    registry,
12};
13
14/// A potentially in-flight local task stored in `CurrentGlobalTaskState::local_tasks`.
15pub enum LocalTask {
16    Scheduled { done_event: Event },
17    Done { output: OutputContent },
18}
19
20pub fn get_local_task_execution_spec<'a>(
21    turbo_tasks: &'_ dyn TurboTasksBackendApi<impl Backend + 'static>,
22    ty: &'a LocalTaskSpec,
23    // if this is a `LocalTaskType::Resolve*`, we'll spawn another task with this persistence, if
24    // this is a `LocalTaskType::Native`, this refers to the parent non-local task.
25    persistence: TaskPersistence,
26) -> TaskExecutionSpec<'a> {
27    match ty.task_type {
28        LocalTaskType::Native { native_fn } => {
29            let span = native_fn.span(TaskPersistence::Local, TaskExecutionReason::Local);
30            let entered = span.enter();
31            let future = native_fn.execute(ty.this, &*ty.arg);
32            drop(entered);
33            TaskExecutionSpec { future, span }
34        }
35        LocalTaskType::ResolveNative { native_fn } => {
36            let span = native_fn.resolve_span(TaskPersistence::Local);
37            let entered = span.enter();
38            let future = Box::pin(LocalTaskType::run_resolve_native(
39                native_fn,
40                ty.this,
41                &*ty.arg,
42                persistence,
43                turbo_tasks.pin(),
44            ));
45            drop(entered);
46            TaskExecutionSpec { future, span }
47        }
48        LocalTaskType::ResolveTrait { trait_method } => {
49            let span = trait_method.resolve_span();
50            let entered = span.enter();
51            let future = Box::pin(LocalTaskType::run_resolve_trait(
52                trait_method,
53                ty.this.unwrap(),
54                &*ty.arg,
55                persistence,
56                turbo_tasks.pin(),
57            ));
58            drop(entered);
59            TaskExecutionSpec { future, span }
60        }
61    }
62}
63
64pub struct LocalTaskSpec {
65    /// The self value, will always be present for `ResolveTrait` tasks and is optional otherwise
66    pub(crate) this: Option<RawVc>,
67    /// Function arguments
68    pub(crate) arg: Box<dyn MagicAny>,
69    pub(crate) task_type: LocalTaskType,
70}
71
72#[derive(Copy, Clone)]
73pub enum LocalTaskType {
74    /// A normal task execution a native (rust) function
75    Native { native_fn: &'static NativeFunction },
76
77    /// A resolve task, which resolves arguments and calls the function with resolve arguments. The
78    /// inner function call will be a `PersistentTaskType` or `LocalTaskType::Native`.
79    ResolveNative { native_fn: &'static NativeFunction },
80
81    /// A trait method resolve task. It resolves the first (`self`) argument and looks up the trait
82    /// method on that value. Then it calls that method. The method call will do a cache lookup and
83    /// might resolve arguments before.
84    ResolveTrait { trait_method: &'static TraitMethod },
85}
86
87impl fmt::Display for LocalTaskType {
88    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89        match self {
90            LocalTaskType::Native { native_fn } => f.write_str(native_fn.name),
91            LocalTaskType::ResolveNative { native_fn } => write!(f, "*{}", native_fn.name),
92            LocalTaskType::ResolveTrait { trait_method } => write!(
93                f,
94                "*{}::{}",
95                trait_method.trait_name, trait_method.method_name
96            ),
97        }
98    }
99}
100
101impl LocalTaskType {
102    /// Implementation of the LocalTaskType::ResolveNative task.
103    /// Resolves all the task inputs and then calls the given function.
104    async fn run_resolve_native<B: Backend + 'static>(
105        native_fn: &'static NativeFunction,
106        mut this: Option<RawVc>,
107        arg: &dyn MagicAny,
108        persistence: TaskPersistence,
109        turbo_tasks: Arc<dyn TurboTasksBackendApi<B>>,
110    ) -> Result<RawVc> {
111        if let Some(this) = this.as_mut() {
112            *this = this.resolve().await?;
113        }
114        let arg = native_fn.arg_meta.resolve(arg).await?;
115        Ok(turbo_tasks.native_call(native_fn, this, arg, persistence))
116    }
117    /// Implementation of the LocalTaskType::ResolveTrait task.
118    async fn run_resolve_trait<B: Backend + 'static>(
119        trait_method: &'static TraitMethod,
120        this: RawVc,
121        arg: &dyn MagicAny,
122        persistence: TaskPersistence,
123        turbo_tasks: Arc<dyn TurboTasksBackendApi<B>>,
124    ) -> Result<RawVc> {
125        let this = this.resolve().await?;
126        let TypedCellContent(this_ty, _) = this.into_read().await?;
127
128        let native_fn = Self::resolve_trait_method_from_value(trait_method, this_ty)?;
129        let arg = native_fn.arg_meta.filter_and_resolve(arg).await?;
130        Ok(turbo_tasks.native_call(native_fn, Some(this), arg, persistence))
131    }
132
133    fn resolve_trait_method_from_value(
134        trait_method: &'static TraitMethod,
135        value_type: ValueTypeId,
136    ) -> Result<&'static NativeFunction> {
137        match registry::get_value_type(value_type).get_trait_method(trait_method) {
138            Some(native_fn) => Ok(native_fn),
139            None => Err(anyhow!(
140                "{} doesn't implement the trait for {:?}, the compiler should have flagged this",
141                registry::get_value_type(value_type),
142                trait_method
143            )),
144        }
145    }
146}
147
148#[cfg(test)]
149pub(crate) mod tests {
150    use super::*;
151    use crate::{self as turbo_tasks, Vc};
152
153    #[turbo_tasks::function]
154    fn mock_func_task() -> Vc<()> {
155        Vc::cell(())
156    }
157
158    #[turbo_tasks::value_trait]
159    trait MockTrait {
160        #[turbo_tasks::function]
161        fn mock_method_task() -> Vc<()>;
162    }
163
164    #[test]
165    fn test_fmt() {
166        crate::register();
167        assert_eq!(
168            LocalTaskType::Native {
169                native_fn: &MOCK_FUNC_TASK_FUNCTION,
170            }
171            .to_string(),
172            "mock_func_task",
173        );
174        assert_eq!(
175            LocalTaskType::ResolveTrait {
176                trait_method: MOCKTRAIT_TRAIT_TYPE.get("mock_method_task"),
177            }
178            .to_string(),
179            "*MockTrait::mock_method_task",
180        );
181    }
182}