Implement TaskInput derive macro (#4828)
This PR implements a `TaskInput` derive macro that allows users to
define structures and enums that can be directly passed as arguments to
`tt::function`s, provided they are composed exclusively of other
`TaskInput` implementors (i.e. primitives for which we've manually
implemented `TaskInput`, `Vc`s, and other structs that derive
`TaskInput`).
There are a lot of cases in Turbopack where we'd like to pass more
advanced structures to `tt::function`s, but since there's no existing
way to create composite structures and enums from existing `Vc`s and
primitives, we end up with the following recurring patterns:
### Functions that have 6+ arguments
For example:
```rust
#[turbo_tasks::function]
fn do_something(a: A, b: B, c: C, d: D, e: E, f: F) {
// ...
}
```
By creating composite structures with arguments that are often used
together and passed down the call tree, this can instead become:
```rust
#[derive(TaskInput, Clone)]
struct Args1 {
a: A,
b: B,
}
#[derive(TaskInput, Clone)]
struct Args2 {
c: C,
d: D,
e: E,
}
#[turbo_tasks::function]
fn do_something(args1: Args1, args2: Args2, f: F) {
// ...
}
```
### Multiple optional arguments
... where only specific combinations make sense.
```rust
#[turbo_tasks::function]
fn do_something(value1: SomeVc, value2: Option<OtherVc>, value3: Option<AnotherVc>) {
if let (Some(value2), Some(value3)) = (value2, value3) {
// ...
}
// ...
}
```
In this example, `value2` might only make sense when `value3` is also
provided. An enum would be better in this case:
```rust
#[derive(Clone, TaskInput)
enum CustomEnum {
NoValues,
Values {
value2: OtherVc,
value3: AnotherVc,
}
}
#[turbo_tasks::function]
fn do_something(value1: SomeVc, values: CustomEnum) {
if let CustomEnum::Values { value2, value3 } = values {
// ...
}
// ...
}
```
### `Value<T>` and `serialization = "auto_for_input"`
For example:
```rust
#[turbo_tasks::value(serialization = "auto_for_input")]
#[derive(PartialOrd, Ord, Debug, Hash, Clone, Copy)]
pub enum SomeArgument {
A,
B,
...
}
// and then later
some_function(Value::new(SomeArgument::B))
```
This can now be replaced with:
```rust
#[derive(TaskInput, Clone)]
pub enum SomeArgument {
A,
B,
...
}
// and then later
some_function(SomeArgument::B)
```
Apart from conciseness and fewer trait bounds, another benefit of this
approach is that `SomeArgument` cannot be (mis)used as a `Vc`, which we
always generate via the `turbo_tasks::value` proc macro.
### How does it work?
The derive macro generates code to convert enums and structs into a list
of `TaskInput`s, similarly to how `FromTaskInput` was previously
implemented for tuples. We use an additional integer discriminant to
differentiate between enum variants.
### Concerns
A potential concern of this approach is that these `TaskInput`s will be
cloned on every single task execution. As such, they should be as
lightweight as possible, and implement `Copy` where it makes sense.
### Testing Instructions
I added a series of tests in turbo-tasks-memory.
link WEB-945