Path: blob/main/crates/bevy_reflect/derive/src/impls/common.rs
9383 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>,85default_partial_ord_delegate: impl FnOnce() -> Option<proc_macro2::TokenStream>,86) -> proc_macro2::TokenStream {87let bevy_reflect_path = meta.bevy_reflect_path();8889let debug_fn = meta.attrs().get_debug_impl();90let partial_eq_fn = meta91.attrs()92.get_partial_eq_impl(bevy_reflect_path)93.or_else(move || {94let default_delegate = default_partial_eq_delegate();95default_delegate.map(|func| {96quote! {97fn reflect_partial_eq(&self, value: &dyn #bevy_reflect_path::PartialReflect) -> #FQOption<bool> {98(#func)(self, value)99}100}101})102});103let partial_ord_fn = meta104.attrs()105.get_partial_ord_impl(bevy_reflect_path)106.or_else(move || {107let default_delegate = default_partial_ord_delegate();108default_delegate.map(|func| {109quote! {110fn reflect_partial_cmp(&self, value: &dyn #bevy_reflect_path::PartialReflect) -> #FQOption<::core::cmp::Ordering> {111(#func)(self, value)112}113}114})115});116let hash_fn = meta117.attrs()118.get_hash_impl(bevy_reflect_path)119.or_else(move || {120let default_delegate = default_hash_delegate();121default_delegate.map(|func| {122quote! {123fn reflect_hash(&self) -> #FQOption<u64> {124(#func)(self)125}126}127})128});129130quote! {131#[inline]132fn try_into_reflect(133self: #bevy_reflect_path::__macro_exports::alloc_utils::Box<Self>134) -> #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>> {135#FQResult::Ok(self)136}137138#[inline]139fn try_as_reflect(&self) -> #FQOption<&dyn #bevy_reflect_path::Reflect> {140#FQOption::Some(self)141}142143#[inline]144fn try_as_reflect_mut(&mut self) -> #FQOption<&mut dyn #bevy_reflect_path::Reflect> {145#FQOption::Some(self)146}147148#[inline]149fn 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> {150self151}152153#[inline]154fn as_partial_reflect(&self) -> &dyn #bevy_reflect_path::PartialReflect {155self156}157158#[inline]159fn as_partial_reflect_mut(&mut self) -> &mut dyn #bevy_reflect_path::PartialReflect {160self161}162163#hash_fn164165#partial_eq_fn166167#partial_ord_fn168169#debug_fn170}171}172173#[cfg(feature = "auto_register")]174pub fn reflect_auto_registration(meta: &ReflectMeta) -> Option<proc_macro2::TokenStream> {175if meta.attrs().no_auto_register() {176return None;177}178179let bevy_reflect_path = meta.bevy_reflect_path();180let type_path = meta.type_path();181182if type_path.impl_is_generic() {183return None;184};185186#[cfg(feature = "auto_register_static")]187{188use std::{189env, fs,190io::Write,191path::PathBuf,192sync::{LazyLock, Mutex},193};194195// Skip unless env var is set, otherwise this might slow down rust-analyzer196if env::var("BEVY_REFLECT_AUTO_REGISTER_STATIC").is_err() {197return None;198}199200// Names of registrations functions will be stored in this file.201// To allow writing to this file from multiple threads during compilation it is protected by mutex.202// This static is valid for the duration of compilation of one crate and we have one file per crate,203// so it is enough to protect compilation threads from overwriting each other.204// This file is reset on every crate recompilation.205//206// It might make sense to replace the mutex with File::lock when file_lock feature becomes stable.207static REGISTRATION_FNS_EXPORT: LazyLock<Mutex<fs::File>> = LazyLock::new(|| {208let path = PathBuf::from("target").join("bevy_reflect_type_registrations");209fs::DirBuilder::new()210.recursive(true)211.create(&path)212.unwrap_or_else(|_| panic!("Failed to create {path:?}"));213let file_path = path.join(env::var("CARGO_CRATE_NAME").unwrap());214let file = fs::OpenOptions::new()215.create(true)216.write(true)217.truncate(true)218.open(&file_path)219.unwrap_or_else(|_| panic!("Failed to create {file_path:?}"));220Mutex::new(file)221});222223let export_name = format!("_bevy_reflect_register_{}", uuid::Uuid::new_v4().as_u128());224225{226let mut file = REGISTRATION_FNS_EXPORT.lock().unwrap();227writeln!(file, "{export_name}")228.unwrap_or_else(|_| panic!("Failed to write registration function {export_name}"));229// We must sync_data to ensure all content is written before releasing the lock.230file.sync_data().unwrap();231};232233Some(quote! {234/// # Safety235/// This function must only be used by the `load_type_registrations` macro.236#[unsafe(export_name=#export_name)]237pub unsafe extern "Rust" fn bevy_register_type(registry: &mut #bevy_reflect_path::TypeRegistry) {238<#type_path as #bevy_reflect_path::__macro_exports::RegisterForReflection>::__register(registry);239}240})241}242243#[cfg(all(244feature = "auto_register_inventory",245not(feature = "auto_register_static")246))]247{248Some(quote! {249#bevy_reflect_path::__macro_exports::auto_register::inventory::submit!{250#bevy_reflect_path::__macro_exports::auto_register::AutomaticReflectRegistrations(251<#type_path as #bevy_reflect_path::__macro_exports::auto_register::RegisterForReflection>::__register252)253}254})255}256}257258259