Streamline GetOwnership/FromArg/IntoReturn (#20126)

# Objective

Three impls are generated for each of these traits when the
`reflect_functions` feature is enabled.

Helps with #19873.

## Solution

Two of the three (the `&T` and `&mut T` ones) can be avoided by instead
providing blanket impls. The impl for `T` remains.

## Testing

I checked the output via `cargo expand`.

According to `-Zmacro-stats`, the size of the `Reflect` code generate
for `bevy_ui` drops by 10.4%.
This commit is contained in:
Nicholas Nethercote 2025-07-15 07:57:34 +10:00 committed by GitHub
parent 2a5e9c1150
commit b8072864aa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 113 additions and 223 deletions

View File

@ -13,23 +13,11 @@ pub(crate) fn impl_from_arg(where_clause_options: &WhereClauseOptions) -> proc_m
quote! {
impl #impl_generics #bevy_reflect::func::args::FromArg for #type_path #ty_generics #where_reflect_clause {
type This<'from_arg> = #type_path #ty_generics;
fn from_arg(arg: #bevy_reflect::func::args::Arg) -> #FQResult<Self::This<'_>, #bevy_reflect::func::args::ArgError> {
fn from_arg(arg: #bevy_reflect::func::args::Arg) ->
#FQResult<Self::This<'_>, #bevy_reflect::func::args::ArgError>
{
arg.take_owned()
}
}
impl #impl_generics #bevy_reflect::func::args::FromArg for &'static #type_path #ty_generics #where_reflect_clause {
type This<'from_arg> = &'from_arg #type_path #ty_generics;
fn from_arg(arg: #bevy_reflect::func::args::Arg) -> #FQResult<Self::This<'_>, #bevy_reflect::func::args::ArgError> {
arg.take_ref()
}
}
impl #impl_generics #bevy_reflect::func::args::FromArg for &'static mut #type_path #ty_generics #where_reflect_clause {
type This<'from_arg> = &'from_arg mut #type_path #ty_generics;
fn from_arg(arg: #bevy_reflect::func::args::Arg) -> #FQResult<Self::This<'_>, #bevy_reflect::func::args::ArgError> {
arg.take_mut()
}
}
}
}

View File

@ -17,17 +17,5 @@ pub(crate) fn impl_get_ownership(
#bevy_reflect::func::args::Ownership::Owned
}
}
impl #impl_generics #bevy_reflect::func::args::GetOwnership for &'_ #type_path #ty_generics #where_reflect_clause {
fn ownership() -> #bevy_reflect::func::args::Ownership {
#bevy_reflect::func::args::Ownership::Ref
}
}
impl #impl_generics #bevy_reflect::func::args::GetOwnership for &'_ mut #type_path #ty_generics #where_reflect_clause {
fn ownership() -> #bevy_reflect::func::args::Ownership {
#bevy_reflect::func::args::Ownership::Mut
}
}
}
}

View File

@ -13,21 +13,11 @@ pub(crate) fn impl_into_return(
quote! {
impl #impl_generics #bevy_reflect::func::IntoReturn for #type_path #ty_generics #where_reflect_clause {
fn into_return<'into_return>(self) -> #bevy_reflect::func::Return<'into_return> where Self: 'into_return {
fn into_return<'into_return>(self) -> #bevy_reflect::func::Return<'into_return>
where Self: 'into_return
{
#bevy_reflect::func::Return::Owned(#bevy_reflect::__macro_exports::alloc_utils::Box::new(self))
}
}
impl #impl_generics #bevy_reflect::func::IntoReturn for &#type_path #ty_generics #where_reflect_clause {
fn into_return<'into_return>(self) -> #bevy_reflect::func::Return<'into_return> where Self: 'into_return {
#bevy_reflect::func::Return::Ref(self)
}
}
impl #impl_generics #bevy_reflect::func::IntoReturn for &mut #type_path #ty_generics #where_reflect_clause {
fn into_return<'into_return>(self) -> #bevy_reflect::func::Return<'into_return> where Self: 'into_return {
#bevy_reflect::func::Return::Mut(self)
}
}
}
}

View File

