use std::collections::HashMap;
use cargo_metadata::camino::Utf8PathBuf;
use indexmap::IndexMap;
use log::debug;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::{AdtDef, TyCtxt};
use serde::Serialize;
use crate::{ImportPathFinder, MetaLoader, TemplateContext};
pub(crate) struct BevyCtxt<'tcx> {
pub(crate) tcx: TyCtxt<'tcx>,
pub(crate) meta_loader: MetaLoader,
pub(crate) reflect_types: IndexMap<DefId, ReflectType<'tcx>>,
pub(crate) cached_traits: CachedTraits,
pub(crate) path_finder: ImportPathFinder<'tcx>,
pub(crate) template_context: Option<TemplateContext>,
}
impl<'tcx> BevyCtxt<'tcx> {
pub(crate) fn new(
tcx: TyCtxt<'tcx>,
meta_dirs: &[Utf8PathBuf],
workspace_meta: crate::WorkspaceMeta,
include_private_paths: bool,
import_path_processor: Option<Box<dyn Fn(&str) -> String>>,
) -> Self {
Self {
tcx,
reflect_types: Default::default(),
cached_traits: Default::default(),
meta_loader: MetaLoader::new(meta_dirs.to_vec(), workspace_meta),
template_context: Default::default(),
path_finder: ImportPathFinder::new(tcx, include_private_paths, import_path_processor),
}
}
pub(crate) fn clear(&mut self) {
debug!("Clearing all context");
*self = Self::new(
self.tcx,
Default::default(),
Default::default(),
Default::default(),
Default::default(),
);
}
}
#[derive(Clone, Default, Debug)]
pub(crate) struct ReflectType<'tcx> {
pub(crate) trait_impls: Option<HashMap<DefId, Vec<DefId>>>,
pub(crate) variant_data: Option<AdtDef<'tcx>>,
pub(crate) valid_functions: Option<Vec<FunctionContext>>,
field_reflection_types: IndexMap<DefId, ReflectionStrategy>,
}
impl ReflectType<'_> {
pub(crate) fn set_field_reflection_strategies<
I: Iterator<Item = (DefId, ReflectionStrategy)>,
>(
&mut self,
field_strats: I,
) {
self.field_reflection_types = field_strats.collect();
}
pub(crate) fn get_field_reflection_strat(&self, field: DefId) -> Option<&ReflectionStrategy> {
self.field_reflection_types.get(&field)
}
}
pub(crate) const DEF_PATHS_FROM_LUA: [&str; 2] = ["value::FromLuaMulti", "mlua::FromLuaMulti"];
pub(crate) const DEF_PATHS_INTO_LUA: [&str; 2] = ["value::IntoLuaMulti", "mlua::IntoLuaMulti"];
pub(crate) const DEF_PATHS_REFLECT: [&str; 2] = ["bevy_reflect::Reflect", "reflect::Reflect"];
pub(crate) const DEF_PATHS_GET_TYPE_REGISTRATION: [&str; 2] = [
"bevy_reflect::GetTypeRegistration",
"reflect::GetTypeRegistration",
];
pub(crate) const STD_SOURCE_TRAITS: [&str; 14] = [
"std::fmt::Debug",
"std::fmt::Display",
"std::string::ToString",
"std::clone::Clone",
"std::ops::Neg",
"std::ops::Mul",
"std::ops::Add",
"std::ops::Sub",
"std::ops::Div",
"std::ops::Rem",
"std::cmp::Eq",
"std::cmp::PartialEq",
"std::cmp::Ord", "std::cmp::PartialOrd",
];
#[derive(Default)]
pub(crate) struct CachedTraits {
pub(crate) mlua_from_lua_multi: Option<DefId>,
pub(crate) mlua_into_lua_multi: Option<DefId>,
pub(crate) bevy_reflect_reflect: Option<DefId>,
pub(crate) bevy_reflect_get_type_registration: Option<DefId>,
pub(crate) std_source_traits: HashMap<String, DefId>,
}
impl CachedTraits {
pub(crate) fn has_all_mlua_traits(&self) -> bool {
self.mlua_from_lua_multi.is_some() && self.mlua_into_lua_multi.is_some()
}
pub(crate) fn has_all_bevy_traits(&self) -> bool {
self.bevy_reflect_reflect.is_some() && self.bevy_reflect_get_type_registration.is_some()
}
pub(crate) fn has_all_std_source_traits(&self) -> bool {
STD_SOURCE_TRAITS
.iter()
.all(|t| self.std_source_traits.contains_key(*t))
}
pub(crate) fn missing_std_source_traits(&self) -> Vec<String> {
STD_SOURCE_TRAITS
.iter()
.filter(|t| !self.std_source_traits.contains_key(**t))
.map(|s| (*s).to_owned())
.collect()
}
}
#[derive(Clone, Debug)]
pub(crate) struct FunctionContext {
pub(crate) def_id: DefId,
pub(crate) has_self: bool,
pub(crate) is_unsafe: bool,
pub(crate) trait_did: Option<DefId>,
pub(crate) reflection_strategies: Vec<ReflectionStrategy>,
}
#[derive(PartialEq, Eq, Clone, Copy, Serialize, Debug)]
pub(crate) enum ReflectionStrategy {
Proxy,
Primitive,
Reflection,
Filtered,
}