|
| 1 | +Tasks are created by defining a Rust function annotated with the `#[turbo_tasks::function]` macro and calling it with arguments. Each unique combination of function and arguments create a new task at runtime. Tasks are the fundamental units of work within the build system. |
| 2 | + |
| 3 | +```rust |
| 4 | +#[turbo_tasks::function] |
| 5 | +fn add(a: i32, b: i32) -> Vc<Something> { |
| 6 | + // Task implementation goes here... |
| 7 | +} |
| 8 | +``` |
| 9 | + |
| 10 | +- Tasks can be implemented as either a **synchronous or asynchronous** function. |
| 11 | +- Arguments must implement the **[`TaskInput`] trait**. Usually these are primitives or types wrapped in [`Vc<T>`]. |
| 12 | +- The **external signature** of a task always **returns a [`Vc<T>`]** or an [`OperationVc<T>`]. |
| 13 | +- **Generics** (type or lifetime parameters) are **not supported** in task functions. |
| 14 | + |
| 15 | +[`Vc<T>`]: crate::Vc |
| 16 | +[`TaskInput`]: crate::TaskInput |
| 17 | + |
| 18 | +## External Signature Rewriting |
| 19 | + |
| 20 | +The `#[turbo_tasks::function]` macro **rewrites the arguments and return values** of functions. The rewritten function signature is referred to as the **"external signature"**. |
| 21 | + |
| 22 | +### Argument Rewrite Rule |
| 23 | + |
| 24 | +- Function arguments with the **[`ResolvedVc<T>`]** type are **rewritten to [`Vc<T>`].** |
| 25 | + - The value cell is automatically resolved when the function is called. This reduces the work needed to convert between `Vc<T>` and `ResolvedVc<T>` types. |
| 26 | + - This rewrite applies for [`ResolvedVc<T>`] types nested inside of `Option<ResolvedVc<T>>` and `Vec<ResolvedVc<T>>`. For more details, refer to the [`FromTaskInput`] trait. |
| 27 | + |
| 28 | +- Method arguments of **`&self`** are **rewritten to `self: Vc<Self>`**. |
| 29 | + |
| 30 | +[`ResolvedVc<T>`]: crate::ResolvedVc |
| 31 | +[`FromTaskInput`]: crate::FromTaskInput |
| 32 | + |
| 33 | +### Return Type Rewrite Rules |
| 34 | + |
| 35 | +- A return type of **`Result<Vc<T>>` is rewritten into `Vc<T>`**. |
| 36 | + - The `Result<Vc<T>>` return type allows for idiomatic use of the `?` operator inside of task functions. |
| 37 | +- A function with **no return type** is rewritten to return **`Vc<()>` instead of `()`**. |
| 38 | +- The **[`impl Future<Output = Vc<T>>`][Future]** type implicitly returned by an async function is **flattened into the `Vc<T>` type**, which implements [`IntoFuture`] and can be `.await`ed. |
| 39 | + |
| 40 | +Some of this logic is represented by the [`TaskOutput`] trait and its associated [`Return`] type. |
| 41 | + |
| 42 | +[`TaskOutput`]: crate::task::TaskOutput |
| 43 | +[`Return`]: crate::task::TaskOutput::Return |
| 44 | + |
| 45 | +### External Signature Example |
| 46 | + |
| 47 | +As an example, the method |
| 48 | + |
| 49 | +```rust |
| 50 | +#[turbo_tasks::function] |
| 51 | +async fn foo( |
| 52 | + &self, |
| 53 | + a: i32, |
| 54 | + b: Vc<i32>, |
| 55 | + c: ResolvedVc<i32>, |
| 56 | + d: Option<Vec<ResolvedVc<i32>>>, |
| 57 | +) -> Result<Vc<i32>> { |
| 58 | + // ... |
| 59 | +} |
| 60 | +``` |
| 61 | + |
| 62 | +will have an external signature of |
| 63 | + |
| 64 | +```rust |
| 65 | +fn foo( |
| 66 | + self: Vc<Self>, // was: &self |
| 67 | + a: i32, |
| 68 | + b: Vc<i32>, |
| 69 | + c: Vc<i32>, // was: ResolvedVc<i32> |
| 70 | + d: Option<Vec<Vc<i32>>>, // was: Option<Vec<ResolvedVc<i32>>> |
| 71 | +) -> Vc<i32>; // was: impl Future<Output = Result<Vc<i32>>> |
| 72 | +``` |
| 73 | + |
| 74 | +## Methods and Self |
| 75 | + |
| 76 | +Tasks can be methods associated with a value or a trait implementation using the [`arbitrary_self_types` nightly compiler feature][self-types]. |
| 77 | + |
| 78 | +[self-types]: https://github.com/rust-lang/rfcs/blob/master/text/3519-arbitrary-self-types-v2.md |
| 79 | + |
| 80 | +### Inherent Implementations |
| 81 | + |
| 82 | +```rust |
| 83 | +#[turbo_tasks::value_impl] |
| 84 | +impl Something { |
| 85 | + #[turbo_tasks::function] |
| 86 | + fn method(self: Vc<Self>, a: i32) -> Vc<SomethingElse> { |
| 87 | + // Receives the full `Vc<Self>` type, which we must `.await` to get a |
| 88 | + // `ReadRef<Self>`. |
| 89 | + vdbg!(self.await?.some_field); |
| 90 | + |
| 91 | + // The `Vc` type is useful for calling other methods declared on |
| 92 | + // `Vc<Self>`, e.g.: |
| 93 | + self.method_resolved(a) |
| 94 | + } |
| 95 | + |
| 96 | + #[turbo_tasks::function] |
| 97 | + fn method_resolved(self: ResolvedVc<Self>, a: i32) -> Vc<SomethingElse> { |
| 98 | + // Same as above, but receives a `ResolvedVc`, which can be `.await`ed |
| 99 | + // to a `ReadRef` or dereferenced (implicitly or with `*`) to `Vc`. |
| 100 | + vdbg!(self.await?.some_field); |
| 101 | + |
| 102 | + // The `ResolvedVc<Self>` type can be used to call other methods |
| 103 | + // declared on `Vc<Self>`, e.g.: |
| 104 | + self.method_ref(a) |
| 105 | + } |
| 106 | + |
| 107 | + #[turbo_tasks::function] |
| 108 | + fn method_ref(&self, a: i32) -> Vc<SomethingElse> { |
| 109 | + // As a convenience, receives the fully resolved version of `self`. This |
| 110 | + // does not require `.await`ing to read. |
| 111 | + // |
| 112 | + // It can access fields on the struct/enum and call methods declared on |
| 113 | + // `Self`, but it cannot call other methods declared on `Vc<Self>` |
| 114 | + // (without cloning the value and re-wrapping it in a `Vc`). |
| 115 | + Vc::cell(SomethingElse::new(self.some_field, a)) |
| 116 | + } |
| 117 | +} |
| 118 | +``` |
| 119 | + |
| 120 | +- **Declaration Location:** The methods are defined on [`Vc<T>`] (i.e. `Vc::<Something>::method` and `Vc::<Something>::method2`), not on the inner type. |
| 121 | + |
| 122 | +- **`&self` Syntactic Sugar:** The `&self` argument of a `#[turbo_tasks::function]` implicitly reads the value from `self: Vc<Self>`. |
| 123 | + |
| 124 | +- **External Signature Rewriting:** All of the signature rewrite rules apply here. `self` can be [`ResolvedVc<T>`]. `async` and `Result<Vc<T>>` return types are supported. |
| 125 | + |
| 126 | +### Trait Implementations |
| 127 | + |
| 128 | +```rust |
| 129 | +#[turbo_tasks::value_impl] |
| 130 | +impl Trait for Something { |
| 131 | + #[turbo_tasks::function] |
| 132 | + fn method(self: Vc<Self>, a: i32) -> Vc<SomethingElse> { |
| 133 | + // Trait method implementation... |
| 134 | + // |
| 135 | + // `self: ResolvedVc<Self>` and `&self` are also valid argument types! |
| 136 | + } |
| 137 | +} |
| 138 | +``` |
| 139 | + |
| 140 | +For traits, only the external signature (after rewriting) must align with the trait definition. |
0 commit comments