@ -1,14 +1,17 @@
use crate::func::args::{Arg, ArgError};
use crate::{Reflect, TypePath};
/// A trait for types that can be created from an [`Arg`].
///
/// This trait exists so that types can be automatically converted into an [`Arg`]
/// so they can be put into an [`ArgList`] and passed to a [`DynamicFunction`] or [`DynamicFunctionMut`].
/// so they can be put into an [`ArgList`] and passed to a [`DynamicFunction`] or
/// [`DynamicFunctionMut`].
///
/// This trait is used instead of a blanket [`From`] implementation due to coherence issues:
/// we can't implement `From<T>` for both `T` and `&T`/`&mut T`.
///
/// This trait is automatically implemented when using the `Reflect` [derive macro].
/// This trait is automatically implemented for non-reference types when using the `Reflect`
/// [derive macro]. Blanket impls cover `&T` and `&mut T`.
///
/// [`ArgList`]: crate::func::args::ArgList
/// [`DynamicFunction`]: crate::func::DynamicFunction
@ -29,6 +32,22 @@ pub trait FromArg {
fn from_arg(arg: Arg) -> Result<Self::This<'_>, ArgError>;
}
// Blanket impl.
impl<T: Reflect + TypePath> FromArg for &'static T {
type This<'a> = &'a T;
fn from_arg(arg: Arg) -> Result<Self::This<'_>, ArgError> {
arg.take_ref()
}
}
// Blanket impl.
impl<T: Reflect + TypePath> FromArg for &'static mut T {
type This<'a> = &'a mut T;
fn from_arg(arg: Arg) -> Result<Self::This<'_>, ArgError> {
arg.take_mut()
}
}
/// Implements the [`FromArg`] trait for the given type.
///
/// This will implement it for `$ty`, `&$ty`, and `&mut $ty`.
@ -40,18 +59,13 @@ macro_rules! impl_from_arg {
(
$ty: ty
$(;
<
$($T: ident $(: $T1: tt $(+ $T2: tt)*)?),*
>
< $($T: ident $(: $T1: tt $(+ $T2: tt)*)?),* >
)?
$(
[
$(const $N: ident : $size: ident),*
]
[ $(const $N: ident : $size: ident),* ]
)?
$(
where
$($U: ty $(: $U1: tt $(+ $U2: tt)*)?),*
where $($U: ty $(: $U1: tt $(+ $U2: tt)*)?),*
)?
) => {
impl <
@ -59,45 +73,16 @@ macro_rules! impl_from_arg {
$(, $(const $N : $size),*)?
> $crate::func::args::FromArg for $ty
$(
where
$($U $(: $U1 $(+ $U2)*)?),*
where $($U $(: $U1 $(+ $U2)*)?),*
)?
{
type This<'from_arg> = $ty;
fn from_arg(arg: $crate::func::args::Arg) -> Result<Self::This<'_>, $crate::func::args::ArgError> {
fn from_arg(arg: $crate::func::args::Arg) ->
Result<Self::This<'_>, $crate::func::args::ArgError>
{
arg.take_owned()
}
}
impl <
$($($T $(: $T1 $(+ $T2)*)?),*)?
$(, $(const $N : $size),*)?
> $crate::func::args::FromArg for &'static $ty
$(
where
$($U $(: $U1 $(+ $U2)*)?),*
)?
{
type This<'from_arg> = &'from_arg $ty;
fn from_arg(arg: $crate::func::args::Arg) -> Result<Self::This<'_>, $crate::func::args::ArgError> {
arg.take_ref()
}
}
impl <
$($($T $(: $T1 $(+ $T2)*)?),*)?
$(, $(const $N : $size),*)?
> $crate::func::args::FromArg for &'static mut $ty
$(
where
$($U $(: $U1 $(+ $U2)*)?),*
)?
{
type This<'from_arg> = &'from_arg mut $ty;
fn from_arg(arg: $crate::func::args::Arg) -> Result<Self::This<'_>, $crate::func::args::ArgError> {
arg.take_mut()
}
}
};
}

View File

