Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs(turbo-tasks): Rewrite the turbo_tasks::value documentation #70743

Merged
merged 3 commits into from
Oct 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 0 additions & 77 deletions turbopack/crates/turbo-tasks-macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,83 +47,6 @@ pub fn derive_task_input(input: TokenStream) -> TokenStream {
derive::derive_task_input(input)
}

/// Creates a Vc<Value> struct for a `struct` or `enum` that represent
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This had to be moved into the turbo-tasks crate's re-export of this macro, otherwise it's not possible for any of the intra-doc links to work: https://doc.rust-lang.org/rustdoc/write-documentation/linking-to-items-by-name.html#warnings-re-exports-and-scoping

When re-exporting an item, rustdoc allows adding additional documentation to it. That additional documentation will be resolved in the scope of the re-export, not the original, allowing you to link to items in the new crate. The new links will still give a warning if they fail to resolve.

This is especially useful for proc-macros, which must always be defined in their own dedicated crate.

/// that type placed into a cell in a Task.
///
/// That Vc<Value> 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<Value> implement `From<Value>` to allow to convert
/// a Value to a Vc<Value> 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<Value>`.
///
/// ### `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]
Expand Down
6 changes: 3 additions & 3 deletions turbopack/crates/turbo-tasks-macros/src/value_macro.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<turbo_tasks::Vc<#ident>> 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()
Comment on lines +342 to +344
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This probably dated back to before Rust 1.41:

Only implement Into when targeting a version prior to Rust 1.41 and converting to a type outside the current crate. From was not able to do these types of conversions in earlier versions because of Rust’s orphaning rules. See Into for more details.

-- https://doc.rust-lang.org/std/convert/trait.From.html

Best-practice these days is to implement From and then use the blanket auto-impl of Into.

}
}
}
Expand Down
105 changes: 104 additions & 1 deletion turbopack/crates/turbo-tasks/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand All @@ -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<u32>);
/// ```
///
/// ## `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<Self>;
/// ```
///
/// This argument controls the visibility of the `.cell()` method, as well as whether a
/// [`From<T> for Vc<T>`][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<TaskId, BuildHasherDefault<FxHasher>, 2>;

pub mod test_helpers {
Expand Down
2 changes: 1 addition & 1 deletion turbopack/crates/turbo-tasks/src/vc/resolved.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,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<T: ?Sized + Send + ResolvedValue> ResolvedValue for ResolvedVc<T> {}
Expand Down
10 changes: 5 additions & 5 deletions turbopack/crates/turbo-tasks/src/vc/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {}
Loading