Skip to content

Commit

Permalink
Reduce amount of code generated by ValueDebugFormat
Browse files Browse the repository at this point in the history
  • Loading branch information
bgw committed May 28, 2024
1 parent 9765fe8 commit 649143c
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 22 deletions.
7 changes: 6 additions & 1 deletion crates/turbo-tasks-macros-shared/src/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,15 @@ pub fn expand_fields<
expand_unnamed: EU,
expand_unit: U,
) -> R {
if fields.is_empty() {
// any empty struct (regardless of the syntax used during declaration) is
// equivalent to a unit struct
return expand_unit(ident);
}
match fields {
Fields::Named(named) => expand_named(ident, named),
Fields::Unnamed(unnamed) => expand_unnamed(ident, unnamed),
Fields::Unit => expand_unit(ident),
Fields::Unit => unreachable!(),
}
}

Expand Down
56 changes: 36 additions & 20 deletions crates/turbo-tasks-macros/src/derive/value_debug_format_macro.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,27 +56,35 @@ pub fn derive_value_debug_format(input: TokenStream) -> TokenStream {
/// Formats a single field nested inside named or unnamed fields.
fn format_field(value: TokenStream2) -> TokenStream2 {
quote! {
turbo_tasks::macro_helpers::value_debug_format_field(#value.value_debug_format(depth.saturating_sub(1))).await
turbo_tasks::macro_helpers::value_debug_format_field(#value.value_debug_format(depth.saturating_sub(1)))
}
}

/// Formats a struct or enum variant with named fields (e.g. `struct Foo {
/// bar: u32 }`, `Foo::Bar { baz: u32 }`).
fn format_named(ident: &Ident, fields: &FieldsNamed) -> (TokenStream2, TokenStream2) {
let (captures, fields_idents) = generate_destructuring(fields.named.iter(), &filter_field);
let fields_values = fields_idents.iter().cloned().map(format_field);
(
captures,
quote! {
FormattingStruct::new_named(
stringify!(#ident),
vec![#(
FormattingField::new(
stringify!(#fields_idents),
#fields_values,
),
)*],
)
if fields_idents.is_empty() {
// this can happen if all fields are ignored, we must special-case this to avoid
// rustc being unable to infer the type of an empty vec of futures
quote! {
FormattingStruct::new_named(stringify!(#ident), vec![])
}
} else {
let fields_values = fields_idents.iter().cloned().map(format_field);
quote! {
FormattingStruct::new_named_async(
stringify!(#ident),
vec![#(
AsyncFormattingField::new(
stringify!(#fields_idents),
#fields_values,
),
)*],
).await
}
},
)
}
Expand All @@ -85,16 +93,24 @@ fn format_named(ident: &Ident, fields: &FieldsNamed) -> (TokenStream2, TokenStre
/// Foo(u32)`, `Foo::Bar(u32)`).
fn format_unnamed(ident: &Ident, fields: &FieldsUnnamed) -> (TokenStream2, TokenStream2) {
let (captures, fields_idents) = generate_destructuring(fields.unnamed.iter(), &filter_field);
let fields_values = fields_idents.into_iter().map(format_field);
(
captures,
quote! {
FormattingStruct::new_unnamed(
stringify!(#ident),
vec![#(
#fields_values,
)*],
)
if fields_idents.is_empty() {
// this can happen if all fields are ignored, we must special-case this to avoid
// rustc being unable to infer the type of an empty vec of futures
quote! {
FormattingStruct::new_unnamed(stringify!(#ident), vec![])
}
} else {
let fields_values = fields_idents.into_iter().map(format_field);
quote! {
FormattingStruct::new_unnamed_async(
stringify!(#ident),
vec![#(
#fields_values,
)*],
).await
}
},
)
}
Expand Down
51 changes: 50 additions & 1 deletion crates/turbo-tasks/src/debug/internal.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::borrow::Cow;
use std::{borrow::Cow, future::Future};

use futures::future::join_all;
pub use turbo_tasks_macros::ValueDebug;

/// Representation of a named field of a structure for formatting purposes of
Expand All @@ -16,6 +17,34 @@ impl<'a> FormattingField<'a> {
}
}

/// Representation of a named field of a structure for formatting purposes of
/// `ValueDebug` implementations.
#[derive(Debug)]
pub struct AsyncFormattingField<'a, Fut>
where
Fut: Future<Output = String>,
{
name: &'a str,
contents: Fut,
}

impl<'a, Fut: Future<Output = String>> AsyncFormattingField<'a, Fut>
where
Fut: Future<Output = String>,
{
pub fn new(name: &'a str, contents: Fut) -> Self {
Self { name, contents }
}

pub async fn resolve(self) -> FormattingField<'a> {
let Self { name, contents } = self;
FormattingField {
name,
contents: contents.await,
}
}
}

/// Representation of a structure for formatting purposes of `ValueDebug`
/// implementations.
pub enum FormattingStruct<'a> {
Expand All @@ -36,6 +65,26 @@ impl<'a> FormattingStruct<'a> {
pub fn new_unnamed(name: &'a str, fields: Vec<String>) -> Self {
Self::Unnamed { name, fields }
}

pub async fn new_named_async(
name: &'a str,
fields: Vec<AsyncFormattingField<'a, impl Future<Output = String>>>,
) -> Self {
Self::Named {
name,
fields: join_all(fields.into_iter().map(AsyncFormattingField::resolve)).await,
}
}

pub async fn new_unnamed_async(
name: &'a str,
fields: Vec<impl Future<Output = String>>,
) -> Self {
Self::Unnamed {
name,
fields: join_all(fields).await,
}
}
}

impl<'a> std::fmt::Debug for FormattingStruct<'a> {
Expand Down

0 comments on commit 649143c

Please sign in to comment.