From 7f5c64b295f872461898855d3d21fe7713f2a598 Mon Sep 17 00:00:00 2001 From: Benjamin Woodruff Date: Thu, 3 Oct 2024 21:09:37 -0700 Subject: [PATCH] docs(turbo-tasks): Rewrite the `turbo_tasks::value` documentation (#70743) This documentation contained broken links, broken formatting, grammatical mistakes, misleading or outdated information, incomplete information, and lacked context one why one might use the various arguments. ![Screenshot 2024-10-02 at 21-40-23 value in turbo_tasks - Rust.png](https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/HAZVitxRNnZz8QMiPn4a/4ed70252-9996-4070-843c-df510c664444.png) --- .../crates/turbo-tasks-macros/src/lib.rs | 77 ------------- .../turbo-tasks-macros/src/value_macro.rs | 6 +- turbopack/crates/turbo-tasks/src/lib.rs | 105 +++++++++++++++++- .../crates/turbo-tasks/src/vc/resolved.rs | 2 +- turbopack/crates/turbo-tasks/src/vc/traits.rs | 10 +- 5 files changed, 113 insertions(+), 87 deletions(-) diff --git a/turbopack/crates/turbo-tasks-macros/src/lib.rs b/turbopack/crates/turbo-tasks-macros/src/lib.rs index 75124c7ae8c0e..8e6358c47ed40 100644 --- a/turbopack/crates/turbo-tasks-macros/src/lib.rs +++ b/turbopack/crates/turbo-tasks-macros/src/lib.rs @@ -47,83 +47,6 @@ pub fn derive_task_input(input: TokenStream) -> TokenStream { derive::derive_task_input(input) } -/// Creates a Vc struct for a `struct` or `enum` that represent -/// that type placed into a cell in a Task. -/// -/// That Vc object can be `await`ed to get a readonly reference -/// to the value contained in the cell. -/// -/// ## Arguments -/// -/// Example: `#[turbo_tasks::value(into = "new", eq = "manual")]` -/// -/// ### `cell` -/// -/// Possible values: -/// -/// - "new": Always overrides the value in the cell. Invalidating all -/// dependent tasks. -/// - "shared" (default): Compares with the existing value in the cell, before -/// overriding it. Requires Value to implement [Eq]. -/// -/// ### `eq` -/// -/// Possible values: -/// -/// - "manual": Prevents deriving [Eq] so you can do it manually. -/// -/// ### `into` -/// -/// When provided the Vc implement `From` to allow to convert -/// a Value to a Vc by placing it into a cell in a Task. -/// -/// Possible values: -/// -/// - "new": Always overrides the value in the cell. Invalidating all -/// dependent tasks. -/// - "shared": Compares with the existing value in the cell, before -/// overriding it. Requires Value to implement [Eq]. -/// - "none" (default): Prevents implementing `From`. -/// -/// ### `serialization` -/// -/// Affects serialization via [serde::Serialize] and [serde::Deserialize]. -/// -/// Possible values: -/// -/// - "auto" (default): Derives the serialization traits and enabled serialization. -/// - "auto_for_input": Same as "auto", but also adds the marker trait [turbo_tasks::TypedForInput]. -/// - "custom": Prevents deriving the serialization traits, but still enables serialization (you -/// need to manually implement [serde::Serialize] and [serde::Deserialize]). -/// - "custom_for_input":Same as "auto", but also adds the marker trait -/// [turbo_tasks::TypedForInput]. -/// - "none": Disables serialization and prevents deriving the traits. -/// -/// ### `shared` -/// -/// Sets both `cell = "shared"` and `into = "shared"` -/// -/// No value. -/// -/// Example: `#[turbo_tasks::value(shared)]` -/// -/// ### `transparent` -/// -/// If applied to a unit struct (e.g. `struct Wrapper(Value)`) the outer struct -/// is skipped for all operations (cell, into, reading). -/// -/// No value. -/// -/// Example: `#[turbo_tasks::value(transparent)]` -/// -/// ### `resolved` -/// -/// A shorthand syntax for -/// [`#[derive(turbo_tasks::ResolvedValue)]`][macro@turbo_tasks::ResolvedValue] -/// -/// Example: `#[turbo_tasks::value(resolved)]` -/// -/// TODO: add more documentation: presets, traits #[allow_internal_unstable(min_specialization, into_future, trivial_bounds)] #[proc_macro_error] #[proc_macro_attribute] diff --git a/turbopack/crates/turbo-tasks-macros/src/value_macro.rs b/turbopack/crates/turbo-tasks-macros/src/value_macro.rs index 0319c9ea4a511..570aeea20b3f3 100644 --- a/turbopack/crates/turbo-tasks-macros/src/value_macro.rs +++ b/turbopack/crates/turbo-tasks-macros/src/value_macro.rs @@ -339,9 +339,9 @@ pub fn value(args: TokenStream, input: TokenStream) -> TokenStream { let into = if let IntoMode::New | IntoMode::Shared = into_mode { quote! { - impl Into> for #ident { - fn into(self) -> turbo_tasks::Vc<#ident> { - self.cell() + impl ::std::convert::From<#ident> for turbo_tasks::Vc<#ident> { + fn from(value: #ident) -> Self { + value.cell() } } } diff --git a/turbopack/crates/turbo-tasks/src/lib.rs b/turbopack/crates/turbo-tasks/src/lib.rs index a289b5ad18aea..b65a3ae423a27 100644 --- a/turbopack/crates/turbo-tasks/src/lib.rs +++ b/turbopack/crates/turbo-tasks/src/lib.rs @@ -107,7 +107,7 @@ pub use serialization_invalidation::SerializationInvalidator; pub use state::{State, TransientState}; pub use task::{task_input::TaskInput, SharedReference}; pub use trait_ref::{IntoTraitRef, TraitRef}; -pub use turbo_tasks_macros::{function, value, value_impl, value_trait, TaskInput}; +pub use turbo_tasks_macros::{function, value_impl, value_trait, TaskInput}; pub use value::{TransientInstance, TransientValue, Value}; pub use value_type::{TraitMethod, TraitType, ValueType}; pub use vc::{ @@ -118,6 +118,109 @@ pub use vc::{ pub use crate::rcstr::RcStr; +/// Implements [`VcValueType`] for the given `struct` or `enum`. These value types can be used +/// inside of a "value cell" as [`Vc<...>`][Vc]. +/// +/// A [`Vc`] represents a (potentially lazy) memoized computation. Each [`Vc`]'s value is placed +/// into a cell associated with the current [`TaskId`]. That [`Vc`] object can be `await`ed to get +/// [a read-only reference to the value contained in the cell][ReadRef]. +/// +/// This macro accepts multiple comma-separated arguments. For example: +/// +/// ``` +/// # #![feature(arbitrary_self_types)] +/// #[turbo_tasks::value(transparent, into = "shared")] +/// struct Foo(Vec); +/// ``` +/// +/// ## `cell = "..."` +/// +/// Controls when a cell is invalidated upon recomputation of a task. Internally, this is performed +/// by setting the [`VcValueType::CellMode`] associated type. +/// +/// - **`"new"`:** Always overrides the value in the cell, invalidating all dependent tasks. +/// - **`"shared"` *(default)*:** Compares with the existing value in the cell, before overriding it. +/// Requires the value to implement [`Eq`]. +/// +/// Avoiding unnecessary invalidation is important to reduce downstream recomputation of tasks that +/// depend on this cell's value. +/// +/// Use `"new"` only if a correct implementation of [`Eq`] is not possible, would be expensive (e.g. +/// would require comparing a large collection), or if you're implementing a low-level primitive +/// that intentionally forces recomputation. +/// +/// ## `eq = "..."` +/// +/// By default, we `#[derive(PartialEq, Eq)]`. [`Eq`] is required by `cell = "shared"`. This +/// argument allows overriding that default implementation behavior. +/// +/// - **`"manual"`:** Prevents deriving [`Eq`] and [`PartialEq`] so you can do it manually. +/// +/// ## `into = "..."` +/// +/// This macro always implements a `.cell()` method on your type with the signature: +/// +/// ```ignore +/// /// Wraps the value in a cell. +/// fn cell(self) -> Vc; +/// ``` +/// +/// This argument controls the visibility of the `.cell()` method, as well as whether a +/// [`From for Vc`][From] implementation is generated. +/// +/// - **`"new"` or `"shared"`:** Exposes both `.cell()` and [`From`]/[`Into`] implementations. Both +/// of these values (`"new"` or `"shared"`) do the same thing (for legacy reasons). +/// - **`"none"` *(default)*:** Makes `.cell()` private and prevents implementing [`From`]/[`Into`]. +/// +/// You should use the default value of `"none"` when providing your own public constructor methods. +/// +/// The naming of this field and it's values are due to legacy reasons. +/// +/// ## `serialization = "..."` +/// +/// Affects serialization via [`serde::Serialize`] and [`serde::Deserialize`]. Serialization is +/// required for persistent caching of tasks to disk. +/// +/// - **`"auto"` *(default)*:** Derives the serialization traits and enables serialization. +/// - **`"auto_for_input"`:** Same as `"auto"`, but also adds the marker trait [`TypedForInput`]. +/// - **`"custom"`:** Prevents deriving the serialization traits, but still enables serialization +/// (you must manually implement [`serde::Serialize`] and [`serde::Deserialize`]). +/// - **`"custom_for_input"`:** Same as `"custom"`, but also adds the marker trait +/// [`TypedForInput`]. +/// - **`"none"`:** Disables serialization and prevents deriving the traits. +/// +/// ## `shared` +/// +/// Sets both `cell = "shared"` *(already the default)* and `into = "shared"`, exposing the +/// `.cell()` method and adding a [`From`]/[`Into`] implementation. +/// +/// ## `transparent` +/// +/// This attribute is only valid on single-element unit structs. When this value is set: +/// +/// 1. The struct will use [`#[repr(transparent)]`][repr-transparent]. +/// 1. Read operations (`vc.await?`) return a [`ReadRef`] containing the inner type, rather than the +/// outer struct. Internally, this is accomplished using [`VcTransparentRead`] for the +/// [`VcValueType::Read`] associated type. +/// 1. Construction of the type must be performed using [`Vc::cell(inner)`][Vc::cell], rather than +/// using the `.cell()` method on the outer type (`outer.cell()`). +/// 1. The [`ValueDebug`][crate::debug::ValueDebug] implementation will defer to the inner type. +/// +/// This is commonly used to create [`VcValueType`] wrappers for foreign or generic types, such as +/// [`Vec`] or [`Option`]. +/// +/// [repr-transparent]: https://doc.rust-lang.org/nomicon/other-reprs.html#reprtransparent +/// +/// ## `resolved` +/// +/// Applies the [`#[derive(ResolvedValue)]`][macro@ResolvedValue] macro. +/// +/// Indicates that this struct has no fields containing [`Vc`] by implementing the [`ResolvedValue`] +/// marker trait. In order to safely implement [`ResolvedValue`], this inserts compile-time +/// assertions that every field in this struct has a type that is also a [`ResolvedValue`]. +#[rustfmt::skip] +pub use turbo_tasks_macros::value; + pub type TaskIdSet = AutoSet, 2>; pub mod test_helpers { diff --git a/turbopack/crates/turbo-tasks/src/vc/resolved.rs b/turbopack/crates/turbo-tasks/src/vc/resolved.rs index 3f194faed1567..3b85ff4a6e584 100644 --- a/turbopack/crates/turbo-tasks/src/vc/resolved.rs +++ b/turbopack/crates/turbo-tasks/src/vc/resolved.rs @@ -222,7 +222,7 @@ where /// /// This trait is marked as unsafe. You should not derive it yourself, but /// instead you should rely on [`#[turbo_tasks::value(resolved)]`][macro@ -/// turbo_tasks::value] to do it for you. +/// crate::value] to do it for you. pub unsafe trait ResolvedValue {} unsafe impl ResolvedValue for ResolvedVc {} diff --git a/turbopack/crates/turbo-tasks/src/vc/traits.rs b/turbopack/crates/turbo-tasks/src/vc/traits.rs index 526db09af974b..a4dbad46e5c35 100644 --- a/turbopack/crates/turbo-tasks/src/vc/traits.rs +++ b/turbopack/crates/turbo-tasks/src/vc/traits.rs @@ -54,9 +54,9 @@ where { } -/// Marker trait that a turbo_tasks::value is prepared for -/// serialization as [`Value<...>`][crate::Value] input. -/// Either use [`#[turbo_tasks::value(serialization: -/// auto_for_input)]`][macro@crate::value] or avoid [`Value<...>`][crate::Value] -/// in favor of a real [Vc][crate::Vc]. +/// Marker trait that a turbo_tasks::value is prepared for serialization as +/// [`Value<...>`][crate::Value] input. +/// +/// Either use [`#[turbo_tasks::value(serialization = "auto_for_input")]`][macro@crate::value] or +/// avoid [`Value<...>`][crate::Value] in favor of a real [Vc][crate::Vc]. pub trait TypedForInput: VcValueType {}