Skip to content

Commit

Permalink
Add derive macro for ResolvedValue
Browse files Browse the repository at this point in the history
  • Loading branch information
bgw committed Jul 5, 2024
1 parent 1903a1a commit 135d59a
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 0 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions crates/turbo-tasks-macros-tests/tests/derive_resolved_value.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
use turbo_tasks::{ResolvedValue, ResolvedVc, Vc};

#[derive(ResolvedValue)]
struct ContainsResolvedVc {
a: ResolvedVc<i32>,
}

#[derive(ResolvedValue)]
struct ContainsVc {
a: Vc<i32>,
}

#[derive(ResolvedValue)]
struct ContainsMixedVc {
a: Vc<i32>,
b: ResolvedVc<i32>,
}
1 change: 1 addition & 0 deletions crates/turbo-tasks-macros/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ workspace = true

[dependencies]
anyhow = { workspace = true }
either = { workspace = true }
proc-macro-error = "1.0.4"
proc-macro2 = { workspace = true }
quote = { workspace = true }
Expand Down
2 changes: 2 additions & 0 deletions crates/turbo-tasks-macros/src/derive/mod.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
mod deterministic_hash_macro;
mod resolved_value_macro;
mod task_input_macro;
mod trace_raw_vcs_macro;
mod value_debug_format_macro;
mod value_debug_macro;

pub use deterministic_hash_macro::derive_deterministic_hash;
pub use resolved_value_macro::derive_resolved_value;
use syn::{spanned::Spanned, Attribute, Meta, MetaList, NestedMeta};
pub use task_input_macro::derive_task_input;
pub use trace_raw_vcs_macro::derive_trace_raw_vcs;
Expand Down
50 changes: 50 additions & 0 deletions crates/turbo-tasks-macros/src/derive/resolved_value_macro.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
use either::Either;
use proc_macro::TokenStream;
use proc_macro2::TokenStream as TokenStream2;
use quote::{quote, quote_spanned};
use syn::{parse_macro_input, spanned::Spanned, Data, DeriveInput, Generics, Type};

pub fn derive_resolved_value(input: TokenStream) -> TokenStream {
let derive_input = parse_macro_input!(input as DeriveInput);
let ident = &derive_input.ident;

let assertions: Vec<_> = iter_data_fields(&derive_input.data)
.map(|f| assert_field_resolved_value(&derive_input.generics, &f.ty))
.collect();

let (impl_generics, ty_generics, where_clause) = derive_input.generics.split_for_impl();
quote! {
unsafe impl #impl_generics ::turbo_tasks::ResolvedValue
for #ident #ty_generics #where_clause {}
#(#assertions)*
}
.into()
}

fn iter_data_fields(data: &Data) -> impl Iterator<Item = &syn::Field> {
match data {
Data::Struct(ds) => Either::Left(ds.fields.iter()),
Data::Enum(de) => Either::Right(Either::Left(de.variants.iter().flat_map(|v| &v.fields))),
Data::Union(du) => Either::Right(Either::Right(du.fields.named.iter())),
}
}

fn assert_field_resolved_value(generics: &Generics, ty: &Type) -> TokenStream2 {
// this technique is based on the trick used by
// `static_assertions::assert_impl_all`, but extended to support generics.
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
quote_spanned! {
ty.span() =>
const _: fn() = || {
// create this struct just to hold onto our generics
struct StaticAssertion #impl_generics #where_clause;
impl #impl_generics StaticAssertion #ty_generics #where_clause {
fn assert_impl_resolved_value<ExpectedResolvedValue: ResolvedValue + ?Sized>() {}
fn call_site() {
// this call is only valid if ty is a ResolvedValue
Self::assert_impl_resolved_value::<#ty>();
}
}
};
}
}
5 changes: 5 additions & 0 deletions crates/turbo-tasks-macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ pub fn derive_trace_raw_vcs_attr(input: TokenStream) -> TokenStream {
derive::derive_trace_raw_vcs(input)
}

#[proc_macro_derive(ResolvedValue, attributes(turbo_tasks))]
pub fn derive_resolved_value_attr(input: TokenStream) -> TokenStream {
derive::derive_resolved_value(input)
}

#[proc_macro_derive(ValueDebug, attributes(turbo_tasks))]
pub fn derive_value_debug_attr(input: TokenStream) -> TokenStream {
derive::derive_value_debug(input)
Expand Down
2 changes: 2 additions & 0 deletions crates/turbo-tasks/src/vc/resolved.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,5 @@ unsafe impl<T: ResolvedValue + ?Sized> ResolvedValue for Arc<T> {}
unsafe impl<T: ResolvedValue, E: ResolvedValue> ResolvedValue for Result<T, E> {}
unsafe impl<T: ResolvedValue + ?Sized> ResolvedValue for Mutex<T> {}
unsafe impl<T: ResolvedValue + ?Sized> ResolvedValue for RefCell<T> {}

pub use turbo_tasks_macros::ResolvedValue;

0 comments on commit 135d59a

Please sign in to comment.