Skip to content

Commit

Permalink
Change return type to Result
Browse files Browse the repository at this point in the history
  • Loading branch information
MrGVSV committed May 22, 2024
1 parent 74ee004 commit ad1146e
Show file tree
Hide file tree
Showing 10 changed files with 308 additions and 124 deletions.
10 changes: 5 additions & 5 deletions crates/bevy_reflect/derive/src/container_attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::custom_attributes::CustomAttributes;
use crate::derive_data::ReflectTraitToImpl;
use crate::utility;
use crate::utility::terminated_parser;
use bevy_macro_utils::fq_std::{FQAny, FQBox, FQClone, FQOption};
use bevy_macro_utils::fq_std::{FQAny, FQBox, FQClone, FQOption, FQResult};
use proc_macro2::{Ident, Span};
use quote::quote_spanned;
use syn::ext::IdentExt;
Expand Down Expand Up @@ -541,14 +541,14 @@ impl ContainerAttributes {
match &self.clone {
&TraitImpl::Implemented(span) => Some(quote_spanned! {span=>
#[inline]
fn reflect_clone(&self) -> #FQOption<#FQBox<dyn #bevy_reflect_path::Reflect>> {
#FQOption::Some(#FQBox::new(#FQClone::clone(self)))
fn reflect_clone(&self) -> #FQResult<#FQBox<dyn #bevy_reflect_path::Reflect>, #bevy_reflect_path::ReflectCloneError> {
#FQResult::Ok(#FQBox::new(#FQClone::clone(self)))
}
}),
&TraitImpl::Custom(ref impl_fn, span) => Some(quote_spanned! {span=>
#[inline]
fn reflect_clone(&self) -> #FQOption<#FQBox<dyn #bevy_reflect_path::Reflect>> {
#FQOption::Some(#FQBox::new(#impl_fn(self)))
fn reflect_clone(&self) -> #FQResult<#FQBox<dyn #bevy_reflect_path::Reflect>, #bevy_reflect_path::ReflectCloneError> {
#FQResult::Ok(#FQBox::new(#impl_fn(self)))
}
}),
TraitImpl::NotImplemented => None,
Expand Down
61 changes: 51 additions & 10 deletions crates/bevy_reflect/derive/src/derive_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use crate::{
utility, REFLECT_ATTRIBUTE_NAME, REFLECT_VALUE_ATTRIBUTE_NAME, TYPE_NAME_ATTRIBUTE_NAME,
TYPE_PATH_ATTRIBUTE_NAME,
};
use bevy_macro_utils::fq_std::{FQBox, FQClone, FQOption};
use bevy_macro_utils::fq_std::{FQBox, FQClone, FQOption, FQResult};
use syn::punctuated::Punctuated;
use syn::spanned::Spanned;
use syn::{
Expand Down Expand Up @@ -520,6 +520,20 @@ impl<'a> StructField<'a> {

info
}

/// Returns a token stream for generating a `FieldId` for this field.
pub fn field_id(&self, bevy_reflect_path: &Path) -> proc_macro2::TokenStream {
match &self.data.ident {
Some(ident) => {
let name = ident.to_string();
quote!(#bevy_reflect_path::FieldId::Named(#name))
}
None => {
let index = self.declaration_index;
quote!(#bevy_reflect_path::FieldId::Unnamed(#index))
}
}
}
}

impl<'a> ReflectStruct<'a> {
Expand Down Expand Up @@ -635,16 +649,41 @@ impl<'a> ReflectStruct<'a> {
let mut tokens = proc_macro2::TokenStream::new();

for field in self.fields() {
let field_ty = &field.data.ty;
let member = ident_or_index(field.data.ident.as_ref(), field.declaration_index);

match &field.attrs.clone {
CloneBehavior::Default => {
if field.attrs.ignore.is_ignored() {
return None;
}
let value = if field.attrs.ignore.is_ignored() {
let field_id = field.field_id(bevy_reflect_path);

quote! {
return #FQResult::Err(#bevy_reflect_path::ReflectCloneError::FieldNotClonable {
field: #field_id,
variant: #FQOption::None,
container_type_path: ::std::borrow::Cow::Borrowed(
<Self as #bevy_reflect_path::TypePath>::type_path()
)
})
}
} else {
quote! {
#bevy_reflect_path::Reflect::reflect_clone(&self.#member)?
.take()
.map_err(|value| #bevy_reflect_path::ReflectCloneError::FailedDowncast {
expected: ::std::borrow::Cow::Borrowed(
<#field_ty as #bevy_reflect_path::TypePath>::type_path()
),
received: ::std::borrow::Cow::Owned(
#bevy_reflect_path::DynamicTypePath::reflect_type_path(&*value)
.to_string()
),
})?
}
};

tokens.extend(quote! {
#member: #bevy_reflect_path::Reflect::reflect_clone(&self.#member)?.take().ok()?,
#member: #value,
});
}
CloneBehavior::Trait => {
Expand All @@ -662,8 +701,9 @@ impl<'a> ReflectStruct<'a> {

Some(quote! {
#[inline]
fn reflect_clone(&self) -> #FQOption<#FQBox<dyn #bevy_reflect_path::Reflect>> {
#FQOption::Some(#FQBox::new(Self {
fn reflect_clone(&self) -> #FQResult<#FQBox<dyn #bevy_reflect_path::Reflect>, #bevy_reflect_path::ReflectCloneError> {
#[allow(unreachable_code)]
#FQResult::Ok(#FQBox::new(Self {
#tokens
}))
}
Expand Down Expand Up @@ -772,12 +812,13 @@ impl<'a> ReflectEnum<'a> {
variant_patterns,
variant_constructors,
..
} = ReflectCloneVariantBuilder::new(self).build(&this)?;
} = ReflectCloneVariantBuilder::new(self).build(&this);

Some(quote! {
#[inline]
fn reflect_clone(&#this) -> #FQOption<#FQBox<dyn #bevy_reflect_path::Reflect>> {
#FQOption::Some(#FQBox::new(match #this {
fn reflect_clone(&self) -> #FQResult<#FQBox<dyn #bevy_reflect_path::Reflect>, #bevy_reflect_path::ReflectCloneError> {
#[allow(unreachable_code)]
#FQResult::Ok(#FQBox::new(match #this {
#(#variant_patterns => #variant_constructors),*
}))
}
Expand Down
167 changes: 83 additions & 84 deletions crates/bevy_reflect/derive/src/enum_utility.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::derive_data::StructField;
use crate::field_attributes::{CloneBehavior, DefaultBehavior};
use crate::{derive_data::ReflectEnum, utility::ident_or_index};
use bevy_macro_utils::fq_std::{FQClone, FQDefault, FQOption};
use bevy_macro_utils::fq_std::{FQClone, FQDefault, FQOption, FQResult};
use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote};