@ -1,21 +1,5 @@
use core::fmt::{Display, Formatter};
/// A trait for getting the ownership of a type.
///
/// This trait exists so that [`TypedFunction`] can automatically generate
/// [`FunctionInfo`] containing the proper [`Ownership`] for its [argument] types.
///
/// This trait is automatically implemented when using the `Reflect` [derive macro].
///
/// [`TypedFunction`]: crate::func::TypedFunction
/// [`FunctionInfo`]: crate::func::FunctionInfo
/// [argument]: crate::func::args::Arg
/// [derive macro]: derive@crate::Reflect
pub trait GetOwnership {
/// Returns the ownership of [`Self`].
fn ownership() -> Ownership;
}
/// The ownership of a type.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Ownership {
@ -37,6 +21,39 @@ impl Display for Ownership {
}
}
/// A trait for getting the ownership of a type.
///
/// This trait exists so that [`TypedFunction`] can automatically generate
/// [`FunctionInfo`] containing the proper [`Ownership`] for its [argument] types.
///
/// This trait is automatically implemented for non-reference types when using the `Reflect`
/// [derive macro]. Blanket impls cover `&T` and `&mut T`.
///
/// [`TypedFunction`]: crate::func::TypedFunction
/// [`FunctionInfo`]: crate::func::FunctionInfo
/// [argument]: crate::func::args::Arg
/// [derive macro]: derive@crate::Reflect
pub trait GetOwnership {
/// Returns the ownership of [`Self`].
fn ownership() -> Ownership {
Ownership::Owned
}
}
// Blanket impl.
impl<T> GetOwnership for &'_ T {
fn ownership() -> Ownership {
Ownership::Ref
}
}
// Blanket impl.
impl<T> GetOwnership for &'_ mut T {
fn ownership() -> Ownership {
Ownership::Mut
}
}
/// Implements the [`GetOwnership`] trait for the given type.
///
/// This will implement it for `$ty`, `&$ty`, and `&mut $ty`.
@ -48,18 +65,13 @@ macro_rules! impl_get_ownership {
(
$ty: ty
$(;
<
$($T: ident $(: $T1: tt $(+ $T2: tt)*)?),*
>
< $($T: ident $(: $T1: tt $(+ $T2: tt)*)?),* >
)?
$(
[
$(const $N: ident : $size: ident),*
]
[ $(const $N: ident : $size: ident),* ]
)?
$(
where
$($U: ty $(: $U1: tt $(+ $U2: tt)*)?),*
where $($U: ty $(: $U1: tt $(+ $U2: tt)*)?),*
)?
) => {
impl <
@ -67,42 +79,9 @@ macro_rules! impl_get_ownership {
$(, $(const $N : $size),*)?
> $crate::func::args::GetOwnership for $ty
$(
where
$($U $(: $U1 $(+ $U2)*)?),*
where $($U $(: $U1 $(+ $U2)*)?),*
)?
{
fn ownership() -> $crate::func::args::Ownership {
$crate::func::args::Ownership::Owned
}
}
impl <
$($($T $(: $T1 $(+ $T2)*)?),*)?
$(, $(const $N : $size),*)?
> $crate::func::args::GetOwnership for &'_ $ty
$(
where
$($U $(: $U1 $(+ $U2)*)?),*
)?
{
fn ownership() -> $crate::func::args::Ownership {
$crate::func::args::Ownership::Ref
}
}
impl <
$($($T $(: $T1 $(+ $T2)*)?),*)?
$(, $(const $N : $size),*)?
> $crate::func::args::GetOwnership for &'_ mut $ty
$(
where
$($U $(: $U1 $(+ $U2)*)?),*
)?
{
fn ownership() -> $crate::func::args::Ownership {
$crate::func::args::Ownership::Mut
}
}
{}
};
}

View File

@ -28,69 +28,49 @@ macro_rules! impl_function_traits {
(
$ty: ty
$(;
<
$($T: ident $(: $T1: tt $(+ $T2: tt)*)?),*
>
< $($T: ident $(: $T1: tt $(+ $T2: tt)*)?),* >
)?
$(
[
$(const $N: ident : $size: ident),*
]
[ $(const $N: ident : $size: ident),* ]
)?
$(
where
$($U: ty $(: $U1: tt $(+ $U2: tt)*)?),*
where $($U: ty $(: $U1: tt $(+ $U2: tt)*)?),*
)?
) => {
$crate::func::args::impl_get_ownership!(
$ty
$(;
<
$($T $(: $T1 $(+ $T2)*)?),*
>
< $($T $(: $T1 $(+ $T2)*)?),* >
)?
$(
[
$(const $N : $size),*
]
[ $(const $N : $size),* ]
)?
$(
where
$($U $(: $U1 $(+ $U2)*)?),*
where $($U $(: $U1 $(+ $U2)*)?),*
)?
);
$crate::func::args::impl_from_arg!(
$ty
$(;
<
$($T $(: $T1 $(+ $T2)*)?),*
>
< $($T $(: $T1 $(+ $T2)*)?),* >
)?
$(
[
$(const $N : $size),*
]
[ $(const $N : $size),* ]
)?
$(
where
$($U $(: $U1 $(+ $U2)*)?),*
where $($U $(: $U1 $(+ $U2)*)?),*
)?
);
$crate::func::impl_into_return!(
$ty
$(;
<
$($T $(: $T1 $(+ $T2)*)?),*
>
< $($T $(: $T1 $(+ $T2)*)?),* >
)?
$(
[
$(const $N : $size),*
]
[ $(const $N : $size),* ]
)?
$(
where
$($U $(: $U1 $(+ $U2)*)?),*
where $($U $(: $U1 $(+ $U2)*)?),*
)?
);
};

View File

@ -76,7 +76,8 @@ impl<'a> Return<'a> {
/// This trait is used instead of a blanket [`Into`] implementation due to coherence issues:
/// we can't implement `Into<Return>` for both `T` and `&T`/`&mut T`.
///
/// This trait is automatically implemented when using the `Reflect` [derive macro].
/// This trait is automatically implemented for non-reference types when using the `Reflect`
/// [derive macro]. Blanket impls cover `&T` and `&mut T`.
///
/// [`ReflectFn`]: crate::func::ReflectFn
/// [`ReflectFnMut`]: crate::func::ReflectFnMut
@ -88,6 +89,26 @@ pub trait IntoReturn {
Self: 'a;
}
// Blanket impl.
impl<T: PartialReflect> IntoReturn for &'_ T {
fn into_return<'a>(self) -> Return<'a>
where
Self: 'a,
{
Return::Ref(self)
}
}
// Blanket impl.
impl<T: PartialReflect> IntoReturn for &'_ mut T {
fn into_return<'a>(self) -> Return<'a>
where
Self: 'a,
{
Return::Mut(self)
}
}
impl IntoReturn for () {
fn into_return<'a>(self) -> Return<'a> {
Return::unit()
@ -105,18 +126,13 @@ macro_rules! impl_into_return {
(
$ty: ty
$(;
<
$($T: ident $(: $T1: tt $(+ $T2: tt)*)?),*
>
< $($T: ident $(: $T1: tt $(+ $T2: tt)*)?),* >
)?
$(
[
$(const $N: ident : $size: ident),*
]
[ $(const $N: ident : $size: ident),* ]
)?
$(
where
$($U: ty $(: $U1: tt $(+ $U2: tt)*)?),*
where $($U: ty $(: $U1: tt $(+ $U2: tt)*)?),*
)?
) => {
impl <
@ -124,42 +140,15 @@ macro_rules! impl_into_return {
$(, $(const $N : $size),*)?
> $crate::func::IntoReturn for $ty
$(
where
$($U $(: $U1 $(+ $U2)*)?),*
where $($U $(: $U1 $(+ $U2)*)?),*
)?
{
fn into_return<'into_return>(self) -> $crate::func::Return<'into_return> where Self: 'into_return {
fn into_return<'into_return>(self) -> $crate::func::Return<'into_return>
where Self: 'into_return
{
$crate::func::Return::Owned(bevy_platform::prelude::Box::new(self))
}
}
impl <
$($($T $(: $T1 $(+ $T2)*)?),*)?
$(, $(const $N : $size),*)?
> $crate::func::IntoReturn for &'static $ty
$(
where
$($U $(: $U1 $(+ $U2)*)?),*
)?
{
fn into_return<'into_return>(self) -> $crate::func::Return<'into_return> where Self: 'into_return {
$crate::func::Return::Ref(self)
}
}
impl <
$($($T $(: $T1 $(+ $T2)*)?),*)?
$(, $(const $N : $size),*)?
> $crate::func::IntoReturn for &'static mut $ty
$(
where
$($U $(: $U1 $(+ $U2)*)?),*
)?
{
fn into_return<'into_return>(self) -> $crate::func::Return<'into_return> where Self: 'into_return {
$crate::func::Return::Mut(self)
}
}
};
}

View File

@ -153,6 +153,3 @@ impl FromReflect for &'static Location<'static> {
reflect.try_downcast_ref::<Self>().copied()
}
}
#[cfg(feature = "functions")]
crate::func::macros::impl_function_traits!(&'static Location<'static>);

View File

@ -293,9 +293,6 @@ impl FromReflect for &'static str {
}
}
#[cfg(feature = "functions")]
crate::func::macros::impl_function_traits!(&'static str);
impl<T: Reflect + MaybeTyped + TypePath + GetTypeRegistration, const N: usize> Array for [T; N] {
#[inline]
fn get(&self, index: usize) -> Option<&dyn PartialReflect> {

View File

@ -160,9 +160,6 @@ impl FromReflect for &'static Path {
}
}
#[cfg(feature = "functions")]
crate::func::macros::impl_function_traits!(&'static Path);
impl PartialReflect for Cow<'static, Path> {
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
Some(<Self as Typed>::type_info())