bevy_reflect: Replace "value" terminology with "opaque" (#15240)

# Objective

Currently, the term "value" in the context of reflection is a bit
overloaded.

For one, it can be used synonymously with "data" or "variable". An
example sentence would be "this function takes a reflected value".

However, it is also used to refer to reflected types which are
`ReflectKind::Value`. These types are usually either primitives, opaque
types, or types that don't fall into any other `ReflectKind` (or perhaps
could, but don't due to some limitation/difficulty). An example sentence
would be "this function takes a reflected value type".

This makes it difficult to write good documentation or other learning
material without causing some amount of confusion to readers. Ideally,
we'd be able to move away from the `ReflectKind::Value` usage and come
up with a better term.

## Solution

This PR replaces the terminology of "value" with "opaque" across
`bevy_reflect`. This includes in documentation, type names, variant
names, and macros.

The term "opaque" was chosen because that's essentially how the type is
treated within the reflection API. In other words, its internal
structure is hidden. All we can do is work with the type itself.

### Primitives

While primitives are not technically opaque types, I think it's still
clearer to refer to them as "opaque" rather than keep the confusing
"value" terminology.

We could consider adding another concept for primitives (e.g.
`ReflectKind::Primitive`), but I'm not sure that provides a lot of
benefit right now. In most circumstances, they'll be treated just like
an opaque type. They would also likely use the same macro (or two copies
of the same macro but with different names).

## Testing

You can test locally by running:

```
cargo test --package bevy_reflect --all-features
```

---

## Migration Guide

The reflection concept of "value type" has been replaced with a clearer
"opaque type". The following renames have been made to account for this:

- `ReflectKind::Value` → `ReflectKind::Opaque`
- `ReflectRef::Value` → `ReflectRef::Opaque`
- `ReflectMut::Value` → `ReflectMut::Opaque`
- `ReflectOwned::Value` → `ReflectOwned::Opaque`
- `TypeInfo::Value` → `TypeInfo::Opaque`
- `ValueInfo` → `OpaqueInfo`
- `impl_reflect_value!` → `impl_reflect_opaque!`
- `impl_from_reflect_value!` → `impl_from_reflect_opaque!`

Additionally, declaring your own opaque types no longer uses
`#[reflect_value]`. This attribute has been replaced by
`#[reflect(opaque)]`:

```rust
// BEFORE
#[derive(Reflect)]
#[reflect_value(Default)]
struct MyOpaqueType(u32);

// AFTER
#[derive(Reflect)]
#[reflect(opaque)]
#[reflect(Default)]
struct MyOpaqueType(u32);
```

Note that the order in which `#[reflect(opaque)]` appears does not
matter.
This commit is contained in:
Gino Valente 2024-09-23 11:04:57 -07:00 committed by GitHub
parent 3139b03e74
commit 83356b12c9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
29 changed files with 266 additions and 303 deletions

View File

@ -48,7 +48,8 @@ use thiserror::Error;
/// clones internal owned [`AssetPaths`](AssetPath).
/// This also means that you should use [`AssetPath::parse`] in cases where `&str` is the explicit type.
#[derive(Eq, PartialEq, Hash, Clone, Default, Reflect)]
#[reflect_value(Debug, PartialEq, Hash, Serialize, Deserialize)]
#[reflect(opaque)]
#[reflect(Debug, PartialEq, Hash, Serialize, Deserialize)]
pub struct AssetPath<'a> {
source: AssetSourceId<'a>,
path: CowArc<'a, Path>,

View File

@ -144,10 +144,11 @@ type IdCursor = isize;
/// [SemVer]: https://semver.org/
#[derive(Clone, Copy)]
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
#[cfg_attr(feature = "bevy_reflect", reflect_value(Hash, PartialEq, Debug))]
#[cfg_attr(feature = "bevy_reflect", reflect(opaque))]
#[cfg_attr(feature = "bevy_reflect", reflect(Hash, PartialEq, Debug))]
#[cfg_attr(
all(feature = "bevy_reflect", feature = "serialize"),
reflect_value(Serialize, Deserialize)
reflect(Serialize, Deserialize)
)]
// Alignment repr necessary to allow LLVM to better output
// optimised codegen for `to_bits`, `PartialEq` and `Ord`.

View File

@ -19,7 +19,8 @@ pub(crate) mod masks;
/// entity kinds.
#[derive(Debug, Clone, Copy)]
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
#[cfg_attr(feature = "bevy_reflect", reflect_value(Debug, Hash, PartialEq))]
#[cfg_attr(feature = "bevy_reflect", reflect(opaque))]
#[cfg_attr(feature = "bevy_reflect", reflect(Debug, Hash, PartialEq))]
// Alignment repr necessary to allow LLVM to better output
// optimised codegen for `to_bits`, `PartialEq` and `Ord`.
#[repr(C, align(8))]

View File