Expand Down Expand Up @@ -34,9 +34,6 @@ pub(crate) struct VariantField<'a, 'b> {

/// Trait used to control how enum variants are built.
pub(crate) trait VariantBuilder: Sized {
/// The variant output data.
type Output;

/// Returns the enum data.
fn reflect_enum(&self) -> &ReflectEnum;

Expand Down Expand Up @@ -121,83 +118,79 @@ pub(crate) trait VariantBuilder: Sized {

/// Returns a token stream that constructs an instance of an ignored field.
///
/// If the ignored field cannot be adequately handled, `None` should be returned.
///
/// # Parameters
/// * `field`: The field to access
fn on_ignored_field(&self, field: VariantField) -> Option<TokenStream> {
Some(match &field.field.attrs.default {
fn on_ignored_field(&self, field: VariantField) -> TokenStream {
match &field.field.attrs.default {
DefaultBehavior::Func(path) => quote! { #path() },
_ => quote! { #FQDefault::default() },
})
}
}

/// Builds the enum variant output data.
fn build(&self, this: &Ident) -> Self::Output;
}
fn build(&self, this: &Ident) -> EnumVariantOutputData {
let variants = self.reflect_enum().variants();

fn build<V: VariantBuilder>(builder: &V, this: &Ident) -> Option<EnumVariantOutputData> {
let variants = builder.reflect_enum().variants();
let mut variant_names = Vec::with_capacity(variants.len());
let mut variant_patterns = Vec::with_capacity(variants.len());
let mut variant_constructors = Vec::with_capacity(variants.len());

let mut variant_names = Vec::with_capacity(variants.len());
let mut variant_patterns = Vec::with_capacity(variants.len());
let mut variant_constructors = Vec::with_capacity(variants.len());
for variant in variants {
let variant_ident = &variant.data.ident;
let variant_name = variant_ident.to_string();
let variant_path = self.reflect_enum().get_unit(variant_ident);

for variant in variants {
let variant_ident = &variant.data.ident;
let variant_name = variant_ident.to_string();
let variant_path = builder.reflect_enum().get_unit(variant_ident);
let fields = variant.fields();

let fields = variant.fields();
let mut field_patterns = Vec::with_capacity(fields.len());
let mut field_constructors = Vec::with_capacity(fields.len());

let mut field_patterns = Vec::with_capacity(fields.len());
let mut field_constructors = Vec::with_capacity(fields.len());
for field in fields {
let member = ident_or_index(field.data.ident.as_ref(), field.declaration_index);
let alias = format_ident!("_{}", member);

for field in fields {
let member = ident_or_index(field.data.ident.as_ref(), field.declaration_index);
let alias = format_ident!("_{}", member);
let variant_field = VariantField {
alias: &alias,
variant_name: &variant_name,
field,
};

let variant_field = VariantField {
alias: &alias,
variant_name: &variant_name,
field,
};
let value = if field.attrs.ignore.is_ignored() {
self.on_ignored_field(variant_field)
} else {
self.on_active_field(this, variant_field)
};

let value = if field.attrs.ignore.is_ignored() {
builder.on_ignored_field(variant_field)?
} else {
builder.on_active_field(this, variant_field)
};
field_patterns.push(quote! {
#member: #alias
});

field_patterns.push(quote! {
#member: #alias
});
field_constructors.push(quote! {
#member: #value
});
}

field_constructors.push(quote! {
#member: #value
});
}
let pattern = quote! {
#variant_path { #( #field_patterns ),* }
};

let pattern = quote! {
#variant_path { #( #field_patterns ),* }
};
let constructor = quote! {
#variant_path {
#( #field_constructors ),*
}
};

let constructor = quote! {
#variant_path {
#( #field_constructors ),*
}
};
variant_names.push(variant_name);
variant_patterns.push(pattern);
variant_constructors.push(constructor);
}

variant_names.push(variant_name);
variant_patterns.push(pattern);
variant_constructors.push(constructor);
EnumVariantOutputData {
variant_names,
variant_patterns,
variant_constructors,
}
}

Some(EnumVariantOutputData {
variant_names,
variant_patterns,
variant_constructors,
})
}

/// Generates the enum variant output data needed to build the `FromReflect::from_reflect` implementation.
Expand All @@ -212,8 +205,6 @@ impl<'a> FromReflectVariantBuilder<'a> {
}

impl<'a> VariantBuilder for FromReflectVariantBuilder<'a> {
type Output = EnumVariantOutputData;

fn reflect_enum(&self) -> &ReflectEnum {
self.reflect_enum
}
Expand All @@ -232,10 +223,6 @@ impl<'a> VariantBuilder for FromReflectVariantBuilder<'a> {
<#field_ty as #bevy_reflect_path::FromReflect>::from_reflect(#alias)?
}
}

fn build(&self, this: &Ident) -> Self::Output {
build(self, this).expect("internal bevy_reflect error: ignored fields should be handled")
}
}

/// Generates the enum variant output data needed to build the `Reflect::try_apply` implementation.
Expand All @@ -250,8 +237,6 @@ impl<'a> TryApplyVariantBuilder<'a> {
}

impl<'a> VariantBuilder for TryApplyVariantBuilder<'a> {
type Output = EnumVariantOutputData;

fn reflect_enum(&self) -> &ReflectEnum {
self.reflect_enum
}
Expand Down Expand Up @@ -294,10 +279,6 @@ impl<'a> VariantBuilder for TryApplyVariantBuilder<'a> {
})?
}
}

fn build(&self, this: &Ident) -> Self::Output {
build(self, this).expect("internal bevy_reflect error: ignored fields should be handled")
}
}

