use crate::{
DummyScriptFunctionRegistry, ScriptFunctionRegistryArc,
docgen::info::GetFunctionInfo,
function::script_function::{AppScriptFunctionRegistry, ScriptFunction},
};
use ::bevy_reflect::{GetTypeRegistration, Reflect};
use bevy_ecs::{reflect::AppTypeRegistry, world::World};
use bevy_mod_scripting_derive::DebugWithTypeInfo;
use bevy_mod_scripting_display::{DisplayWithTypeInfo, GetTypeInfo, WithTypeInfo};
use std::{any::TypeId, borrow::Cow, marker::PhantomData};
use super::type_dependencies::GetFunctionTypeDependencies;
#[derive(Clone, Copy, PartialEq, Eq, Hash, Default, Reflect, DebugWithTypeInfo)]
#[debug_with_type_info(bms_display_path = "bevy_mod_scripting_display")]
pub enum Namespace {
#[default]
Global,
OnType(TypeId),
}
pub struct GlobalNamespace;
pub trait IntoNamespace {
fn into_namespace() -> Namespace;
}
impl<T: ?Sized + 'static> IntoNamespace for T {
fn into_namespace() -> Namespace {
if TypeId::of::<T>() == TypeId::of::<GlobalNamespace>() {
Namespace::Global
} else {
Namespace::OnType(TypeId::of::<T>())
}
}
}
#[profiling::all_functions]
impl Namespace {
pub fn prefix(self) -> Cow<'static, str> {
match self {
Namespace::Global => Cow::Borrowed(""),
Namespace::OnType(type_id) => Cow::Owned(format!("{type_id:?}::")),
}
}
pub fn function_name<I: Into<Cow<'static, str>>>(self, name: I) -> Cow<'static, str> {
match self {
Namespace::Global => name.into(),
Namespace::OnType(type_id) => Cow::Owned(format!("{:?}::{}", type_id, name.into())),
}
}
}
pub struct NamespaceBuilder<'a, N> {
registry: ScriptFunctionRegistryArc,
namespace: PhantomData<N>,
pub world: &'a mut World,
}
#[profiling::all_functions]
impl<'a, S: IntoNamespace> NamespaceBuilder<'a, S> {
pub fn new(world: &'a mut World) -> Self
where
S: GetTypeRegistration,
{
{
let registry = world.get_resource_or_init::<AppTypeRegistry>();
let mut registry = registry.write();
registry.register::<S>();
}
Self {
registry: world
.get_resource_or_init::<AppScriptFunctionRegistry>()
.0
.clone(),
namespace: Default::default(),
world,
}
}
pub fn new_unregistered(world: &'a mut World) -> Self {
Self {
registry: world
.get_resource_or_init::<AppScriptFunctionRegistry>()
.0
.clone(),
namespace: Default::default(),
world,
}
}
pub fn with_dummy_registry(mut self) -> Self {
self.registry = self
.world
.get_resource_or_init::<DummyScriptFunctionRegistry>()
.0
.clone();
self
}
pub fn register<'env, N, F, M>(&mut self, name: N, function: F) -> &mut Self
where
N: Into<Cow<'static, str>>,
F: ScriptFunction<'env, M> + GetFunctionTypeDependencies<M> + GetFunctionInfo<M>,
{
self.register_inner(name, function, None, None)
}
pub fn register_documented<'env, N, F, M>(
&mut self,
name: N,
function: F,
docstring: &'static str,
arg_names: &'static [&'static str],
) -> &mut Self
where
N: Into<Cow<'static, str>>,
F: ScriptFunction<'env, M> + GetFunctionTypeDependencies<M> + GetFunctionInfo<M>,
{
self.register_inner(name, function, Some(docstring), Some(arg_names))
}
fn register_inner<'env, N, F, M>(
&mut self,
name: N,
function: F,
docstring: Option<&'static str>,
arg_names: Option<&'static [&'static str]>,
) -> &mut Self
where
N: Into<Cow<'static, str>>,
F: ScriptFunction<'env, M> + GetFunctionTypeDependencies<M> + GetFunctionInfo<M>,
{
{
{
let mut registry = self.registry.write();
registry.register_with_arg_names(
S::into_namespace(),
name,
function,
docstring.unwrap_or_default(),
arg_names.unwrap_or(&[]),
);
}
{
let type_registry = self.world.get_resource_or_init::<AppTypeRegistry>();
let mut type_registry = type_registry.write();
F::register_type_dependencies(&mut type_registry);
}
}
self
}
}
impl From<TypeId> for Namespace {
fn from(value: TypeId) -> Self {
Namespace::OnType(value)
}
}
impl DisplayWithTypeInfo for Namespace {
fn display_with_type_info(
&self,
f: &mut std::fmt::Formatter<'_>,
type_info_provider: Option<&dyn GetTypeInfo>,
) -> std::fmt::Result {
match self {
Namespace::Global => f.write_str("Global Namespace"),
Namespace::OnType(type_id) => {
write!(
f,
"Namespace for type {}",
WithTypeInfo::new_with_opt_info(type_id, type_info_provider)
)
}
}
}
}