Move all_tuples
to a new crate (#16161)
# Objective Fixes #15941 ## Solution Created https://crates.io/crates/variadics_please and moved the code there; updating references `bevy_utils/macros` is deleted. ## Testing cargo check ## Migration Guide Use `variadics_please::{all_tuples, all_tuples_with_size}` instead of `bevy::utils::{all_tuples, all_tuples_with_size}`.
This commit is contained in:
parent
2e267bba5a
commit
afd0f1322d
@ -34,6 +34,7 @@ derive_more = { version = "1", default-features = false, features = [
|
|||||||
"from",
|
"from",
|
||||||
"display",
|
"display",
|
||||||
] }
|
] }
|
||||||
|
variadics_please = "1.0"
|
||||||
|
|
||||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||||
ctrlc = "3.4.4"
|
ctrlc = "3.4.4"
|
||||||
|
@ -129,7 +129,7 @@ pub trait Plugins<Marker>: sealed::Plugins<Marker> {}
|
|||||||
impl<Marker, T> Plugins<Marker> for T where T: sealed::Plugins<Marker> {}
|
impl<Marker, T> Plugins<Marker> for T where T: sealed::Plugins<Marker> {}
|
||||||
|
|
||||||
mod sealed {
|
mod sealed {
|
||||||
use bevy_utils::all_tuples;
|
use variadics_please::all_tuples;
|
||||||
|
|
||||||
use crate::{App, AppError, Plugin, PluginGroup};
|
use crate::{App, AppError, Plugin, PluginGroup};
|
||||||
|
|
||||||
|
@ -43,6 +43,7 @@ derive_more = { version = "1", default-features = false, features = [
|
|||||||
nonmax = "0.5"
|
nonmax = "0.5"
|
||||||
arrayvec = { version = "0.7.4", optional = true }
|
arrayvec = { version = "0.7.4", optional = true }
|
||||||
smallvec = { version = "1", features = ["union"] }
|
smallvec = { version = "1", features = ["union"] }
|
||||||
|
variadics_please = "1.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
rand = "0.8"
|
rand = "0.8"
|
||||||
|
@ -21,10 +21,11 @@ use crate::{
|
|||||||
world::{unsafe_world_cell::UnsafeWorldCell, ON_ADD, ON_INSERT, ON_REPLACE},
|
world::{unsafe_world_cell::UnsafeWorldCell, ON_ADD, ON_INSERT, ON_REPLACE},
|
||||||
};
|
};
|
||||||
use bevy_ptr::{ConstNonNull, OwningPtr};
|
use bevy_ptr::{ConstNonNull, OwningPtr};
|
||||||
use bevy_utils::{all_tuples, HashMap, HashSet, TypeIdMap};
|
use bevy_utils::{HashMap, HashSet, TypeIdMap};
|
||||||
#[cfg(feature = "track_change_detection")]
|
#[cfg(feature = "track_change_detection")]
|
||||||
use core::panic::Location;
|
use core::panic::Location;
|
||||||
use core::{any::TypeId, ptr::NonNull};
|
use core::{any::TypeId, ptr::NonNull};
|
||||||
|
use variadics_please::all_tuples;
|
||||||
|
|
||||||
/// The `Bundle` trait enables insertion and removal of [`Component`]s from an entity.
|
/// The `Bundle` trait enables insertion and removal of [`Component`]s from an entity.
|
||||||
///
|
///
|
||||||
|
@ -12,9 +12,9 @@ use crate::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
use bevy_ptr::{ThinSlicePtr, UnsafeCellDeref};
|
use bevy_ptr::{ThinSlicePtr, UnsafeCellDeref};
|
||||||
use bevy_utils::all_tuples;
|
|
||||||
use core::{cell::UnsafeCell, marker::PhantomData};
|
use core::{cell::UnsafeCell, marker::PhantomData};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
use variadics_please::all_tuples;
|
||||||
|
|
||||||
/// Types that can be fetched from a [`World`] using a [`Query`].
|
/// Types that can be fetched from a [`World`] using a [`Query`].
|
||||||
///
|
///
|
||||||
|
@ -7,8 +7,8 @@ use crate::{
|
|||||||
world::{unsafe_world_cell::UnsafeWorldCell, World},
|
world::{unsafe_world_cell::UnsafeWorldCell, World},
|
||||||
};
|
};
|
||||||
use bevy_ptr::{ThinSlicePtr, UnsafeCellDeref};
|
use bevy_ptr::{ThinSlicePtr, UnsafeCellDeref};
|
||||||
use bevy_utils::all_tuples;
|
|
||||||
use core::{cell::UnsafeCell, marker::PhantomData};
|
use core::{cell::UnsafeCell, marker::PhantomData};
|
||||||
|
use variadics_please::all_tuples;
|
||||||
|
|
||||||
/// Types that filter the results of a [`Query`].
|
/// Types that filter the results of a [`Query`].
|
||||||
///
|
///
|
||||||
|
@ -6,7 +6,7 @@ use crate::{
|
|||||||
storage::{Table, TableRow},
|
storage::{Table, TableRow},
|
||||||
world::{unsafe_world_cell::UnsafeWorldCell, World},
|
world::{unsafe_world_cell::UnsafeWorldCell, World},
|
||||||
};
|
};
|
||||||
use bevy_utils::all_tuples;
|
use variadics_please::all_tuples;
|
||||||
|
|
||||||
/// Types that can be used as parameters in a [`Query`].
|
/// Types that can be used as parameters in a [`Query`].
|
||||||
/// Types that implement this should also implement either [`QueryData`] or [`QueryFilter`]
|
/// Types that implement this should also implement either [`QueryData`] or [`QueryFilter`]
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use bevy_utils::all_tuples;
|
use variadics_please::all_tuples;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
schedule::{
|
schedule::{
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use bevy_utils::{all_tuples, synccell::SyncCell};
|
use bevy_utils::synccell::SyncCell;
|
||||||
|
use variadics_please::all_tuples;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
prelude::QueryBuilder,
|
prelude::QueryBuilder,
|
||||||
|
@ -11,8 +11,8 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use alloc::borrow::Cow;
|
use alloc::borrow::Cow;
|
||||||
use bevy_utils::all_tuples;
|
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
use variadics_please::all_tuples;
|
||||||
|
|
||||||
/// A function system that runs with exclusive [`World`] access.
|
/// A function system that runs with exclusive [`World`] access.
|
||||||
///
|
///
|
||||||
|
@ -4,8 +4,9 @@ use crate::{
|
|||||||
system::{Local, SystemMeta, SystemParam, SystemState},
|
system::{Local, SystemMeta, SystemParam, SystemState},
|
||||||
world::World,
|
world::World,
|
||||||
};
|
};
|
||||||
use bevy_utils::{all_tuples, synccell::SyncCell};
|
use bevy_utils::synccell::SyncCell;
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
use variadics_please::all_tuples;
|
||||||
|
|
||||||
/// A parameter that can be used in an exclusive system (a system with an `&mut World` parameter).
|
/// A parameter that can be used in an exclusive system (a system with an `&mut World` parameter).
|
||||||
/// Any parameters implementing this trait must come after the `&mut World` parameter.
|
/// Any parameters implementing this trait must come after the `&mut World` parameter.
|
||||||
|
@ -12,8 +12,8 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use alloc::borrow::Cow;
|
use alloc::borrow::Cow;
|
||||||
use bevy_utils::all_tuples;
|
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
use variadics_please::all_tuples;
|
||||||
|
|
||||||
#[cfg(feature = "trace")]
|
#[cfg(feature = "trace")]
|
||||||
use bevy_utils::tracing::{info_span, Span};
|
use bevy_utils::tracing::{info_span, Span};
|
||||||
|
@ -19,7 +19,7 @@ use crate::{
|
|||||||
use bevy_ecs_macros::impl_param_set;
|
use bevy_ecs_macros::impl_param_set;
|
||||||
pub use bevy_ecs_macros::{Resource, SystemParam};
|
pub use bevy_ecs_macros::{Resource, SystemParam};
|
||||||
use bevy_ptr::UnsafeCellDeref;
|
use bevy_ptr::UnsafeCellDeref;
|
||||||
use bevy_utils::{all_tuples, synccell::SyncCell};
|
use bevy_utils::synccell::SyncCell;
|
||||||
#[cfg(feature = "track_change_detection")]
|
#[cfg(feature = "track_change_detection")]
|
||||||
use core::panic::Location;
|
use core::panic::Location;
|
||||||
use core::{
|
use core::{
|
||||||
@ -30,6 +30,7 @@ use core::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use super::Populated;
|
use super::Populated;
|
||||||
|
use variadics_please::all_tuples;
|
||||||
|
|
||||||
/// A parameter that can be used in a [`System`](super::System).
|
/// A parameter that can be used in a [`System`](super::System).
|
||||||
///
|
///
|
||||||
|
@ -51,6 +51,7 @@ glam = { version = "0.29", features = ["serde"], optional = true }
|
|||||||
petgraph = { version = "0.6", features = ["serde-1"], optional = true }
|
petgraph = { version = "0.6", features = ["serde-1"], optional = true }
|
||||||
smol_str = { version = "0.2.0", features = ["serde"], optional = true }
|
smol_str = { version = "0.2.0", features = ["serde"], optional = true }
|
||||||
uuid = { version = "1.0", optional = true, features = ["v4", "serde"] }
|
uuid = { version = "1.0", optional = true, features = ["v4", "serde"] }
|
||||||
|
variadics_please = "1.0"
|
||||||
wgpu-types = { version = "23", features = ["serde"], optional = true }
|
wgpu-types = { version = "23", features = ["serde"], optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use alloc::borrow::Cow;
|
use alloc::borrow::Cow;
|
||||||
|
|
||||||
use bevy_utils::all_tuples;
|
use variadics_please::all_tuples;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
func::args::{ArgInfo, GetOwnership, Ownership},
|
func::args::{ArgInfo, GetOwnership, Ownership},
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use bevy_utils::all_tuples;
|
use variadics_please::all_tuples;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
func::{
|
func::{
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use bevy_utils::all_tuples;
|
use variadics_please::all_tuples;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
func::{
|
func::{
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use bevy_reflect_derive::impl_type_path;
|
use bevy_reflect_derive::impl_type_path;
|
||||||
use bevy_utils::all_tuples;
|
use variadics_please::all_tuples;
|
||||||
|
|
||||||
use crate::generics::impl_generic_info_methods;
|
use crate::generics::impl_generic_info_methods;
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -95,6 +95,7 @@ async-channel = "2.3.0"
|
|||||||
nonmax = "0.5"
|
nonmax = "0.5"
|
||||||
smallvec = { version = "1.11", features = ["const_new"] }
|
smallvec = { version = "1.11", features = ["const_new"] }
|
||||||
offset-allocator = "0.2"
|
offset-allocator = "0.2"
|
||||||
|
variadics_please = "1.0"
|
||||||
|
|
||||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||||
# Omit the `glsl` feature in non-WebAssembly by default.
|
# Omit the `glsl` feature in non-WebAssembly by default.
|
||||||
|
@ -13,10 +13,10 @@ use bevy_ecs::{
|
|||||||
query::{QueryItem, QueryState, ReadOnlyQueryData},
|
query::{QueryItem, QueryState, ReadOnlyQueryData},
|
||||||
world::{FromWorld, World},
|
world::{FromWorld, World},
|
||||||
};
|
};
|
||||||
use bevy_utils::all_tuples_with_size;
|
|
||||||
use core::fmt::Debug;
|
use core::fmt::Debug;
|
||||||
use derive_more::derive::{Display, Error, From};
|
use derive_more::derive::{Display, Error, From};
|
||||||
use downcast_rs::{impl_downcast, Downcast};
|
use downcast_rs::{impl_downcast, Downcast};
|
||||||
|
use variadics_please::all_tuples_with_size;
|
||||||
|
|
||||||
pub use bevy_render_macros::RenderLabel;
|
pub use bevy_render_macros::RenderLabel;
|
||||||
|
|
||||||
|
@ -6,10 +6,11 @@ use bevy_ecs::{
|
|||||||
system::{ReadOnlySystemParam, Resource, SystemParam, SystemParamItem, SystemState},
|
system::{ReadOnlySystemParam, Resource, SystemParam, SystemParamItem, SystemState},
|
||||||
world::World,
|
world::World,
|
||||||
};
|
};
|
||||||
use bevy_utils::{all_tuples, TypeIdMap};
|
use bevy_utils::TypeIdMap;
|
||||||
use core::{any::TypeId, fmt::Debug, hash::Hash};
|
use core::{any::TypeId, fmt::Debug, hash::Hash};
|
||||||
use derive_more::derive::{Display, Error};
|
use derive_more::derive::{Display, Error};
|
||||||
use std::sync::{PoisonError, RwLock, RwLockReadGuard, RwLockWriteGuard};
|
use std::sync::{PoisonError, RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||||
|
use variadics_please::all_tuples;
|
||||||
|
|
||||||
/// A draw function used to draw [`PhaseItem`]s.
|
/// A draw function used to draw [`PhaseItem`]s.
|
||||||
///
|
///
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use bevy_utils::all_tuples_with_size;
|
use variadics_please::all_tuples_with_size;
|
||||||
use wgpu::{BindGroupEntry, BindingResource};
|
use wgpu::{BindGroupEntry, BindingResource};
|
||||||
|
|
||||||
use super::{Sampler, TextureView};
|
use super::{Sampler, TextureView};
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use bevy_utils::all_tuples_with_size;
|
|
||||||
use core::num::NonZero;
|
use core::num::NonZero;
|
||||||
|
use variadics_please::all_tuples_with_size;
|
||||||
use wgpu::{BindGroupLayoutEntry, BindingType, ShaderStages};
|
use wgpu::{BindGroupLayoutEntry, BindingType, ShaderStages};
|
||||||
|
|
||||||
/// Helper for constructing bind group layouts.
|
/// Helper for constructing bind group layouts.
|
||||||
|
@ -23,6 +23,7 @@ bevy_utils = { path = "../bevy_utils", version = "0.15.0-dev" }
|
|||||||
bevy_reflect = { path = "../bevy_reflect", version = "0.15.0-dev", optional = true }
|
bevy_reflect = { path = "../bevy_reflect", version = "0.15.0-dev", optional = true }
|
||||||
bevy_app = { path = "../bevy_app", version = "0.15.0-dev", optional = true }
|
bevy_app = { path = "../bevy_app", version = "0.15.0-dev", optional = true }
|
||||||
bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.15.0-dev", optional = true }
|
bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.15.0-dev", optional = true }
|
||||||
|
variadics_please = "1.0"
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
@ -3,7 +3,7 @@ use bevy_ecs::{
|
|||||||
schedule::{IntoSystemConfigs, IntoSystemSetConfigs, Schedule},
|
schedule::{IntoSystemConfigs, IntoSystemSetConfigs, Schedule},
|
||||||
system::{Commands, IntoSystem, Res, ResMut},
|
system::{Commands, IntoSystem, Res, ResMut},
|
||||||
};
|
};
|
||||||
use bevy_utils::all_tuples;
|
use variadics_please::all_tuples;
|
||||||
|
|
||||||
use self::sealed::StateSetSealed;
|
use self::sealed::StateSetSealed;
|
||||||
|
|
||||||
|
@ -26,7 +26,6 @@ ahash = { version = "0.8.7", default-features = false, features = [
|
|||||||
] }
|
] }
|
||||||
tracing = { version = "0.1", default-features = false }
|
tracing = { version = "0.1", default-features = false }
|
||||||
hashbrown = { version = "0.14.2", default-features = false }
|
hashbrown = { version = "0.14.2", default-features = false }
|
||||||
bevy_utils_proc_macros = { version = "0.15.0-dev", path = "macros" }
|
|
||||||
thread_local = { version = "1.0", optional = true }
|
thread_local = { version = "1.0", optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "bevy_utils_proc_macros"
|
|
||||||
version = "0.15.0-dev"
|
|
||||||
description = "Bevy Utils Proc Macros"
|
|
||||||
edition = "2021"
|
|
||||||
license = "MIT OR Apache-2.0"
|
|
||||||
repository = "https://github.com/bevyengine/bevy"
|
|
||||||
|
|
||||||
[lib]
|
|
||||||
proc-macro = true
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
syn = "2.0"
|
|
||||||
quote = "1.0"
|
|
||||||
proc-macro2 = "1.0"
|
|
||||||
|
|
||||||
[lints]
|
|
||||||
workspace = true
|
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
|
||||||
rustdoc-args = ["-Zunstable-options", "--generate-link-to-definition"]
|
|
||||||
all-features = true
|
|
@ -1,402 +0,0 @@
|
|||||||
// FIXME(15321): solve CI failures, then replace with `#![expect()]`.
|
|
||||||
#![allow(missing_docs, reason = "Not all docs are written yet, see #3492.")]
|
|
||||||
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
|
||||||
|
|
||||||
use proc_macro::TokenStream;
|
|
||||||
use proc_macro2::{Span as Span2, TokenStream as TokenStream2};
|
|
||||||
use quote::{format_ident, quote};
|
|
||||||
use syn::{
|
|
||||||
parse::{Parse, ParseStream},
|
|
||||||
parse_macro_input,
|
|
||||||
spanned::Spanned as _,
|
|
||||||
token::Comma,
|
|
||||||
Attribute, Error, Ident, LitInt, LitStr, Result,
|
|
||||||
};
|
|
||||||
struct AllTuples {
|
|
||||||
fake_variadic: bool,
|
|
||||||
macro_ident: Ident,
|
|
||||||
start: usize,
|
|
||||||
end: usize,
|
|
||||||
idents: Vec<Ident>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Parse for AllTuples {
|
|
||||||
fn parse(input: ParseStream) -> Result<Self> {
|
|
||||||
let fake_variadic = input.call(parse_fake_variadic_attr)?;
|
|
||||||
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>()?);
|
|
||||||
}
|
|
||||||
|
|
||||||
if start > 1 && fake_variadic {
|
|
||||||
return Err(Error::new(
|
|
||||||
input.span(),
|
|
||||||
"#[doc(fake_variadic)] only works when the tuple with length one is included",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(AllTuples {
|
|
||||||
fake_variadic,
|
|
||||||
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`.
|
|
||||||
/// If you require the length of the tuple, see [`all_tuples_with_size!`].
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ## Single parameter
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # use core::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!(T0);
|
|
||||||
/// // impl_wrapped_in_foo!(T0, T1);
|
|
||||||
/// // ..
|
|
||||||
/// // impl_wrapped_in_foo!(T0 .. T14);
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// # 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));
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// **`#[doc(fake_variadic)]`**
|
|
||||||
///
|
|
||||||
/// To improve the readability of your docs when implementing a trait for
|
|
||||||
/// tuples or fn pointers of varying length you can use the rustdoc-internal `fake_variadic` marker.
|
|
||||||
/// All your impls are collapsed and shown as a single `impl Trait for (F₁, F₂, …, Fₙ)`.
|
|
||||||
///
|
|
||||||
/// The `all_tuples!` macro does most of the work for you, the only change to your implementation macro
|
|
||||||
/// is that you have to accept attributes using `$(#[$meta:meta])*`.
|
|
||||||
///
|
|
||||||
/// Since this feature requires a nightly compiler, it's only enabled on docs.rs by default.
|
|
||||||
/// Add the following to your lib.rs if not already present:
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// // `rustdoc_internals` is needed for `#[doc(fake_variadics)]`
|
|
||||||
/// #![allow(internal_features)]
|
|
||||||
/// #![cfg_attr(any(docsrs, docsrs_dep), feature(rustdoc_internals))]
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # use bevy_utils_proc_macros::all_tuples;
|
|
||||||
/// #
|
|
||||||
/// trait Variadic {}
|
|
||||||
///
|
|
||||||
/// impl Variadic for () {}
|
|
||||||
///
|
|
||||||
/// macro_rules! impl_variadic {
|
|
||||||
/// ($(#[$meta:meta])* $(($P:ident, $p:ident)),*) => {
|
|
||||||
/// $(#[$meta])*
|
|
||||||
/// impl<$($P),*> Variadic for ($($P,)*) {}
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// all_tuples!(#[doc(fake_variadic)] impl_variadic, 1, 15, P, p);
|
|
||||||
/// ```
|
|
||||||
#[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));
|
|
||||||
ident_tuples.push(to_ident_tuple(idents, input.idents.len()));
|
|
||||||
}
|
|
||||||
|
|
||||||
let macro_ident = &input.macro_ident;
|
|
||||||
let invocations = (input.start..=input.end).map(|i| {
|
|
||||||
let ident_tuples = choose_ident_tuples(&input, &ident_tuples, i);
|
|
||||||
let attrs = if input.fake_variadic {
|
|
||||||
fake_variadic_attrs(len, i)
|
|
||||||
} else {
|
|
||||||
TokenStream2::default()
|
|
||||||
};
|
|
||||||
quote! {
|
|
||||||
#macro_ident!(#attrs #ident_tuples);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
TokenStream::from(quote! {
|
|
||||||
#(
|
|
||||||
#invocations
|
|
||||||
)*
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Helper macro to generate tuple pyramids with their length. Useful to generate scaffolding to
|
|
||||||
/// work around Rust lacking variadics. Invoking `all_tuples_with_size!(impl_foo, start, end, P, Q, ..)`
|
|
||||||
/// invokes `impl_foo` providing ident tuples through arity `start..=end` preceded by their length.
|
|
||||||
/// If you don't require the length of the tuple, see [`all_tuples!`].
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ## Single parameter
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # use core::marker::PhantomData;
|
|
||||||
/// # use bevy_utils_proc_macros::all_tuples_with_size;
|
|
||||||
/// #
|
|
||||||
/// struct Foo<T> {
|
|
||||||
/// // ..
|
|
||||||
/// # _phantom: PhantomData<T>
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// trait WrappedInFoo {
|
|
||||||
/// type Tup;
|
|
||||||
/// const LENGTH: usize;
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// macro_rules! impl_wrapped_in_foo {
|
|
||||||
/// ($N:expr, $($T:ident),*) => {
|
|
||||||
/// impl<$($T),*> WrappedInFoo for ($($T,)*) {
|
|
||||||
/// type Tup = ($(Foo<$T>,)*);
|
|
||||||
/// const LENGTH: usize = $N;
|
|
||||||
/// }
|
|
||||||
/// };
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// all_tuples_with_size!(impl_wrapped_in_foo, 0, 15, T);
|
|
||||||
/// // impl_wrapped_in_foo!(0);
|
|
||||||
/// // impl_wrapped_in_foo!(1, T0);
|
|
||||||
/// // impl_wrapped_in_foo!(2, T0, T1);
|
|
||||||
/// // ..
|
|
||||||
/// // impl_wrapped_in_foo!(15, T0 .. T14);
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// ## Multiple parameters
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # use bevy_utils_proc_macros::all_tuples_with_size;
|
|
||||||
/// #
|
|
||||||
/// 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 {
|
|
||||||
/// ($N:expr, $(($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_with_size!(impl_append, 1, 15, P, p);
|
|
||||||
/// // impl_append!(1, (P0, p0));
|
|
||||||
/// // impl_append!(2, (P0, p0), (P1, p1));
|
|
||||||
/// // impl_append!(3, (P0, p0), (P1, p1), (P2, p2));
|
|
||||||
/// // ..
|
|
||||||
/// // impl_append!(15, (P0, p0) .. (P14, p14));
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// **`#[doc(fake_variadic)]`**
|
|
||||||
///
|
|
||||||
/// To improve the readability of your docs when implementing a trait for
|
|
||||||
/// tuples or fn pointers of varying length you can use the rustdoc-internal `fake_variadic` marker.
|
|
||||||
/// All your impls are collapsed and shown as a single `impl Trait for (F₁, F₂, …, Fₙ)`.
|
|
||||||
///
|
|
||||||
/// The `all_tuples!` macro does most of the work for you, the only change to your implementation macro
|
|
||||||
/// is that you have to accept attributes using `$(#[$meta:meta])*`.
|
|
||||||
///
|
|
||||||
/// Since this feature requires a nightly compiler, it's only enabled on docs.rs by default.
|
|
||||||
/// Add the following to your lib.rs if not already present:
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// // `rustdoc_internals` is needed for `#[doc(fake_variadics)]`
|
|
||||||
/// #![allow(internal_features)]
|
|
||||||
/// #![cfg_attr(any(docsrs, docsrs_dep), feature(rustdoc_internals))]
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # use bevy_utils_proc_macros::all_tuples_with_size;
|
|
||||||
/// #
|
|
||||||
/// trait Variadic {}
|
|
||||||
///
|
|
||||||
/// impl Variadic for () {}
|
|
||||||
///
|
|
||||||
/// macro_rules! impl_variadic {
|
|
||||||
/// ($N:expr, $(#[$meta:meta])* $(($P:ident, $p:ident)),*) => {
|
|
||||||
/// $(#[$meta])*
|
|
||||||
/// impl<$($P),*> Variadic for ($($P,)*) {}
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// all_tuples_with_size!(#[doc(fake_variadic)] impl_variadic, 1, 15, P, p);
|
|
||||||
/// ```
|
|
||||||
#[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));
|
|
||||||
ident_tuples.push(to_ident_tuple(idents, input.idents.len()));
|
|
||||||
}
|
|
||||||
let macro_ident = &input.macro_ident;
|
|
||||||
let invocations = (input.start..=input.end).map(|i| {
|
|
||||||
let ident_tuples = choose_ident_tuples(&input, &ident_tuples, i);
|
|
||||||
let attrs = if input.fake_variadic {
|
|
||||||
fake_variadic_attrs(len, i)
|
|
||||||
} else {
|
|
||||||
TokenStream2::default()
|
|
||||||
};
|
|
||||||
quote! {
|
|
||||||
#macro_ident!(#i, #attrs #ident_tuples);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
TokenStream::from(quote! {
|
|
||||||
#(
|
|
||||||
#invocations
|
|
||||||
)*
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Parses the attribute `#[doc(fake_variadic)]`
|
|
||||||
fn parse_fake_variadic_attr(input: ParseStream) -> Result<bool> {
|
|
||||||
let attribute = match input.call(Attribute::parse_outer)? {
|
|
||||||
attributes if attributes.is_empty() => return Ok(false),
|
|
||||||
attributes if attributes.len() == 1 => attributes[0].clone(),
|
|
||||||
attributes => {
|
|
||||||
return Err(Error::new(
|
|
||||||
input.span(),
|
|
||||||
format!("Expected exactly one attribute, got {}", attributes.len()),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if attribute.path().is_ident("doc") {
|
|
||||||
let nested = attribute.parse_args::<Ident>()?;
|
|
||||||
if nested == "fake_variadic" {
|
|
||||||
return Ok(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Err(Error::new(
|
|
||||||
attribute.meta.span(),
|
|
||||||
"Unexpected attribute".to_string(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn choose_ident_tuples(input: &AllTuples, ident_tuples: &[TokenStream2], i: usize) -> TokenStream2 {
|
|
||||||
// `rustdoc` uses the first ident to generate nice
|
|
||||||
// idents with subscript numbers e.g. (F₁, F₂, …, Fₙ).
|
|
||||||
// We don't want two numbers, so we use the
|
|
||||||
// original, unnumbered idents for this case.
|
|
||||||
if input.fake_variadic && i == 1 {
|
|
||||||
let ident_tuple = to_ident_tuple(input.idents.iter().cloned(), input.idents.len());
|
|
||||||
quote! { #ident_tuple }
|
|
||||||
} else {
|
|
||||||
let ident_tuples = &ident_tuples[..i];
|
|
||||||
quote! { #(#ident_tuples),* }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_ident_tuple(idents: impl Iterator<Item = Ident>, len: usize) -> TokenStream2 {
|
|
||||||
if len < 2 {
|
|
||||||
quote! { #(#idents)* }
|
|
||||||
} else {
|
|
||||||
quote! { (#(#idents),*) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fake_variadic_attrs(len: usize, i: usize) -> TokenStream2 {
|
|
||||||
let cfg = quote! { any(docsrs, docsrs_dep) };
|
|
||||||
match i {
|
|
||||||
// An empty tuple (i.e. the unit type) is still documented separately,
|
|
||||||
// so no `#[doc(hidden)]` here.
|
|
||||||
0 => TokenStream2::default(),
|
|
||||||
// The `#[doc(fake_variadic)]` attr has to be on the first impl block.
|
|
||||||
1 => {
|
|
||||||
let doc = LitStr::new(
|
|
||||||
&format!("This trait is implemented for tuples up to {len} items long."),
|
|
||||||
Span2::call_site(),
|
|
||||||
);
|
|
||||||
quote! {
|
|
||||||
#[cfg_attr(#cfg, doc(fake_variadic))]
|
|
||||||
#[cfg_attr(#cfg, doc = #doc)]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => quote! { #[cfg_attr(#cfg, doc(hidden))] },
|
|
||||||
}
|
|
||||||
}
|
|
@ -36,7 +36,6 @@ mod parallel_queue;
|
|||||||
mod time;
|
mod time;
|
||||||
|
|
||||||
pub use ahash::{AHasher, RandomState};
|
pub use ahash::{AHasher, RandomState};
|
||||||
pub use bevy_utils_proc_macros::*;
|
|
||||||
pub use default::default;
|
pub use default::default;
|
||||||
pub use hashbrown;
|
pub use hashbrown;
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
# if crate A depends on crate B, B must come before A in this list
|
# if crate A depends on crate B, B must come before A in this list
|
||||||
crates=(
|
crates=(
|
||||||
bevy_utils/macros
|
|
||||||
bevy_utils
|
bevy_utils
|
||||||
bevy_ptr
|
bevy_ptr
|
||||||
bevy_macro_utils
|
bevy_macro_utils
|
||||||
|
Loading…
Reference in New Issue
Block a user