/// Generates the enum variant output data needed to build the `Reflect::reflect_clone` implementation.
Expand All @@ -312,7 +293,6 @@ impl<'a> ReflectCloneVariantBuilder<'a> {
}

impl<'a> VariantBuilder for ReflectCloneVariantBuilder<'a> {
type Output = Option<EnumVariantOutputData>;
fn reflect_enum(&self) -> &ReflectEnum {
self.reflect_enum
}
Expand All @@ -331,11 +311,22 @@ impl<'a> VariantBuilder for ReflectCloneVariantBuilder<'a> {
let bevy_reflect_path = self.reflect_enum.meta().bevy_reflect_path();

let alias = field.alias;
let field_ty = &field.field.data.ty;

match &field.field.attrs.clone {
CloneBehavior::Default => {
quote! {
#bevy_reflect_path::Reflect::reflect_clone(#alias)?.take().ok()?
#bevy_reflect_path::Reflect::reflect_clone(#alias)?
.take()
.map_err(|value| #bevy_reflect_path::ReflectCloneError::FailedDowncast {
expected: ::std::borrow::Cow::Borrowed(
<#field_ty as #bevy_reflect_path::TypePath>::type_path()
),
received: ::std::borrow::Cow::Owned(
#bevy_reflect_path::DynamicTypePath::reflect_type_path(&*value)
.to_string()
),
})?
}
}
CloneBehavior::Trait => {
Expand All @@ -355,19 +346,27 @@ impl<'a> VariantBuilder for ReflectCloneVariantBuilder<'a> {
self.construct_field(field)
}

fn on_ignored_field(&self, field: VariantField) -> Option<TokenStream> {
fn on_ignored_field(&self, field: VariantField) -> TokenStream {
let bevy_reflect_path = self.reflect_enum.meta().bevy_reflect_path();
let variant_name = field.variant_name;
let alias = field.alias;

match &field.field.attrs.clone {
CloneBehavior::Default => None,
CloneBehavior::Trait => Some(quote! {
#FQClone::clone(#alias)
}),
CloneBehavior::Func(clone_fn) => Some(quote! { #clone_fn() }),
}
}
CloneBehavior::Default => {
let field_id = field.field.field_id(bevy_reflect_path);

fn build(&self, this: &Ident) -> Self::Output {
build(self, this)
quote! {
return #FQResult::Err(
#bevy_reflect_path::ReflectCloneError::FieldNotClonable {
field: #field_id,
variant: #FQOption::Some(::std::borrow::Cow::Borrowed(#variant_name)),
container_type_path: ::std::borrow::Cow::Borrowed(<Self as #bevy_reflect_path::TypePath>::type_path())
}
)
}
}
CloneBehavior::Trait => quote! { #FQClone::clone(#alias) },
CloneBehavior::Func(clone_fn) => quote! { #clone_fn() },
}
}
}
Loading

0 comments on commit ad1146e

Please sign in to comment.