Path: blob/main/crates/bevy_reflect/derive/src/impls/common.rs
6600 views
use bevy_macro_utils::fq_std::{FQAny, FQOption, FQResult};12use quote::quote;34use crate::{derive_data::ReflectMeta, where_clause_options::WhereClauseOptions};56pub fn impl_full_reflect(where_clause_options: &WhereClauseOptions) -> proc_macro2::TokenStream {7let meta = where_clause_options.meta();8let bevy_reflect_path = meta.bevy_reflect_path();9let type_path = meta.type_path();1011let (impl_generics, ty_generics, where_clause) = type_path.generics().split_for_impl();12let where_reflect_clause = where_clause_options.extend_where_clause(where_clause);1314let any_impls = if meta.is_remote_wrapper() {15quote! {16#[inline]17fn into_any(self: #bevy_reflect_path::__macro_exports::alloc_utils::Box<Self>) -> #bevy_reflect_path::__macro_exports::alloc_utils::Box<dyn #FQAny> {18#bevy_reflect_path::__macro_exports::alloc_utils::Box::new(self.0)19}2021#[inline]22fn as_any(&self) -> &dyn #FQAny {23&self.024}2526#[inline]27fn as_any_mut(&mut self) -> &mut dyn #FQAny {28&mut self.029}30}31} else {32quote! {33#[inline]34fn into_any(self: #bevy_reflect_path::__macro_exports::alloc_utils::Box<Self>) -> #bevy_reflect_path::__macro_exports::alloc_utils::Box<dyn #FQAny> {35self36}3738#[inline]39fn as_any(&self) -> &dyn #FQAny {40self41}4243#[inline]44fn as_any_mut(&mut self) -> &mut dyn #FQAny {45self46}47}48};4950quote! {51impl #impl_generics #bevy_reflect_path::Reflect for #type_path #ty_generics #where_reflect_clause {52#any_impls5354#[inline]55fn into_reflect(self: #bevy_reflect_path::__macro_exports::alloc_utils::Box<Self>) -> #bevy_reflect_path::__macro_exports::alloc_utils::Box<dyn #bevy_reflect_path::Reflect> {56self57}5859#[inline]60fn as_reflect(&self) -> &dyn #bevy_reflect_path::Reflect {61self62}6364#[inline]65fn as_reflect_mut(&mut self) -> &mut dyn #bevy_reflect_path::Reflect {66self67}6869#[inline]70fn set(71&mut self,72value: #bevy_reflect_path::__macro_exports::alloc_utils::Box<dyn #bevy_reflect_path::Reflect>73) -> #FQResult<(), #bevy_reflect_path::__macro_exports::alloc_utils::Box<dyn #bevy_reflect_path::Reflect>> {74*self = <dyn #bevy_reflect_path::Reflect>::take(value)?;75#FQResult::Ok(())76}77}78}79}8081pub fn common_partial_reflect_methods(82meta: &ReflectMeta,83default_partial_eq_delegate: impl FnOnce() -> Option<proc_macro2::TokenStream>,84default_hash_delegate: impl FnOnce() -> Option<proc_macro2::TokenStream>,85) -> proc_macro2::TokenStream {86let bevy_reflect_path = meta.bevy_reflect_path();8788let debug_fn = meta.attrs().get_debug_impl();89let partial_eq_fn = meta90.attrs()91.get_partial_eq_impl(bevy_reflect_path)92.or_else(move || {93let default_delegate = default_partial_eq_delegate();94default_delegate.map(|func| {95quote! {96fn reflect_partial_eq(&self, value: &dyn #bevy_reflect_path::PartialReflect) -> #FQOption<bool> {97(#func)(self, value)98}99}100})101});102let hash_fn = meta103.attrs()104.get_hash_impl(bevy_reflect_path)105.or_else(move || {106let default_delegate = default_hash_delegate();107default_delegate.map(|func| {108quote! {109fn reflect_hash(&self) -> #FQOption<u64> {110(#func)(self)111}112}113})114});115116quote! {117#[inline]118fn try_into_reflect(119self: #bevy_reflect_path::__macro_exports::alloc_utils::Box<Self>120) -> #FQResult<#bevy_reflect_path::__macro_exports::alloc_utils::Box<dyn #bevy_reflect_path::Reflect>, #bevy_reflect_path::__macro_exports::alloc_utils::Box<dyn #bevy_reflect_path::PartialReflect>> {121#FQResult::Ok(self)122}123124#[inline]125fn try_as_reflect(&self) -> #FQOption<&dyn #bevy_reflect_path::Reflect> {126#FQOption::Some(self)127}128129#[inline]130fn try_as_reflect_mut(&mut self) -> #FQOption<&mut dyn #bevy_reflect_path::Reflect> {131#FQOption::Some(self)132}133134#[inline]135fn into_partial_reflect(self: #bevy_reflect_path::__macro_exports::alloc_utils::Box<Self>) -> #bevy_reflect_path::__macro_exports::alloc_utils::Box<dyn #bevy_reflect_path::PartialReflect> {136self137}138139#[inline]140fn as_partial_reflect(&self) -> &dyn #bevy_reflect_path::PartialReflect {141self142}143144#[inline]145fn as_partial_reflect_mut(&mut self) -> &mut dyn #bevy_reflect_path::PartialReflect {146self147}148149#hash_fn150151#partial_eq_fn152153#debug_fn154}155}156157#[cfg(feature = "auto_register")]158pub fn reflect_auto_registration(meta: &ReflectMeta) -> Option<proc_macro2::TokenStream> {159if meta.attrs().no_auto_register() {160return None;161}162163let bevy_reflect_path = meta.bevy_reflect_path();164let type_path = meta.type_path();165166if type_path.impl_is_generic() {167return None;168};169170#[cfg(feature = "auto_register_static")]171{172use std::{173env, fs,174io::Write,175path::PathBuf,176sync::{LazyLock, Mutex},177};178179// Skip unless env var is set, otherwise this might slow down rust-analyzer180if env::var("BEVY_REFLECT_AUTO_REGISTER_STATIC").is_err() {181return None;182}183184// Names of registrations functions will be stored in this file.185// To allow writing to this file from multiple threads during compilation it is protected by mutex.186// This static is valid for the duration of compilation of one crate and we have one file per crate,187// so it is enough to protect compilation threads from overwriting each other.188// This file is reset on every crate recompilation.189//190// It might make sense to replace the mutex with File::lock when file_lock feature becomes stable.191static REGISTRATION_FNS_EXPORT: LazyLock<Mutex<fs::File>> = LazyLock::new(|| {192let path = PathBuf::from("target").join("bevy_reflect_type_registrations");193fs::DirBuilder::new()194.recursive(true)195.create(&path)196.unwrap_or_else(|_| panic!("Failed to create {path:?}"));197let file_path = path.join(env::var("CARGO_CRATE_NAME").unwrap());198let file = fs::OpenOptions::new()199.create(true)200.write(true)201.truncate(true)202.open(&file_path)203.unwrap_or_else(|_| panic!("Failed to create {file_path:?}"));204Mutex::new(file)205});206207let export_name = format!("_bevy_reflect_register_{}", uuid::Uuid::new_v4().as_u128());208209{210let mut file = REGISTRATION_FNS_EXPORT.lock().unwrap();211writeln!(file, "{export_name}")212.unwrap_or_else(|_| panic!("Failed to write registration function {export_name}"));213// We must sync_data to ensure all content is written before releasing the lock.214file.sync_data().unwrap();215};216217Some(quote! {218/// # Safety219/// This function must only be used by the `load_type_registrations` macro.220#[unsafe(export_name=#export_name)]221pub unsafe extern "Rust" fn bevy_register_type(registry: &mut #bevy_reflect_path::TypeRegistry) {222<#type_path as #bevy_reflect_path::__macro_exports::RegisterForReflection>::__register(registry);223}224})225}226227#[cfg(all(228feature = "auto_register_inventory",229not(feature = "auto_register_static")230))]231{232Some(quote! {233#bevy_reflect_path::__macro_exports::auto_register::inventory::submit!{234#bevy_reflect_path::__macro_exports::auto_register::AutomaticReflectRegistrations(235<#type_path as #bevy_reflect_path::__macro_exports::auto_register::RegisterForReflection>::__register236)237}238})239}240}241242243