 6f2a5cb862
			
		
	
	
		6f2a5cb862
		
			
		
	
	
	
	
		
			
			# Objective Simplify bind group creation code. alternative to (and based on) #9476 ## Solution - Add a `BindGroupEntries` struct that can transparently be used where `&[BindGroupEntry<'b>]` is required in BindGroupDescriptors. Allows constructing the descriptor's entries as: ```rust render_device.create_bind_group( "my_bind_group", &my_layout, &BindGroupEntries::with_indexes(( (2, &my_sampler), (3, my_uniform), )), ); ``` instead of ```rust render_device.create_bind_group( "my_bind_group", &my_layout, &[ BindGroupEntry { binding: 2, resource: BindingResource::Sampler(&my_sampler), }, BindGroupEntry { binding: 3, resource: my_uniform, }, ], ); ``` or ```rust render_device.create_bind_group( "my_bind_group", &my_layout, &BindGroupEntries::sequential((&my_sampler, my_uniform)), ); ``` instead of ```rust render_device.create_bind_group( "my_bind_group", &my_layout, &[ BindGroupEntry { binding: 0, resource: BindingResource::Sampler(&my_sampler), }, BindGroupEntry { binding: 1, resource: my_uniform, }, ], ); ``` the structs has no user facing macros, is tuple-type-based so stack allocated, and has no noticeable impact on compile time. - Also adds a `DynamicBindGroupEntries` struct with a similar api that uses a `Vec` under the hood and allows extending the entries. - Modifies `RenderDevice::create_bind_group` to take separate arguments `label`, `layout` and `entries` instead of a `BindGroupDescriptor` struct. The struct can't be stored due to the internal references, and with only 3 members arguably does not add enough context to justify itself. - Modify the codebase to use the new api and the `BindGroupEntries` / `DynamicBindGroupEntries` structs where appropriate (whenever the entries slice contains more than 1 member). ## Migration Guide - Calls to `RenderDevice::create_bind_group({BindGroupDescriptor { label, layout, entries })` must be amended to `RenderDevice::create_bind_group(label, layout, entries)`. - If `label`s have been specified as `"bind_group_name".into()`, they need to change to just `"bind_group_name"`. `Some("bind_group_name")` and `None` will still work, but `Some("bind_group_name")` can optionally be simplified to just `"bind_group_name"`. --------- Co-authored-by: IceSentry <IceSentry@users.noreply.github.com>
		
			
				
	
	
		
			174 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			174 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| use proc_macro::TokenStream;
 | |
| use quote::{format_ident, quote};
 | |
| use syn::{
 | |
|     parse::{Parse, ParseStream},
 | |
|     parse_macro_input,
 | |
|     token::Comma,
 | |
|     Ident, LitInt, Result,
 | |
| };
 | |
| struct AllTuples {
 | |
|     macro_ident: Ident,
 | |
|     start: usize,
 | |
|     end: usize,
 | |
|     idents: Vec<Ident>,
 | |
| }
 | |
| 
 | |
| impl Parse for AllTuples {
 | |
|     fn parse(input: ParseStream) -> Result<Self> {
 | |
|         let macro_ident = input.parse::<Ident>()?;
 | |
|         input.parse::<Comma>()?;
 | |
|         let start = input.parse::<LitInt>()?.base10_parse()?;
 | |
|         input.parse::<Comma>()?;
 | |
|         let end = input.parse::<LitInt>()?.base10_parse()?;
 | |
|         input.parse::<Comma>()?;
 | |
|         let mut idents = vec![input.parse::<Ident>()?];
 | |
|         while input.parse::<Comma>().is_ok() {
 | |
|             idents.push(input.parse::<Ident>()?);
 | |
|         }
 | |
| 
 | |
|         Ok(AllTuples {
 | |
|             macro_ident,
 | |
|             start,
 | |
|             end,
 | |
|             idents,
 | |
|         })
 | |
|     }
 | |
| }
 | |
| 
 | |
| /// Helper macro to generate tuple pyramids. Useful to generate scaffolding to work around Rust
 | |
| /// lacking variadics. Invoking `all_tuples!(impl_foo, start, end, P, Q, ..)`
 | |
| /// invokes `impl_foo` providing ident tuples through arity `start..=end`.
 | |
| /// # Examples
 | |
| /// A single parameter.
 | |
| /// ```
 | |
| /// use std::marker::PhantomData;
 | |
| /// use bevy_utils_proc_macros::all_tuples;
 | |
| ///
 | |
| /// struct Foo<T> {
 | |
| ///     // ..
 | |
| ///     _phantom: PhantomData<T>
 | |
| /// }
 | |
| ///
 | |
| /// trait WrappedInFoo {
 | |
| ///     type Tup;
 | |
| /// }
 | |
| ///
 | |
| /// macro_rules! impl_wrapped_in_foo {
 | |
| ///     ($($T:ident),*) => {
 | |