@ -3,7 +3,7 @@
//! A container attribute is an attribute which applies to an entire struct or enum
//! as opposed to a particular field or variant. An example of such an attribute is
//! the derive helper attribute for `Reflect`, which looks like:
//! `#[reflect(PartialEq, Default, ...)]` and `#[reflect_value(PartialEq, Default, ...)]`.
//! `#[reflect(PartialEq, Default, ...)]`.
use crate::attribute_parser::terminated_parser;
use crate::custom_attributes::CustomAttributes;
@ -23,6 +23,7 @@ mod kw {
syn::custom_keyword!(PartialEq);
syn::custom_keyword!(Hash);
syn::custom_keyword!(no_field_bounds);
syn::custom_keyword!(opaque);
}
// The "special" trait idents that are used internally for reflection.
@ -188,6 +189,7 @@ pub(crate) struct ContainerAttributes {
custom_where: Option<WhereClause>,
no_field_bounds: bool,
custom_attributes: CustomAttributes,
is_opaque: bool,
idents: Vec<Ident>,
}
@ -236,6 +238,8 @@ impl ContainerAttributes {
self.parse_from_reflect(input, trait_)
} else if lookahead.peek(kw::type_path) {
self.parse_type_path(input, trait_)
} else if lookahead.peek(kw::opaque) {
self.parse_opaque(input)
} else if lookahead.peek(kw::no_field_bounds) {
self.parse_no_field_bounds(input)
} else if lookahead.peek(kw::Debug) {
@ -336,6 +340,16 @@ impl ContainerAttributes {
Ok(())
}
/// Parse `opaque` attribute.
///
/// Examples:
/// - `#[reflect(opaque)]`
fn parse_opaque(&mut self, input: ParseStream) -> syn::Result<()> {
input.parse::<kw::opaque>()?;
self.is_opaque = true;
Ok(())
}
/// Parse `no_field_bounds` attribute.
///
/// Examples:
@ -528,6 +542,11 @@ impl ContainerAttributes {
pub fn no_field_bounds(&self) -> bool {
self.no_field_bounds
}
/// Returns true if the `opaque` attribute was found on this type.
pub fn is_opaque(&self) -> bool {
self.is_opaque
}
}
/// Adds an identifier to a vector of identifiers if it is not already present.

View File

@ -12,10 +12,7 @@ use syn::token::Comma;
use crate::remote::RemoteType;
use crate::serialization::SerializationDataDef;
use crate::{
REFLECT_ATTRIBUTE_NAME, REFLECT_VALUE_ATTRIBUTE_NAME, TYPE_NAME_ATTRIBUTE_NAME,
TYPE_PATH_ATTRIBUTE_NAME,
};
use crate::{REFLECT_ATTRIBUTE_NAME, TYPE_NAME_ATTRIBUTE_NAME, TYPE_PATH_ATTRIBUTE_NAME};
use syn::punctuated::Punctuated;
use syn::spanned::Spanned;
use syn::{
@ -28,7 +25,7 @@ pub(crate) enum ReflectDerive<'a> {
TupleStruct(ReflectStruct<'a>),
UnitStruct(ReflectStruct<'a>),
Enum(ReflectEnum<'a>),
Value(ReflectMeta<'a>),
Opaque(ReflectMeta<'a>),
}
/// Metadata present on all reflected types, including name, generics, and attributes.
@ -135,15 +132,6 @@ pub(crate) enum EnumVariantFields<'a> {
Unit,
}
/// The method in which the type should be reflected.
#[derive(PartialEq, Eq)]
enum ReflectMode {
/// Reflect the type normally, providing information about all fields/variants.
Normal,
/// Reflect the type as a value.
Value,
}
/// How the macro was invoked.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub(crate) enum ReflectImplSource {
@ -192,8 +180,6 @@ impl<'a> ReflectDerive<'a> {
provenance: ReflectProvenance,
) -> Result<Self, syn::Error> {
let mut container_attributes = ContainerAttributes::default();
// Should indicate whether `#[reflect_value]` was used.
let mut reflect_mode = None;
// Should indicate whether `#[type_path = "..."]` was used.
let mut custom_path: Option<Path> = None;
// Should indicate whether `#[type_name = "..."]` was used.
@ -205,37 +191,8 @@ impl<'a> ReflectDerive<'a> {
for attribute in &input.attrs {
match &attribute.meta {
Meta::List(meta_list) if meta_list.path.is_ident(REFLECT_ATTRIBUTE_NAME) => {
if !matches!(reflect_mode, None | Some(ReflectMode::Normal)) {
return Err(syn::Error::new(
meta_list.span(),
format_args!("cannot use both `#[{REFLECT_ATTRIBUTE_NAME}]` and `#[{REFLECT_VALUE_ATTRIBUTE_NAME}]`"),
));
}
reflect_mode = Some(ReflectMode::Normal);
container_attributes.parse_meta_list(meta_list, provenance.trait_)?;
}
Meta::List(meta_list) if meta_list.path.is_ident(REFLECT_VALUE_ATTRIBUTE_NAME) => {
if !matches!(reflect_mode, None | Some(ReflectMode::Value)) {
return Err(syn::Error::new(
meta_list.span(),
format_args!("cannot use both `#[{REFLECT_ATTRIBUTE_NAME}]` and `#[{REFLECT_VALUE_ATTRIBUTE_NAME}]`"),
));
}
reflect_mode = Some(ReflectMode::Value);
container_attributes.parse_meta_list(meta_list, provenance.trait_)?;
}
Meta::Path(path) if path.is_ident(REFLECT_VALUE_ATTRIBUTE_NAME) => {
if !matches!(reflect_mode, None | Some(ReflectMode::Value)) {
return Err(syn::Error::new(
path.span(),
format_args!("cannot use both `#[{REFLECT_ATTRIBUTE_NAME}]` and `#[{REFLECT_VALUE_ATTRIBUTE_NAME}]`"),
));
}
reflect_mode = Some(ReflectMode::Value);
}
Meta::NameValue(pair) if pair.path.is_ident(TYPE_PATH_ATTRIBUTE_NAME) => {
let syn::Expr::Lit(syn::ExprLit {
lit: syn::Lit::Str(lit),
@ -315,11 +272,8 @@ impl<'a> ReflectDerive<'a> {
#[cfg(feature = "documentation")]
let meta = meta.with_docs(doc);
// Use normal reflection if unspecified
let reflect_mode = reflect_mode.unwrap_or(ReflectMode::Normal);
if reflect_mode == ReflectMode::Value {
return Ok(Self::Value(meta));
if meta.attrs().is_opaque() {
return Ok(Self::Opaque(meta));
}
return match &input.data {
@ -354,7 +308,7 @@ impl<'a> ReflectDerive<'a> {
///
/// # Panics
///
/// Panics when called on [`ReflectDerive::Value`].
/// Panics when called on [`ReflectDerive::Opaque`].
pub fn set_remote(&mut self, remote_ty: Option<RemoteType<'a>>) {
match self {
Self::Struct(data) | Self::TupleStruct(data) | Self::UnitStruct(data) => {
@ -363,7 +317,7 @@ impl<'a> ReflectDerive<'a> {
Self::Enum(data) => {
data.meta.remote_ty = remote_ty;
}
Self::Value(meta) => {
Self::Opaque(meta) => {
meta.remote_ty = remote_ty;
}
}
@ -376,7 +330,7 @@ impl<'a> ReflectDerive<'a> {
data.meta.remote_ty()
}
Self::Enum(data) => data.meta.remote_ty(),
Self::Value(meta) => meta.remote_ty(),
Self::Opaque(meta) => meta.remote_ty(),
}
}
@ -385,7 +339,7 @@ impl<'a> ReflectDerive<'a> {
match self {
Self::Struct(data) | Self::TupleStruct(data) | Self::UnitStruct(data) => data.meta(),
Self::Enum(data) => data.meta(),
Self::Value(meta) => meta,
Self::Opaque(meta) => meta,
}
}
@ -395,7 +349,7 @@ impl<'a> ReflectDerive<'a> {
data.where_clause_options()
}
Self::Enum(data) => data.where_clause_options(),
Self::Value(meta) => WhereClauseOptions::new(meta),
Self::Opaque(meta) => WhereClauseOptions::new(meta),
}
}

View File

@ -20,7 +20,7 @@ pub(crate) fn impl_tuple_struct(reflect_struct: &ReflectStruct) -> proc_macro2::
impl_struct_internal(reflect_struct, true)
}
pub(crate) fn impl_value(meta: &ReflectMeta) -> proc_macro2::TokenStream {
pub(crate) fn impl_opaque(meta: &ReflectMeta) -> proc_macro2::TokenStream {
let type_path = meta.type_path();
let bevy_reflect_path = meta.bevy_reflect_path();
let (impl_generics, ty_generics, where_clause) = type_path.generics().split_for_impl();

View File

@ -3,17 +3,17 @@ mod common;
mod enums;
#[cfg(feature = "functions")]
mod func;
mod opaque;
mod structs;
mod tuple_structs;
mod typed;
mod values;
pub(crate) use assertions::impl_assertions;
pub(crate) use common::{common_partial_reflect_methods, impl_full_reflect};
pub(crate) use enums::impl_enum;
#[cfg(feature = "functions")]
pub(crate) use func::impl_function_traits;
pub(crate) use opaque::impl_opaque;
pub(crate) use structs::impl_struct;
pub(crate) use tuple_structs::impl_tuple_struct;
pub(crate) use typed::{impl_type_path, impl_typed};
pub(crate) use values::impl_value;

View File

@ -5,7 +5,7 @@ use bevy_macro_utils::fq_std::{FQBox, FQClone, FQOption, FQResult};
use quote::quote;
/// Implements `GetTypeRegistration` and `Reflect` for the given type data.
pub(crate) fn impl_value(meta: &ReflectMeta) -> proc_macro2::TokenStream {
pub(crate) fn impl_opaque(meta: &ReflectMeta) -> proc_macro2::TokenStream {
let bevy_reflect_path = meta.bevy_reflect_path();
let type_path = meta.type_path();
@ -22,8 +22,8 @@ pub(crate) fn impl_value(meta: &ReflectMeta) -> proc_macro2::TokenStream {
meta,
&where_clause_options,
quote! {
let info = #bevy_reflect_path::ValueInfo::new::<Self>() #with_docs;
#bevy_reflect_path::TypeInfo::Value(info)
let info = #bevy_reflect_path::OpaqueInfo::new::<Self>() #with_docs;
#bevy_reflect_path::TypeInfo::Opaque(info)
},
);
@ -96,22 +96,22 @@ pub(crate) fn impl_value(meta: &ReflectMeta) -> proc_macro2::TokenStream {
#[inline]
fn reflect_kind(&self) -> #bevy_reflect_path::ReflectKind {
#bevy_reflect_path::ReflectKind::Value
#bevy_reflect_path::ReflectKind::Opaque
}
#[inline]
fn reflect_ref(&self) -> #bevy_reflect_path::ReflectRef {
#bevy_reflect_path::ReflectRef::Value(self)
#bevy_reflect_path::ReflectRef::Opaque(self)
}
#[inline]
fn reflect_mut(&mut self) -> #bevy_reflect_path::ReflectMut {
#bevy_reflect_path::ReflectMut::Value(self)
#bevy_reflect_path::ReflectMut::Opaque(self)
}
#[inline]
fn reflect_owned(self: #FQBox<Self>) -> #bevy_reflect_path::ReflectOwned {
#bevy_reflect_path::ReflectOwned::Value(self)
#bevy_reflect_path::ReflectOwned::Opaque(self)
}
#common_methods

View File

@ -28,7 +28,7 @@ mod from_reflect;
mod ident;
mod impls;
mod meta;
mod reflect_value;
mod reflect_opaque;
mod registration;
mod remote;
mod result_sifter;
@ -44,12 +44,11 @@ use container_attributes::ContainerAttributes;
use derive_data::{ReflectImplSource, ReflectProvenance, ReflectTraitToImpl, ReflectTypePath};
use proc_macro::TokenStream;
use quote::quote;
use reflect_value::ReflectValueDef;
use reflect_opaque::ReflectOpaqueDef;
use syn::{parse_macro_input, DeriveInput};
use type_path::NamedTypePathDef;
pub(crate) static REFLECT_ATTRIBUTE_NAME: &str = "reflect";
pub(crate) static REFLECT_VALUE_ATTRIBUTE_NAME: &str = "reflect_value";
pub(crate) static TYPE_PATH_ATTRIBUTE_NAME: &str = "type_path";
pub(crate) static TYPE_NAME_ATTRIBUTE_NAME: &str = "type_name";
@ -96,10 +95,10 @@ fn match_reflect_impls(ast: DeriveInput, source: ReflectImplSource) -> TokenStre
None
},
),
ReflectDerive::Value(meta) => (
impls::impl_value(&meta),
ReflectDerive::Opaque(meta) => (
impls::impl_opaque(&meta),
if meta.from_reflect().should_auto_derive() {
Some(from_reflect::impl_value(&meta))
Some(from_reflect::impl_opaque(&meta))
} else {
None
},
@ -178,10 +177,10 @@ fn match_reflect_impls(ast: DeriveInput, source: ReflectImplSource) -> TokenStre
/// a base value using its [`Default`] implementation avoiding issues with ignored fields
/// (for structs and tuple structs only).
///
/// ## `#[reflect_value]`
/// ## `#[reflect(opaque)]`
///
/// The `#[reflect_value]` attribute (which may also take the form `#[reflect_value(Ident)]`),
/// denotes that the item should implement `Reflect` as though it were a base value type.
/// The `#[reflect(opaque)]` attribute denotes that the item should implement `Reflect` as an opaque type,
/// hiding its structure and fields from the reflection API.
/// This means that it will forgo implementing `Struct`, `TupleStruct`, or `Enum`.
///
/// Furthermore, it requires that the type implements [`Clone`].
@ -369,7 +368,7 @@ fn match_reflect_impls(ast: DeriveInput, source: ReflectImplSource) -> TokenStre
/// ```
///
/// [`reflect_trait`]: macro@reflect_trait
#[proc_macro_derive(Reflect, attributes(reflect, reflect_value, type_path, type_name))]
#[proc_macro_derive(Reflect, attributes(reflect, type_path, type_name))]
pub fn derive_reflect(input: TokenStream) -> TokenStream {
let ast = parse_macro_input!(input as DeriveInput);
match_reflect_impls(ast, ReflectImplSource::DeriveLocalType)
@ -422,7 +421,7 @@ pub fn derive_from_reflect(input: TokenStream) -> TokenStream {
}
ReflectDerive::TupleStruct(struct_data) => from_reflect::impl_tuple_struct(&struct_data),
ReflectDerive::Enum(meta) => from_reflect::impl_enum(&meta),
ReflectDerive::Value(meta) => from_reflect::impl_value(&meta),
ReflectDerive::Opaque(meta) => from_reflect::impl_opaque(&meta),
};
TokenStream::from(quote! {
@ -610,10 +609,10 @@ pub fn reflect_remote(args: TokenStream, input: TokenStream) -> TokenStream {
/// A macro used to generate reflection trait implementations for the given type.
///
/// This is functionally the same as [deriving `Reflect`] using the `#[reflect_value]` container attribute.
/// This is functionally the same as [deriving `Reflect`] using the `#[reflect(opaque)]` container attribute.
///
/// The only reason for this macro's existence is so that `bevy_reflect` can easily implement the reflection traits
/// on primitives and other Rust types internally.
/// on primitives and other opaque types internally.
///
/// Since this macro also implements `TypePath`, the type path must be explicit.
/// See [`impl_type_path!`] for the exact syntax.
@ -623,26 +622,26 @@ pub fn reflect_remote(args: TokenStream, input: TokenStream) -> TokenStream {
/// Types can be passed with or without registering type data:
///
/// ```ignore (bevy_reflect is not accessible from this crate)
/// impl_reflect_value!(my_crate::Foo);
/// impl_reflect_value!(my_crate::Bar(Debug, Default, Serialize, Deserialize));
/// impl_reflect_opaque!(my_crate::Foo);
/// impl_reflect_opaque!(my_crate::Bar(Debug, Default, Serialize, Deserialize));
/// ```
///
/// Generic types can also specify their parameters and bounds:
///
/// ```ignore (bevy_reflect is not accessible from this crate)
/// impl_reflect_value!(my_crate::Foo<T1, T2: Baz> where T1: Bar (Default, Serialize, Deserialize));
/// impl_reflect_opaque!(my_crate::Foo<T1, T2: Baz> where T1: Bar (Default, Serialize, Deserialize));
/// ```
///
/// Custom type paths can be specified:
///
/// ```ignore (bevy_reflect is not accessible from this crate)
/// impl_reflect_value!((in not_my_crate as NotFoo) Foo(Debug, Default));
/// impl_reflect_opaque!((in not_my_crate as NotFoo) Foo(Debug, Default));
/// ```
///
/// [deriving `Reflect`]: Reflect
#[proc_macro]
pub fn impl_reflect_value(input: TokenStream) -> TokenStream {
let def = parse_macro_input!(input with ReflectValueDef::parse_reflect);
pub fn impl_reflect_opaque(input: TokenStream) -> TokenStream {
let def = parse_macro_input!(input with ReflectOpaqueDef::parse_reflect);
let default_name = &def.type_path.segments.last().unwrap().ident;
let type_path = if def.type_path.leading_colon.is_none() && def.custom_path.is_none() {
@ -660,8 +659,8 @@ pub fn impl_reflect_value(input: TokenStream) -> TokenStream {
#[cfg(feature = "documentation")]
let meta = meta.with_docs(documentation::Documentation::from_attributes(&def.attrs));
let reflect_impls = impls::impl_value(&meta);
let from_reflect_impl = from_reflect::impl_value(&meta);
let reflect_impls = impls::impl_opaque(&meta);
let from_reflect_impl = from_reflect::impl_opaque(&meta);
TokenStream::from(quote! {
const _: () = {
@ -674,8 +673,8 @@ pub fn impl_reflect_value(input: TokenStream) -> TokenStream {
/// A replacement for `#[derive(Reflect)]` to be used with foreign types which
/// the definitions of cannot be altered.
///
/// This macro is an alternative to [`impl_reflect_value!`] and [`impl_from_reflect_value!`]
/// which implement foreign types as Value types. Note that there is no `impl_from_reflect`,
/// This macro is an alternative to [`impl_reflect_opaque!`] and [`impl_from_reflect_opaque!`]
/// which implement foreign types as Opaque types. Note that there is no `impl_from_reflect`,
/// as this macro will do the job of both. This macro implements them using one of the reflect
/// variant traits (`bevy_reflect::{Struct, TupleStruct, Enum}`, etc.),
/// which have greater functionality. The type being reflected must be in scope, as you cannot
@ -713,26 +712,26 @@ pub fn impl_reflect(input: TokenStream) -> TokenStream {
/// A macro used to generate a `FromReflect` trait implementation for the given type.
///
/// This is functionally the same as [deriving `FromReflect`] on a type that [derives `Reflect`] using
/// the `#[reflect_value]` container attribute.
/// the `#[reflect(opaque)]` container attribute.
///
/// The only reason this macro exists is so that `bevy_reflect` can easily implement `FromReflect` on
/// primitives and other Rust types internally.
/// primitives and other opaque types internally.
///
/// Please note that this macro will not work with any type that [derives `Reflect`] normally
/// or makes use of the [`impl_reflect_value!`] macro, as those macros also implement `FromReflect`
/// or makes use of the [`impl_reflect_opaque!`] macro, as those macros also implement `FromReflect`
/// by default.
///
/// # Examples
///
/// ```ignore (bevy_reflect is not accessible from this crate)
/// impl_from_reflect_value!(foo<T1, T2: Baz> where T1: Bar);
/// impl_from_reflect_opaque!(foo<T1, T2: Baz> where T1: Bar);
/// ```
///
/// [deriving `FromReflect`]: FromReflect
/// [derives `Reflect`]: Reflect
#[proc_macro]
pub fn impl_from_reflect_value(input: TokenStream) -> TokenStream {
let def = parse_macro_input!(input with ReflectValueDef::parse_from_reflect);
pub fn impl_from_reflect_opaque(input: TokenStream) -> TokenStream {
let def = parse_macro_input!(input with ReflectOpaqueDef::parse_from_reflect);
let default_name = &def.type_path.segments.last().unwrap().ident;
let type_path = if def.type_path.leading_colon.is_none()
@ -749,7 +748,7 @@ pub fn impl_from_reflect_value(input: TokenStream) -> TokenStream {
};
let from_reflect_impl =
from_reflect::impl_value(&ReflectMeta::new(type_path, def.traits.unwrap_or_default()));
from_reflect::impl_opaque(&ReflectMeta::new(type_path, def.traits.unwrap_or_default()));
TokenStream::from(quote! {
const _: () = {

View File

@ -5,9 +5,7 @@ use syn::parse::ParseStream;
use syn::token::Paren;
use syn::{parenthesized, Attribute, Generics, Path};
/// A struct used to define a simple reflected value type (such as primitives).
///
///
/// A struct used to define a simple reflection-opaque types (including primitives).
///
/// This takes the form:
///
@ -21,10 +19,10 @@ use syn::{parenthesized, Attribute, Generics, Path};
/// // With generics and where clause
/// ::my_crate::foo::Bar<T1, T2> where T1: Bar (TraitA, TraitB)
///
/// // With a custom path (not with impl_from_reflect_value)
/// // With a custom path (not with impl_from_reflect_opaque)
/// (in my_crate::bar) Bar(TraitA, TraitB)
/// ```
pub(crate) struct ReflectValueDef {
pub(crate) struct ReflectOpaqueDef {
#[cfg_attr(
not(feature = "documentation"),
expect(
@ -39,7 +37,7 @@ pub(crate) struct ReflectValueDef {
pub custom_path: Option<CustomPathDef>,
}
impl ReflectValueDef {
impl ReflectOpaqueDef {
pub fn parse_reflect(input: ParseStream) -> syn::Result<Self> {
Self::parse(input, ReflectTraitToImpl::Reflect)
}
@ -67,7 +65,7 @@ impl ReflectValueDef {
attrs
});
}
Ok(ReflectValueDef {
Ok(Self {
attrs,
type_path,
generics,

View File

@ -1,9 +1,7 @@
use crate::derive_data::{ReflectImplSource, ReflectProvenance, ReflectTraitToImpl};
use crate::ident::ident_or_index;
use crate::impls::impl_assertions;
use crate::{
from_reflect, impls, ReflectDerive, REFLECT_ATTRIBUTE_NAME, REFLECT_VALUE_ATTRIBUTE_NAME,
};
use crate::{from_reflect, impls, ReflectDerive, REFLECT_ATTRIBUTE_NAME};
use bevy_macro_utils::fq_std::FQOption;
use proc_macro::TokenStream;
use proc_macro2::{Ident, Span};
@ -70,10 +68,10 @@ pub(crate) fn reflect_remote(args: TokenStream, input: TokenStream) -> TokenStre
None
},
),
ReflectDerive::Value(meta) => (
impls::impl_value(&meta),
ReflectDerive::Opaque(meta) => (
impls::impl_opaque(&meta),
if meta.from_reflect().should_auto_derive() {
Some(from_reflect::impl_value(&meta))
Some(from_reflect::impl_opaque(&meta))
} else {
None
},
@ -114,10 +112,10 @@ fn generate_remote_wrapper(input: &DeriveInput, remote_ty: &TypePath) -> proc_ma
let vis = &input.vis;
let ty_generics = &input.generics;
let where_clause = &input.generics.where_clause;
let attrs = input.attrs.iter().filter(|attr| {
!attr.path().is_ident(REFLECT_ATTRIBUTE_NAME)
&& !attr.path().is_ident(REFLECT_VALUE_ATTRIBUTE_NAME)
});
let attrs = input
.attrs
.iter()
.filter(|attr| !attr.path().is_ident(REFLECT_ATTRIBUTE_NAME));
quote! {
#(#attrs)*
@ -407,7 +405,7 @@ fn generate_remote_definition_assertions(derive_data: &ReflectDerive) -> proc_ma
}
}
}
ReflectDerive::Value(_) => {
ReflectDerive::Opaque(_) => {
// No assertions needed since there are no fields to check
proc_macro2::TokenStream::new()
}

View File

@ -1,6 +1,6 @@
use crate as bevy_reflect;
use crate::{std_traits::ReflectDefault, ReflectDeserialize, ReflectSerialize};
use bevy_reflect_derive::{impl_reflect, impl_reflect_value};
use bevy_reflect_derive::{impl_reflect, impl_reflect_opaque};
use glam::*;
impl_reflect!(
@ -343,8 +343,8 @@ impl_reflect!(
}
);
impl_reflect_value!(::glam::BVec3A(Debug, Default, Deserialize, Serialize));
impl_reflect_value!(::glam::BVec4A(Debug, Default, Deserialize, Serialize));
impl_reflect_opaque!(::glam::BVec3A(Debug, Default, Deserialize, Serialize));
impl_reflect_opaque!(::glam::BVec4A(Debug, Default, Deserialize, Serialize));
#[cfg(test)]
mod tests {

View File

@ -1,14 +1,14 @@
use crate::{
self as bevy_reflect, impl_reflect_value, prelude::ReflectDefault, ReflectDeserialize,
self as bevy_reflect, impl_reflect_opaque, prelude::ReflectDefault, ReflectDeserialize,
ReflectSerialize,
};
impl_reflect_value!(::petgraph::graph::NodeIndex(
impl_reflect_opaque!(::petgraph::graph::NodeIndex(
Default,
Serialize,
Deserialize
));
impl_reflect_value!(::petgraph::graph::DiGraph<
impl_reflect_opaque!(::petgraph::graph::DiGraph<
N: ::std::clone::Clone,
E: ::std::clone::Clone,
Ix: ::petgraph::graph::IndexType

View File

@ -1,8 +1,8 @@
use crate::{self as bevy_reflect};
use crate::{std_traits::ReflectDefault, ReflectDeserialize, ReflectSerialize};
use bevy_reflect_derive::impl_reflect_value;
use bevy_reflect_derive::impl_reflect_opaque;
impl_reflect_value!(::smol_str::SmolStr(
impl_reflect_opaque!(::smol_str::SmolStr(
Debug,
Hash,
PartialEq,

View File

@ -9,12 +9,12 @@ use crate::{
self as bevy_reflect, impl_type_path, map_apply, map_partial_eq, map_try_apply,
reflect::impl_full_reflect, set_apply, set_partial_eq, set_try_apply, ApplyError, Array,
ArrayInfo, ArrayIter, DynamicMap, DynamicSet, DynamicTypePath, FromReflect, FromType,
GetTypeRegistration, List, ListInfo, ListIter, Map, MapInfo, MapIter, MaybeTyped,
GetTypeRegistration, List, ListInfo, ListIter, Map, MapInfo, MapIter, MaybeTyped, OpaqueInfo,
PartialReflect, Reflect, ReflectDeserialize, ReflectFromPtr, ReflectFromReflect, ReflectKind,
ReflectMut, ReflectOwned, ReflectRef, ReflectSerialize, Set, SetInfo, TypeInfo, TypePath,
TypeRegistration, TypeRegistry, Typed, ValueInfo,
TypeRegistration, TypeRegistry, Typed,
};
use bevy_reflect_derive::{impl_reflect, impl_reflect_value};
use bevy_reflect_derive::{impl_reflect, impl_reflect_opaque};
use std::fmt;
use std::{
any::Any,
@ -24,7 +24,7 @@ use std::{
path::Path,
};
impl_reflect_value!(bool(
impl_reflect_opaque!(bool(
Debug,
Hash,
PartialEq,
@ -32,7 +32,7 @@ impl_reflect_value!(bool(
Deserialize,
Default
));
impl_reflect_value!(char(
impl_reflect_opaque!(char(
Debug,
Hash,
PartialEq,
@ -40,11 +40,11 @@ impl_reflect_value!(char(
Deserialize,
Default
));
impl_reflect_value!(u8(Debug, Hash, PartialEq, Serialize, Deserialize, Default));
impl_reflect_value!(u16(Debug, Hash, PartialEq, Serialize, Deserialize, Default));
impl_reflect_value!(u32(Debug, Hash, PartialEq, Serialize, Deserialize, Default));
impl_reflect_value!(u64(Debug, Hash, PartialEq, Serialize, Deserialize, Default));
impl_reflect_value!(u128(
impl_reflect_opaque!(u8(Debug, Hash, PartialEq, Serialize, Deserialize, Default));
impl_reflect_opaque!(u16(Debug, Hash, PartialEq, Serialize, Deserialize, Default));
impl_reflect_opaque!(u32(Debug, Hash, PartialEq, Serialize, Deserialize, Default));
impl_reflect_opaque!(u64(Debug, Hash, PartialEq, Serialize, Deserialize, Default));
impl_reflect_opaque!(u128(
Debug,
Hash,
PartialEq,
@ -52,7 +52,7 @@ impl_reflect_value!(u128(
Deserialize,
Default
));
impl_reflect_value!(usize(
impl_reflect_opaque!(usize(
Debug,
Hash,
PartialEq,
@ -60,11 +60,11 @@ impl_reflect_value!(usize(
Deserialize,
Default
));
impl_reflect_value!(i8(Debug, Hash, PartialEq, Serialize, Deserialize, Default));
impl_reflect_value!(i16(Debug, Hash, PartialEq, Serialize, Deserialize, Default));
impl_reflect_value!(i32(Debug, Hash, PartialEq, Serialize, Deserialize, Default));
impl_reflect_value!(i64(Debug, Hash, PartialEq, Serialize, Deserialize, Default));
impl_reflect_value!(i128(
impl_reflect_opaque!(i8(Debug, Hash, PartialEq, Serialize, Deserialize, Default));
impl_reflect_opaque!(i16(Debug, Hash, PartialEq, Serialize, Deserialize, Default));
impl_reflect_opaque!(i32(Debug, Hash, PartialEq, Serialize, Deserialize, Default));
impl_reflect_opaque!(i64(Debug, Hash, PartialEq, Serialize, Deserialize, Default));
impl_reflect_opaque!(i128(
Debug,
Hash,
PartialEq,
@ -72,7 +72,7 @@ impl_reflect_value!(i128(
Deserialize,
Default
));
impl_reflect_value!(isize(
impl_reflect_opaque!(isize(
Debug,
Hash,
PartialEq,
@ -80,10 +80,10 @@ impl_reflect_value!(isize(
Deserialize,
Default
));
impl_reflect_value!(f32(Debug, PartialEq, Serialize, Deserialize, Default));
impl_reflect_value!(f64(Debug, PartialEq, Serialize, Deserialize, Default));
impl_reflect_opaque!(f32(Debug, PartialEq, Serialize, Deserialize, Default));
impl_reflect_opaque!(f64(Debug, PartialEq, Serialize, Deserialize, Default));
impl_type_path!(str);
impl_reflect_value!(::alloc::string::String(
impl_reflect_opaque!(::alloc::string::String(
Debug,
Hash,
PartialEq,
@ -91,7 +91,7 @@ impl_reflect_value!(::alloc::string::String(
Deserialize,
Default
));
impl_reflect_value!(::std::path::PathBuf(
impl_reflect_opaque!(::std::path::PathBuf(
Debug,
Hash,
PartialEq,
@ -99,16 +99,16 @@ impl_reflect_value!(::std::path::PathBuf(
Deserialize,
Default
));
impl_reflect_value!(::std::any::TypeId(Debug, Hash, PartialEq,));
impl_reflect_value!(::std::collections::BTreeSet<T: Ord + Eq + Clone + Send + Sync>());
impl_reflect_value!(::core::ops::Range<T: Clone + Send + Sync>());
impl_reflect_value!(::core::ops::RangeInclusive<T: Clone + Send + Sync>());
impl_reflect_value!(::core::ops::RangeFrom<T: Clone + Send + Sync>());
impl_reflect_value!(::core::ops::RangeTo<T: Clone + Send + Sync>());
impl_reflect_value!(::core::ops::RangeToInclusive<T: Clone + Send + Sync>());
impl_reflect_value!(::core::ops::RangeFull());
impl_reflect_value!(::std::ops::Bound<T: Clone + Send + Sync>());
impl_reflect_value!(::bevy_utils::Duration(
impl_reflect_opaque!(::std::any::TypeId(Debug, Hash, PartialEq,));
impl_reflect_opaque!(::std::collections::BTreeSet<T: Ord + Eq + Clone + Send + Sync>());
impl_reflect_opaque!(::core::ops::Range<T: Clone + Send + Sync>());
impl_reflect_opaque!(::core::ops::RangeInclusive<T: Clone + Send + Sync>());
impl_reflect_opaque!(::core::ops::RangeFrom<T: Clone + Send + Sync>());
impl_reflect_opaque!(::core::ops::RangeTo<T: Clone + Send + Sync>());
impl_reflect_opaque!(::core::ops::RangeToInclusive<T: Clone + Send + Sync>());
impl_reflect_opaque!(::core::ops::RangeFull());
impl_reflect_opaque!(::std::ops::Bound<T: Clone + Send + Sync>());
impl_reflect_opaque!(::bevy_utils::Duration(
Debug,
Hash,
PartialEq,
@ -116,99 +116,99 @@ impl_reflect_value!(::bevy_utils::Duration(
Deserialize,
Default
));
impl_reflect_value!(::bevy_utils::Instant(Debug, Hash, PartialEq));
impl_reflect_value!(::core::num::NonZeroI128(
impl_reflect_opaque!(::bevy_utils::Instant(Debug, Hash, PartialEq));
impl_reflect_opaque!(::core::num::NonZeroI128(
Debug,
Hash,
PartialEq,
Serialize,
Deserialize
));
impl_reflect_value!(::core::num::NonZeroU128(
impl_reflect_opaque!(::core::num::NonZeroU128(
Debug,
Hash,
PartialEq,
Serialize,
Deserialize
));
impl_reflect_value!(::core::num::NonZeroIsize(
impl_reflect_opaque!(::core::num::NonZeroIsize(
Debug,
Hash,
PartialEq,
Serialize,
Deserialize
));
impl_reflect_value!(::core::num::NonZeroUsize(
impl_reflect_opaque!(::core::num::NonZeroUsize(
Debug,
Hash,
PartialEq,
Serialize,
Deserialize
));
impl_reflect_value!(::core::num::NonZeroI64(
impl_reflect_opaque!(::core::num::NonZeroI64(
Debug,
Hash,
PartialEq,
Serialize,
Deserialize
));
impl_reflect_value!(::core::num::NonZeroU64(
impl_reflect_opaque!(::core::num::NonZeroU64(
Debug,
Hash,
PartialEq,
Serialize,
Deserialize
));
impl_reflect_value!(::core::num::NonZeroU32(
impl_reflect_opaque!(::core::num::NonZeroU32(
Debug,
Hash,
PartialEq,
Serialize,
Deserialize
));
impl_reflect_value!(::core::num::NonZeroI32(
impl_reflect_opaque!(::core::num::NonZeroI32(
Debug,
Hash,
PartialEq,
Serialize,
Deserialize
));
impl_reflect_value!(::core::num::NonZeroI16(
impl_reflect_opaque!(::core::num::NonZeroI16(
Debug,
Hash,
PartialEq,
Serialize,
Deserialize
));
impl_reflect_value!(::core::num::NonZeroU16(
impl_reflect_opaque!(::core::num::NonZeroU16(
Debug,
Hash,
PartialEq,
Serialize,
Deserialize
));
impl_reflect_value!(::core::num::NonZeroU8(
impl_reflect_opaque!(::core::num::NonZeroU8(
Debug,
Hash,
PartialEq,
Serialize,
Deserialize
));
impl_reflect_value!(::core::num::NonZeroI8(
impl_reflect_opaque!(::core::num::NonZeroI8(
Debug,
Hash,
PartialEq,
Serialize,
Deserialize
));
impl_reflect_value!(::core::num::Wrapping<T: Clone + Send + Sync>());
impl_reflect_value!(::core::num::Saturating<T: Clone + Send + Sync>());
impl_reflect_value!(::std::sync::Arc<T: Send + Sync>);
impl_reflect_opaque!(::core::num::Wrapping<T: Clone + Send + Sync>());
impl_reflect_opaque!(::core::num::Saturating<T: Clone + Send + Sync>());
impl_reflect_opaque!(::std::sync::Arc<T: Send + Sync>);
// `Serialize` and `Deserialize` only for platforms supported by serde:
// https://github.com/serde-rs/serde/blob/3ffb86fc70efd3d329519e2dddfa306cc04f167c/serde/src/de/impls.rs#L1732
#[cfg(any(unix, windows))]
impl_reflect_value!(::std::ffi::OsString(
impl_reflect_opaque!(::std::ffi::OsString(
Debug,
Hash,
PartialEq,
@ -216,8 +216,8 @@ impl_reflect_value!(::std::ffi::OsString(
Deserialize
));
#[cfg(not(any(unix, windows)))]
impl_reflect_value!(::std::ffi::OsString(Debug, Hash, PartialEq));
impl_reflect_value!(::alloc::collections::BinaryHeap<T: Clone>);
impl_reflect_opaque!(::std::ffi::OsString(Debug, Hash, PartialEq));
impl_reflect_opaque!(::alloc::collections::BinaryHeap<T: Clone>);
macro_rules! impl_reflect_for_atomic {
($ty:ty, $ordering:expr) => {
@ -250,8 +250,8 @@ macro_rules! impl_reflect_for_atomic {
fn type_info() -> &'static TypeInfo {
static CELL: NonGenericTypeInfoCell = NonGenericTypeInfoCell::new();
CELL.get_or_set(|| {
let info = ValueInfo::new::<Self>();
TypeInfo::Value(info)
let info = OpaqueInfo::new::<Self>();
TypeInfo::Opaque(info)
})
}
}
@ -308,19 +308,19 @@ macro_rules! impl_reflect_for_atomic {
}
#[inline]
fn reflect_kind(&self) -> ReflectKind {
ReflectKind::Value
ReflectKind::Opaque
}
#[inline]
fn reflect_ref(&self) -> ReflectRef {
ReflectRef::Value(self)
ReflectRef::Opaque(self)
}
#[inline]
fn reflect_mut(&mut self) -> ReflectMut {
ReflectMut::Value(self)
ReflectMut::Opaque(self)
}
#[inline]
fn reflect_owned(self: Box<Self>) -> ReflectOwned {
ReflectOwned::Value(self)
ReflectOwned::Opaque(self)
}
fn debug(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(self, f)
@ -1542,19 +1542,19 @@ impl PartialReflect for Cow<'static, str> {
}
fn reflect_kind(&self) -> ReflectKind {
ReflectKind::Value
ReflectKind::Opaque
}
fn reflect_ref(&self) -> ReflectRef {
ReflectRef::Value(self)
ReflectRef::Opaque(self)
}
fn reflect_mut(&mut self) -> ReflectMut {
ReflectMut::Value(self)
ReflectMut::Opaque(self)
}
fn reflect_owned(self: Box<Self>) -> ReflectOwned {
ReflectOwned::Value(self)
ReflectOwned::Opaque(self)
}
fn clone_value(&self) -> Box<dyn PartialReflect> {
@ -1599,7 +1599,7 @@ impl_full_reflect!(for Cow<'static, str>);
impl Typed for Cow<'static, str> {
fn type_info() -> &'static TypeInfo {
static CELL: NonGenericTypeInfoCell = NonGenericTypeInfoCell::new();
CELL.get_or_set(|| TypeInfo::Value(ValueInfo::new::<Self>()))
CELL.get_or_set(|| TypeInfo::Opaque(OpaqueInfo::new::<Self>()))
}
}
@ -1844,15 +1844,15 @@ impl PartialReflect for &'static str {
}
fn reflect_ref(&self) -> ReflectRef {
ReflectRef::Value(self)
ReflectRef::Opaque(self)
}
fn reflect_mut(&mut self) -> ReflectMut {
ReflectMut::Value(self)
ReflectMut::Opaque(self)
}
fn reflect_owned(self: Box<Self>) -> ReflectOwned {
ReflectOwned::Value(self)
ReflectOwned::Opaque(self)
}
fn clone_value(&self) -> Box<dyn PartialReflect> {
@ -1925,7 +1925,7 @@ impl Reflect for &'static str {
impl Typed for &'static str {
fn type_info() -> &'static TypeInfo {
static CELL: NonGenericTypeInfoCell = NonGenericTypeInfoCell::new();
CELL.get_or_set(|| TypeInfo::Value(ValueInfo::new::<Self>()))
CELL.get_or_set(|| TypeInfo::Opaque(OpaqueInfo::new::<Self>()))
}
}
@ -1978,19 +1978,19 @@ impl PartialReflect for &'static Path {
}
fn reflect_kind(&self) -> ReflectKind {
ReflectKind::Value
ReflectKind::Opaque
}
fn reflect_ref(&self) -> ReflectRef {
ReflectRef::Value(self)
ReflectRef::Opaque(self)
}
fn reflect_mut(&mut self) -> ReflectMut {
ReflectMut::Value(self)
ReflectMut::Opaque(self)
}
fn reflect_owned(self: Box<Self>) -> ReflectOwned {
ReflectOwned::Value(self)
ReflectOwned::Opaque(self)
}
fn clone_value(&self) -> Box<dyn PartialReflect> {
@ -2059,7 +2059,7 @@ impl Reflect for &'static Path {
impl Typed for &'static Path {
fn type_info() -> &'static TypeInfo {
static CELL: NonGenericTypeInfoCell = NonGenericTypeInfoCell::new();
CELL.get_or_set(|| TypeInfo::Value(ValueInfo::new::<Self>()))
CELL.get_or_set(|| TypeInfo::Opaque(OpaqueInfo::new::<Self>()))
}
}
@ -2111,19 +2111,19 @@ impl PartialReflect for Cow<'static, Path> {
}
fn reflect_kind(&self) -> ReflectKind {
ReflectKind::Value
ReflectKind::Opaque
}
fn reflect_ref(&self) -> ReflectRef {
ReflectRef::Value(self)
ReflectRef::Opaque(self)
}
fn reflect_mut(&mut self) -> ReflectMut {
ReflectMut::Value(self)
ReflectMut::Opaque(self)
}
fn reflect_owned(self: Box<Self>) -> ReflectOwned {
ReflectOwned::Value(self)
ReflectOwned::Opaque(self)
}
fn clone_value(&self) -> Box<dyn PartialReflect> {
@ -2196,7 +2196,7 @@ impl Reflect for Cow<'static, Path> {
impl Typed for Cow<'static, Path> {
fn type_info() -> &'static TypeInfo {
static CELL: NonGenericTypeInfoCell = NonGenericTypeInfoCell::new();
CELL.get_or_set(|| TypeInfo::Value(ValueInfo::new::<Self>()))
CELL.get_or_set(|| TypeInfo::Opaque(OpaqueInfo::new::<Self>()))
}
}

View File

@ -1,9 +1,9 @@
use crate as bevy_reflect;
use crate::{std_traits::ReflectDefault, ReflectDeserialize, ReflectSerialize};
use bevy_reflect_derive::impl_reflect_value;
use bevy_reflect_derive::impl_reflect_opaque;
impl_reflect_value!(::uuid::Uuid(
impl_reflect_opaque!(::uuid::Uuid(
Serialize,
Deserialize,
Default,

View File

@ -1,5 +1,6 @@
use crate::{self as bevy_reflect, impl_reflect_value, ReflectDeserialize, ReflectSerialize};
impl_reflect_value!(::wgpu_types::TextureFormat(
use crate::{self as bevy_reflect, impl_reflect_opaque, ReflectDeserialize, ReflectSerialize};
impl_reflect_opaque!(::wgpu_types::TextureFormat(
Debug,
Hash,
PartialEq,

View File

@ -50,17 +50,21 @@ pub enum ReflectKind {
/// [function-like]: Function
#[cfg(feature = "functions")]
Function,
/// A value-like type.
/// An opaque type.
///
/// This most often represents a primitive or opaque type,
/// where it is not possible, difficult, or not useful to reflect the type further.
/// This most often represents a type where it is either impossible, difficult,
/// or unuseful to reflect the type further.
///
/// For example, `u32` and `String` are examples of value-like types.
/// Additionally, any type that derives [`Reflect`] with the `#[reflect_value]` attribute
/// will be considered a value-like type.
/// This includes types like `String` and `Instant`.
///
/// [`Reflect`]: crate::Reflect
Value,
/// Despite not technically being opaque types,
/// primitives like `u32` `i32` are considered opaque for the purposes of reflection.
///
/// Additionally, any type that [derives `Reflect`] with the `#[reflect(opaque)]` attribute
/// will be considered an opaque type.
///
/// [derives `Reflect`]: bevy_reflect_derive::Reflect
Opaque,
}
impl std::fmt::Display for ReflectKind {
@ -76,7 +80,7 @@ impl std::fmt::Display for ReflectKind {
ReflectKind::Enum => f.pad("enum"),
#[cfg(feature = "functions")]
ReflectKind::Function => f.pad("function"),
ReflectKind::Value => f.pad("value"),
ReflectKind::Opaque => f.pad("opaque"),
}
}
}
@ -97,7 +101,7 @@ macro_rules! impl_reflect_kind_conversions {
Self::Enum(_) => ReflectKind::Enum,
#[cfg(feature = "functions")]
Self::Function(_) => ReflectKind::Function,
Self::Value(_) => ReflectKind::Value,
Self::Opaque(_) => ReflectKind::Opaque,
}
}
}
@ -115,7 +119,7 @@ macro_rules! impl_reflect_kind_conversions {
$name::Enum(_) => Self::Enum,
#[cfg(feature = "functions")]
$name::Function(_) => Self::Function,
$name::Value(_) => Self::Value,
$name::Opaque(_) => Self::Opaque,
}
}
}
@ -133,14 +137,14 @@ pub struct ReflectKindMismatchError {
}
macro_rules! impl_cast_method {
($name:ident : Value => $retval:ty) => {
($name:ident : Opaque => $retval:ty) => {
#[doc = "Attempts a cast to a [`PartialReflect`] trait object."]
#[doc = "\n\nReturns an error if `self` is not the [`Self::Value`] variant."]
#[doc = "\n\nReturns an error if `self` is not the [`Self::Opaque`] variant."]
pub fn $name(self) -> Result<$retval, ReflectKindMismatchError> {
match self {
Self::Value(value) => Ok(value),
Self::Opaque(value) => Ok(value),
_ => Err(ReflectKindMismatchError {
expected: ReflectKind::Value,
expected: ReflectKind::Opaque,
received: self.kind(),
}),
}
@ -180,7 +184,7 @@ pub enum ReflectRef<'a> {
Enum(&'a dyn Enum),
#[cfg(feature = "functions")]
Function(&'a dyn Function),
Value(&'a dyn PartialReflect),
Opaque(&'a dyn PartialReflect),
}
impl_reflect_kind_conversions!(ReflectRef<'_>);
@ -193,7 +197,7 @@ impl<'a> ReflectRef<'a> {
impl_cast_method!(as_map: Map => &'a dyn Map);
impl_cast_method!(as_set: Set => &'a dyn Set);
impl_cast_method!(as_enum: Enum => &'a dyn Enum);
impl_cast_method!(as_value: Value => &'a dyn PartialReflect);
impl_cast_method!(as_opaque: Opaque => &'a dyn PartialReflect);
}
/// A mutable enumeration of ["kinds"] of a reflected type.
@ -215,7 +219,7 @@ pub enum ReflectMut<'a> {
Enum(&'a mut dyn Enum),
#[cfg(feature = "functions")]
Function(&'a mut dyn Function),
Value(&'a mut dyn PartialReflect),
Opaque(&'a mut dyn PartialReflect),
}
impl_reflect_kind_conversions!(ReflectMut<'_>);
@ -228,7 +232,7 @@ impl<'a> ReflectMut<'a> {
impl_cast_method!(as_map: Map => &'a mut dyn Map);
impl_cast_method!(as_set: Set => &'a mut dyn Set);
impl_cast_method!(as_enum: Enum => &'a mut dyn Enum);
impl_cast_method!(as_value: Value => &'a mut dyn PartialReflect);
impl_cast_method!(as_opaque: Opaque => &'a mut dyn PartialReflect);
}
/// An owned enumeration of ["kinds"] of a reflected type.
@ -250,7 +254,7 @@ pub enum ReflectOwned {
Enum(Box<dyn Enum>),
#[cfg(feature = "functions")]
Function(Box<dyn Function>),
Value(Box<dyn PartialReflect>),
Opaque(Box<dyn PartialReflect>),
}
impl_reflect_kind_conversions!(ReflectOwned);
@ -263,7 +267,7 @@ impl ReflectOwned {
impl_cast_method!(into_map: Map => Box<dyn Map>);
impl_cast_method!(into_set: Set => Box<dyn Set>);
impl_cast_method!(into_enum: Enum => Box<dyn Enum>);
impl_cast_method!(into_value: Value => Box<dyn PartialReflect>);
impl_cast_method!(into_value: Opaque => Box<dyn PartialReflect>);
}
#[cfg(test)]

View File

@ -164,15 +164,17 @@
//! we can just use the matching [`PartialReflect::as_partial_reflect`], [`PartialReflect::as_partial_reflect_mut`],
//! or [`PartialReflect::into_partial_reflect`] methods.
//!
//! ## Value Types
//! ## Opaque Types
//!
//! Types that do not fall under one of the above subtraits,
//! such as for primitives (e.g. `bool`, `usize`, etc.)
//! and simple types (e.g. `String`, `Duration`),
//! are referred to as _value_ types
//! since methods like [`PartialReflect::reflect_ref`] return a [`ReflectRef::Value`] variant.
//! While most other types contain their own `dyn Reflect` fields and data,
//! these types generally cannot be broken down any further.
//! Some types don't fall under a particular subtrait.
//!
//! These types hide their internal structure to reflection,
//! either because it is not possible, difficult, or not useful to reflect its internals.
//! Such types are known as _opaque_ types.
//!
//! This includes truly opaque types like `String` or `Instant`,
//! but also includes all the primitive types (e.g. `bool`, `usize`, etc.)
//! since they can't be broken down any further.
//!
//! # Dynamic Types
//!
@ -198,7 +200,7 @@
//!
//! They are most commonly used as "proxies" for other types,
//! where they contain the same data as— and therefore, represent— a concrete type.
//! The [`PartialReflect::clone_value`] method will return a dynamic type for all non-value types,
//! The [`PartialReflect::clone_value`] method will return a dynamic type for all non-opaque types,
//! allowing all types to essentially be "cloned".
//! And since dynamic types themselves implement [`PartialReflect`],
//! we may pass them around just like most other reflected types.
@ -398,7 +400,7 @@
//! The `TypedReflectSerializer` will simply output the serialized data.
//!
//! The `ReflectDeserializer` can be used to deserialize this map and return a `Box<dyn Reflect>`,
//! where the underlying type will be a dynamic type representing some concrete type (except for value types).
//! where the underlying type will be a dynamic type representing some concrete type (except for opaque types).
//!
//! Again, it's important to remember that dynamic types may need to be converted to their concrete counterparts
//! in order to be used in certain cases.
@ -1792,7 +1794,7 @@ mod tests {
// Cow<'static, str>
type MyCowStr = Cow<'static, str>;
let info = MyCowStr::type_info().as_value().unwrap();
let info = MyCowStr::type_info().as_opaque().unwrap();
assert!(info.is::<MyCowStr>());
assert_eq!(std::any::type_name::<MyCowStr>(), info.type_path());
@ -1837,7 +1839,7 @@ mod tests {
// Value
type MyValue = String;
let info = MyValue::type_info().as_value().unwrap();
let info = MyValue::type_info().as_opaque().unwrap();
assert!(info.is::<MyValue>());
assert_eq!(MyValue::type_path(), info.type_path());
@ -1956,7 +1958,7 @@ mod tests {
#[derive(Clone)]
struct SomePrimitive;
impl_reflect_value!(
impl_reflect_opaque!(
/// Some primitive for which we have attributed custom documentation.
(in bevy_reflect::tests) SomePrimitive
);
@ -2172,27 +2174,6 @@ bevy_reflect::tests::Test {
assert_eq!("Foo".to_string(), format!("{foo:?}"));
}
#[test]
fn multiple_reflect_value_lists() {
#[derive(Clone, Hash, PartialEq, Reflect)]
#[reflect_value(Debug, Hash)]
#[reflect_value(PartialEq)]
struct Foo(i32);
impl Debug for Foo {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "Foo")
}
}
let foo = Foo(123);
let foo: &dyn PartialReflect = &foo;
assert!(foo.reflect_hash().is_some());
assert_eq!(Some(true), foo.reflect_partial_eq(foo));
assert_eq!("Foo".to_string(), format!("{foo:?}"));
}
#[test]
fn custom_debug_function() {
#[derive(Reflect)]
@ -2591,7 +2572,8 @@ bevy_reflect::tests::Test {
// === Remote Wrapper === //
#[reflect_remote(external_crate::TheirType)]
#[derive(Clone, Debug, Default)]
#[reflect_value(Debug, Default)]
#[reflect(opaque)]
#[reflect(Debug, Default)]
struct MyType {
pub value: String,
}

View File

@ -1,8 +1,7 @@
use crate::{
array_debug, enum_debug, list_debug, map_debug, serde::Serializable, set_debug, struct_debug,
tuple_debug, tuple_struct_debug, DynamicTypePath, DynamicTyped, ReflectKind,
tuple_debug, tuple_struct_debug, DynamicTypePath, DynamicTyped, OpaqueInfo, ReflectKind,
ReflectKindMismatchError, ReflectMut, ReflectOwned, ReflectRef, TypeInfo, TypePath, Typed,
ValueInfo,
};
use std::{
any::{Any, TypeId},
@ -178,7 +177,7 @@ where
/// a `List`, while `value` is a `Struct`).
/// - If `T` is any complex type and the corresponding fields or elements of
/// `self` and `value` are not of the same type.
/// - If `T` is a value type and `self` cannot be downcast to `T`
/// - If `T` is an opaque type and `self` cannot be downcast to `T`
fn apply(&mut self, value: &dyn PartialReflect) {
PartialReflect::try_apply(self, value).unwrap();
}
@ -266,7 +265,7 @@ where
ReflectRef::Enum(dyn_enum) => enum_debug(dyn_enum, f),
#[cfg(feature = "functions")]
ReflectRef::Function(dyn_function) => dyn_function.fmt(f),
ReflectRef::Value(_) => write!(f, "Reflect({})", self.reflect_type_path()),
ReflectRef::Opaque(_) => write!(f, "Reflect({})", self.reflect_type_path()),
}
}
@ -497,7 +496,7 @@ impl Debug for dyn Reflect {
impl Typed for dyn Reflect {
fn type_info() -> &'static TypeInfo {
static CELL: NonGenericTypeInfoCell = NonGenericTypeInfoCell::new();
CELL.get_or_set(|| TypeInfo::Value(ValueInfo::new::<Self>()))
CELL.get_or_set(|| TypeInfo::Opaque(OpaqueInfo::new::<Self>()))
}
}

View File

@ -32,7 +32,7 @@ use std::fmt;
///
/// This deserializer will return a [`Box<dyn Reflect>`] containing the deserialized data.
///
/// For value types (i.e. [`ReflectKind::Value`]) or types that register [`ReflectDeserialize`] type data,
/// For opaque types (i.e. [`ReflectKind::Opaque`]) or types that register [`ReflectDeserialize`] type data,
/// this `Box` will contain the expected type.
/// For example, deserializing an `i32` will return a `Box<i32>` (as a `Box<dyn Reflect>`).
///
@ -69,7 +69,7 @@ use std::fmt;
///
/// let output: Box<dyn PartialReflect> = reflect_deserializer.deserialize(&mut deserializer).unwrap();
///
/// // Since `MyStruct` is not a value type and does not register `ReflectDeserialize`,
/// // Since `MyStruct` is not an opaque type and does not register `ReflectDeserialize`,
/// // we know that its deserialized value will be a `DynamicStruct`,
/// // although it will represent `MyStruct`.
/// assert!(output.as_partial_reflect().represents::<MyStruct>());
@ -89,7 +89,7 @@ use std::fmt;
/// [`ReflectSerializer`]: crate::serde::ReflectSerializer
/// [type path]: crate::TypePath::type_path
/// [`Box<dyn Reflect>`]: crate::Reflect
/// [`ReflectKind::Value`]: crate::ReflectKind::Value
/// [`ReflectKind::Opaque`]: crate::ReflectKind::Opaque
/// [`ReflectDeserialize`]: crate::ReflectDeserialize
/// [`Box<DynamicStruct>`]: crate::DynamicStruct
/// [`Box<DynamicList>`]: crate::DynamicList
@ -165,7 +165,7 @@ impl<'a, 'de> DeserializeSeed<'de> for ReflectDeserializer<'a> {
///
/// This deserializer will return a [`Box<dyn Reflect>`] containing the deserialized data.
///
/// For value types (i.e. [`ReflectKind::Value`]) or types that register [`ReflectDeserialize`] type data,
/// For opaque types (i.e. [`ReflectKind::Opaque`]) or types that register [`ReflectDeserialize`] type data,
/// this `Box` will contain the expected type.
/// For example, deserializing an `i32` will return a `Box<i32>` (as a `Box<dyn Reflect>`).
///
@ -202,7 +202,7 @@ impl<'a, 'de> DeserializeSeed<'de> for ReflectDeserializer<'a> {
///
/// let output: Box<dyn PartialReflect> = reflect_deserializer.deserialize(&mut deserializer).unwrap();
///
/// // Since `MyStruct` is not a value type and does not register `ReflectDeserialize`,
/// // Since `MyStruct` is not an opaque type and does not register `ReflectDeserialize`,
/// // we know that its deserialized value will be a `DynamicStruct`,
/// // although it will represent `MyStruct`.
/// assert!(output.as_partial_reflect().represents::<MyStruct>());
@ -221,7 +221,7 @@ impl<'a, 'de> DeserializeSeed<'de> for ReflectDeserializer<'a> {
///
/// [`TypedReflectSerializer`]: crate::serde::TypedReflectSerializer
/// [`Box<dyn Reflect>`]: crate::Reflect
/// [`ReflectKind::Value`]: crate::ReflectKind::Value
/// [`ReflectKind::Opaque`]: crate::ReflectKind::Opaque
/// [`ReflectDeserialize`]: crate::ReflectDeserialize
/// [`Box<DynamicStruct>`]: crate::DynamicStruct
/// [`Box<DynamicList>`]: crate::DynamicList
@ -345,7 +345,7 @@ impl<'a, 'de> DeserializeSeed<'de> for TypedReflectDeserializer<'a> {
dynamic_enum.set_represented_type(Some(self.registration.type_info()));
Ok(Box::new(dynamic_enum))
}
TypeInfo::Value(_) => {
TypeInfo::Opaque(_) => {
// This case should already be handled
Err(make_custom_error(format_args!(
"type `{type_path}` did not register the `ReflectDeserialize` type data. For certain types, this may need to be registered manually using `register_type_data`",

View File

@ -196,7 +196,7 @@ impl<'a> Serialize for TypedReflectSerializer<'a> {
}
#[cfg(feature = "functions")]
ReflectRef::Function(_) => Err(make_custom_error("functions cannot be serialized")),
ReflectRef::Value(_) => Err(serializable.err().unwrap()),
ReflectRef::Opaque(_) => Err(serializable.err().unwrap()),
};
#[cfg(feature = "debug_stack")]

View File

@ -32,7 +32,7 @@ use thiserror::Error;
///
/// ```
/// # use std::any::Any;
/// # use bevy_reflect::{DynamicTypePath, NamedField, PartialReflect, Reflect, ReflectMut, ReflectOwned, ReflectRef, StructInfo, TypeInfo, TypePath, ValueInfo, ApplyError};
/// # use bevy_reflect::{DynamicTypePath, NamedField, PartialReflect, Reflect, ReflectMut, ReflectOwned, ReflectRef, StructInfo, TypeInfo, TypePath, OpaqueInfo, ApplyError};
/// # use bevy_reflect::utility::NonGenericTypeInfoCell;
/// use bevy_reflect::Typed;
///
@ -207,7 +207,7 @@ pub enum TypeInfo {
Map(MapInfo),
Set(SetInfo),
Enum(EnumInfo),
Value(ValueInfo),
Opaque(OpaqueInfo),
}
impl TypeInfo {
@ -224,7 +224,7 @@ impl TypeInfo {
Self::Map(info) => info.ty(),
Self::Set(info) => info.ty(),
Self::Enum(info) => info.ty(),
Self::Value(info) => info.ty(),
Self::Opaque(info) => info.ty(),
}
}
@ -272,7 +272,7 @@ impl TypeInfo {
Self::Map(info) => info.docs(),
Self::Set(info) => info.docs(),
Self::Enum(info) => info.docs(),
Self::Value(info) => info.docs(),
Self::Opaque(info) => info.docs(),
}
}
@ -289,7 +289,7 @@ impl TypeInfo {
Self::Map(_) => ReflectKind::Map,
Self::Set(_) => ReflectKind::Set,
Self::Enum(_) => ReflectKind::Enum,
Self::Value(_) => ReflectKind::Value,
Self::Opaque(_) => ReflectKind::Opaque,
}
}
}
@ -319,7 +319,7 @@ impl TypeInfo {
impl_cast_method!(as_array: Array => ArrayInfo);
impl_cast_method!(as_map: Map => MapInfo);
impl_cast_method!(as_enum: Enum => EnumInfo);
impl_cast_method!(as_value: Value => ValueInfo);
impl_cast_method!(as_opaque: Opaque => OpaqueInfo);
}
/// The base representation of a Rust type.
@ -516,22 +516,22 @@ macro_rules! impl_type_methods {
pub(crate) use impl_type_methods;
/// A container for compile-time info related to general value types, including primitives.
/// A container for compile-time info related to reflection-opaque types, including primitives.
///
/// This typically represents a type which cannot be broken down any further. This is often
/// due to technical reasons (or by definition), but it can also be a purposeful choice.
///
/// For example, [`i32`] cannot be broken down any further, so it is represented by a [`ValueInfo`].
/// For example, [`i32`] cannot be broken down any further, so it is represented by an [`OpaqueInfo`].
/// And while [`String`] itself is a struct, its fields are private, so we don't really treat
/// it _as_ a struct. It therefore makes more sense to represent it as a [`ValueInfo`].
/// it _as_ a struct. It therefore makes more sense to represent it as an [`OpaqueInfo`].
#[derive(Debug, Clone)]
pub struct ValueInfo {
pub struct OpaqueInfo {
ty: Type,
#[cfg(feature = "documentation")]
docs: Option<&'static str>,
}
impl ValueInfo {
impl OpaqueInfo {
pub fn new<T: Reflect + TypePath + ?Sized>() -> Self {
Self {
ty: Type::of::<T>(),
@ -540,7 +540,7 @@ impl ValueInfo {
}
}
/// Sets the docstring for this value.
/// Sets the docstring for this type.
#[cfg(feature = "documentation")]
pub fn with_docs(self, doc: Option<&'static str>) -> Self {
Self { docs: doc, ..self }
@ -548,7 +548,7 @@ impl ValueInfo {
impl_type_methods!(ty);
/// The docstring of this dynamic value, if any.
/// The docstring of this dynamic type, if any.
#[cfg(feature = "documentation")]
pub fn docs(&self) -> Option<&'static str> {
self.docs

View File

@ -92,7 +92,8 @@ pub struct ComputedCameraValues {
///
/// <https://en.wikipedia.org/wiki/Exposure_(photography)>
#[derive(Component, Clone, Copy, Reflect)]
#[reflect_value(Component, Default)]
#[reflect(opaque)]
#[reflect(Component, Default)]
pub struct Exposure {
/// <https://en.wikipedia.org/wiki/Exposure_value#Tabulated_exposure_values>
pub ev100: f32,
@ -614,7 +615,8 @@ impl Default for CameraOutputMode {
/// Configures the [`RenderGraph`](crate::render_graph::RenderGraph) name assigned to be run for a given [`Camera`] entity.
#[derive(Component, Debug, Deref, DerefMut, Reflect, Clone)]
#[reflect_value(Component, Debug)]
#[reflect(opaque)]
#[reflect(Component, Debug)]
pub struct CameraRenderGraph(InternedRenderSubGraph);
impl CameraRenderGraph {
@ -901,7 +903,8 @@ pub fn camera_system<T: CameraProjection + Component>(
/// This component lets you control the [`TextureUsages`] field of the main texture generated for the camera
#[derive(Component, ExtractComponent, Clone, Copy, Reflect)]
#[reflect_value(Component, Default)]
#[reflect(opaque)]
#[reflect(Component, Default)]
pub struct CameraMainTextureUsages(pub TextureUsages);
impl Default for CameraMainTextureUsages {
fn default() -> Self {

View File

@ -91,7 +91,8 @@ bitflags::bitflags! {
/// details.
#[repr(transparent)]
#[derive(Serialize, Deserialize, Hash, Clone, Copy, PartialEq, Eq, Debug, Reflect)]
#[reflect_value(Serialize, Deserialize, Hash, PartialEq, Debug)]
#[reflect(opaque)]
#[reflect(Serialize, Deserialize, Hash, PartialEq, Debug)]
pub struct RenderAssetUsages: u8 {
const MAIN_WORLD = 1 << 0;
const RENDER_WORLD = 1 << 1;

View File

@ -27,7 +27,8 @@ impl Plugin for StoragePlugin {
/// A storage buffer that is prepared as a [`RenderAsset`] and uploaded to the GPU.
#[derive(Asset, Reflect, Debug, Clone)]
#[reflect_value(Default)]
#[reflect(opaque)]
#[reflect(Default, Debug)]
pub struct ShaderStorageBuffer {
/// Optional data used to initialize the buffer.
pub data: Option<Vec<u8>>,

View File

@ -167,7 +167,8 @@ impl ImageFormat {
}
#[derive(Asset, Reflect, Debug, Clone)]
#[reflect_value(Default)]
#[reflect(opaque)]
#[reflect(Default, Debug)]
pub struct Image {
pub data: Vec<u8>,
// TODO: this nesting makes accessing Image metadata verbose. Either flatten out descriptor or add accessors

View File

@ -104,7 +104,7 @@ fn setup(type_registry: Res<AppTypeRegistry>) {
// Deserializing returns a `Box<dyn PartialReflect>` value.
// Generally, deserializing a value will return the "dynamic" variant of a type.
// For example, deserializing a struct will return the DynamicStruct type.
// "Value types" will be deserialized as themselves.
// "Opaque types" will be deserialized as themselves.
assert_eq!(
reflect_value.reflect_type_path(),
DynamicStruct::type_path(),

View File

@ -53,12 +53,12 @@ pub struct E {
}
/// By default, deriving with Reflect assumes the type is either a "struct" or an "enum".
/// You can tell reflect to treat your type instead as a "value type" by using the `reflect_value`
/// attribute in place of `reflect`. It is generally a good idea to implement (and reflect)
/// the `PartialEq`, `Serialize`, and `Deserialize` traits on `reflect_value` types to ensure
/// that these values behave as expected when nested underneath Reflect-ed structs.
/// You can tell reflect to treat your type instead as an "opaque type" by using the `#[reflect(opaque)]`.
/// It is generally a good idea to implement (and reflect) the `PartialEq`, `Serialize`, and `Deserialize`
/// traits on opaque types to ensure that these values behave as expected when nested in other reflected types.
#[derive(Reflect, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[reflect_value(PartialEq, Serialize, Deserialize)]
#[reflect(opaque)]
#[reflect(PartialEq, Serialize, Deserialize)]
#[allow(dead_code)]
enum F {
X,
@ -118,10 +118,10 @@ fn setup() {
// This variant only exists if the `reflect_functions` feature is enabled.
#[cfg(feature = "reflect_functions")]
ReflectRef::Function(_) => {}
// `Value` types do not implement any of the other traits above. They are simply a Reflect
// implementation. Value is implemented for core types like i32, usize, f32, and
// String.
ReflectRef::Value(_) => {}
// `Opaque` types do not implement any of the other traits above. They are simply a Reflect
// implementation. Opaque is implemented for opaque types like String and Instant,
// but also include primitive types like i32, usize, and f32 (despite not technically being opaque).
ReflectRef::Opaque(_) => {}
}
let mut dynamic_list = DynamicList::default();