Skip to content

Commit

Permalink
Misc comments in turbo_tasks (vercel/turborepo#5723)
Browse files Browse the repository at this point in the history
### Description

Adds some comments to explain some of the implementation details of the
`Vc<T>` PR.

Closes WEB-1380
  • Loading branch information
alexkirsz authored Aug 16, 2023
1 parent 391cf96 commit dc1b05e
Show file tree
Hide file tree
Showing 7 changed files with 68 additions and 5 deletions.
6 changes: 6 additions & 0 deletions crates/turbo-tasks/src/task/concrete_task_input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,12 @@ impl<'de> Deserialize<'de> for SharedValue {
}
}

/// Intermediate representation of task inputs.
///
/// When a task is called, all its arguments will be converted and stored as
/// [`ConcreteTaskInput`]s. When the task is actually run, these inputs will be
/// converted back into the argument types. This is handled by the [`TaskInput`]
/// trait.
#[allow(clippy::derived_hash_with_manual_eq)]
#[derive(Debug, Hash, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum ConcreteTaskInput {
Expand Down
32 changes: 30 additions & 2 deletions crates/turbo-tasks/src/task/function.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,26 @@
//! # Function tasks
//!
//! This module contains the trait definitions and implementations that are
//! necessary for accepting functions as tasks when using the
//! `turbo_tasks::function` macro.
//!
//! This system is inspired by Bevy's Systems and Axum's Handlers.
//!
//! The original principle is somewhat simple: a function is accepted if all
//! of its arguments implement `TaskInput` and its return type implements
//! `TaskOutput`. There are a few hoops one needs to jump through to make this
//! work, but they are described in this blog post:
//! https://blog.logrocket.com/rust-bevy-entity-component-system/
//!
//! However, there are is an additional complication in our case: async methods
//! that accept a reference to the receiver as their first argument.
//!
//! This complication handled through our own version of the `async_trait`
//! crate, which allows us to target `async fn` as trait bounds. The naive
//! approach runs into many issues with lifetimes, hence the need for an
//! intermediate trait. However, this implementation doesn't support all async
//! methods (see commented out tests).
use std::{future::Future, marker::PhantomData, pin::Pin};

use anyhow::{bail, Context, Result};
Expand Down Expand Up @@ -56,10 +79,15 @@ trait TaskFnInputFunction<Mode: TaskFnMode, Inputs: TaskInputs>: Send + Sync + C
fn functor(&self, name: &'static str, inputs: &[ConcreteTaskInput]) -> Result<NativeTaskFn>;
}

pub trait TaskFnMode: Send + Sync + 'static {}

pub trait TaskInputs: Send + Sync + 'static {}

/// Modes to allow multiple `TaskFnInputFunction` blanket implementations on
/// `Fn`s. Even though the implementations are non-conflicting in practice, they
/// could be in theory (at least from with the compiler's current limitations).
/// Despite this, the compiler is still able to infer the correct mode from a
/// function.
pub trait TaskFnMode: Send + Sync + 'static {}

pub struct FunctionMode;
impl TaskFnMode for FunctionMode {}

Expand Down
5 changes: 5 additions & 0 deletions crates/turbo-tasks/src/task/task_input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ use crate::{
TypedForInput, Value, Vc, VcValueType,
};

/// Trait to implement in order for a type to be accepted as a
/// `turbo_tasks::function` argument.
///
/// See also [`ConcreteTaskInput`].
pub trait TaskInput: Send + Sync + Clone {
fn try_from_concrete(input: &ConcreteTaskInput) -> Result<Self>;
fn into_concrete(self) -> ConcreteTaskInput;
Expand Down Expand Up @@ -306,6 +310,7 @@ macro_rules! tuple_impls {
};
}

// Implement `TaskInput` for all tuples of 1 to 12 elements.
tuple_impls! { A }
tuple_impls! { A B }
tuple_impls! { A B C }
Expand Down
2 changes: 2 additions & 0 deletions crates/turbo-tasks/src/task/task_output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ use anyhow::Result;

use crate::{unit, RawVc, Vc};

/// Trait to implement in order for a type to be accepted as a
/// `turbo_tasks::function` return type.
pub trait TaskOutput {
type Return;

Expand Down
12 changes: 11 additions & 1 deletion crates/turbo-tasks/src/unit.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
use crate::Vc;
use crate::{ValueDefault, Vc};

// TODO(alexkirsz) Should this be `#[turbo_tasks::function]` or is it okay to
// always return a new `Vc`?
pub fn unit() -> Vc<()> {
Vc::cell(())
}

impl ValueDefault for () {
// TODO(alexkirsz) Should this be `#[turbo_tasks::function]` or is it
// preferrable to always return a new `Vc`?
fn value_default() -> Vc<Self> {
Vc::cell(())
}
}
11 changes: 11 additions & 0 deletions crates/turbo-tasks/src/vc/default.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,17 @@ use turbo_tasks::Vc;

use crate::{self as turbo_tasks};

/// `Vc<T>` analog to the `Default` trait.
///
/// Implementing this trait on `T` will make `Vc::default()` produce
/// `T::value_default()`.
///
/// There are two ways to implement this trait:
/// 1. Annotating with `#[turbo_tasks::value_impl]`: this will make
/// `Vc::default()` always return the same underlying value (i.e. a
/// singleton).
/// 2. No annotations: this will make `Vc::default()` always return a different
/// value.
#[turbo_tasks::value_trait]
pub trait ValueDefault {
fn value_default() -> Vc<Self>;
Expand Down
5 changes: 3 additions & 2 deletions crates/turbo-tasks/src/vc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,16 @@ where
pub(crate) _t: PhantomData<T>,
}

/// This only exists to satisfy the Rust type system. However, this struct can
/// never actually be instantiated, as dereferencing a `Vc<T>` will result in a
/// linker error. See the implementation of `Deref` for `Vc<T>`.
pub struct VcDeref<T>
where
T: ?Sized,
{
_t: PhantomData<T>,
}

trait Impossible {}

macro_rules! do_not_use_or_you_will_be_fired {
($($name:ident)*) => {
impl<T> VcDeref<T>
Expand Down

0 comments on commit dc1b05e

Please sign in to comment.