| ///         impl<$($T),*> WrappedInFoo for ($($T,)*) {
 | |
| ///             type Tup = ($(Foo<$T>,)*);
 | |
| ///         }
 | |
| ///     };
 | |
| /// }
 | |
| ///
 | |
| /// all_tuples!(impl_wrapped_in_foo, 0, 15, T);
 | |
| /// // impl_wrapped_in_foo!();
 | |
| /// // impl_wrapped_in_foo!(P0);
 | |
| /// // impl_wrapped_in_foo!(P0, P1);
 | |
| /// // ..
 | |
| /// // impl_wrapped_in_foo!(P0 .. P14);
 | |
| /// ```
 | |
| /// Multiple parameters.
 | |
| /// ```
 | |
| /// use bevy_utils_proc_macros::all_tuples;
 | |
| ///
 | |
| /// trait Append {
 | |
| ///     type Out<Item>;
 | |
| ///     fn append<Item>(tup: Self, item: Item) -> Self::Out<Item>;
 | |
| /// }
 | |
| ///
 | |
| /// impl Append for () {
 | |
| ///     type Out<Item> = (Item,);
 | |
| ///     fn append<Item>(_: Self, item: Item) -> Self::Out<Item> {
 | |
| ///         (item,)
 | |
| ///     }
 | |
| /// }
 | |
| ///
 | |
| /// macro_rules! impl_append {
 | |
| ///     ($(($P:ident, $p:ident)),*) => {
 | |
| ///         impl<$($P),*> Append for ($($P,)*) {
 | |
| ///             type Out<Item> = ($($P),*, Item);
 | |
| ///             fn append<Item>(($($p,)*): Self, item: Item) -> Self::Out<Item> {
 | |
| ///                 ($($p),*, item)
 | |
| ///             }
 | |
| ///         }
 | |
| ///     }
 | |
| /// }
 | |
| ///
 | |
| /// all_tuples!(impl_append, 1, 15, P, p);
 | |
| /// // impl_append!((P0, p0));
 | |
| /// // impl_append!((P0, p0), (P1, p1));
 | |
| /// // impl_append!((P0, p0), (P1, p1), (P2, p2));
 | |
| /// // ..
 | |
| /// // impl_append!((P0, p0) .. (P14, p14));
 | |
| /// ````
 | |
| #[proc_macro]
 | |
| pub fn all_tuples(input: TokenStream) -> TokenStream {
 | |
|     let input = parse_macro_input!(input as AllTuples);
 | |
|     let len = 1 + input.end - input.start;
 | |
|     let mut ident_tuples = Vec::with_capacity(len);
 | |
|     for i in 0..=len {
 | |
|         let idents = input
 | |
|             .idents
 | |
|             .iter()
 | |
|             .map(|ident| format_ident!("{}{}", ident, i));
 | |
|         if input.idents.len() < 2 {
 | |
|             ident_tuples.push(quote! {
 | |
|                 #(#idents)*
 | |
|             });
 | |
|         } else {
 | |
|             ident_tuples.push(quote! {
 | |
|                 (#(#idents),*)
 | |
|             });
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     let macro_ident = &input.macro_ident;
 | |
|     let invocations = (input.start..=input.end).map(|i| {
 | |
|         let ident_tuples = &ident_tuples[..i];
 | |
|         quote! {
 | |
|             #macro_ident!(#(#ident_tuples),*);
 | |
|         }
 | |
|     });
 | |
|     TokenStream::from(quote! {
 | |
|         #(
 | |
|             #invocations
 | |
|         )*
 | |
|     })
 | |
| }
 | |
| 
 | |
| #[proc_macro]
 | |
| pub fn all_tuples_with_size(input: TokenStream) -> TokenStream {
 | |
|     let input = parse_macro_input!(input as AllTuples);
 | |
|     let len = 1 + input.end - input.start;
 | |
|     let mut ident_tuples = Vec::with_capacity(len);
 | |
|     for i in 0..=len {
 | |
|         let idents = input
 | |
|             .idents
 | |
|             .iter()
 | |
|             .map(|ident| format_ident!("{}{}", ident, i));
 | |
|         if input.idents.len() < 2 {
 | |
|             ident_tuples.push(quote! {
 | |
|                 #(#idents)*
 | |
|             });
 | |
|         } else {
 | |
|             ident_tuples.push(quote! {
 | |
|                 (#(#idents),*)
 | |
|             });
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     let macro_ident = &input.macro_ident;
 | |
|     let invocations = (input.start..=input.end).map(|i| {
 | |
|         let ident_tuples = &ident_tuples[..i];
 | |
|         quote! {
 | |
|             #macro_ident!(#i, #(#ident_tuples),*);
 | |
|         }
 | |
|     });
 | |
|     TokenStream::from(quote! {
 | |
|         #(
 | |
|             #invocations
 | |
|         )*
 | |
|     })
 | |
| }
 |