Skip to content

Commit 164f7d1

Browse files
committed
feat! add type cache table global, and refactor GetTypeDependencies to work better with nested types
1 parent 7ca94df commit 164f7d1

File tree

10 files changed

+163
-55
lines changed

10 files changed

+163
-55
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
2+
function on_test()
3+
local my_type = types.TestResource;
4+
assert(my_type ~= nil, "Type t.TestResource is not available");
5+
assert(my_type:short_name() == "TestResource", "Type t.TestResource:short_name() is not correct: " .. my_type:short_name());
6+
end

crates/bevy_mod_scripting_core/src/bindings/function/arg_meta.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::{ffi::OsString, path::PathBuf};
44

55
use crate::{
66
bindings::{script_value::ScriptValue, ReflectReference},
7-
docgen::typed_through::TypedThrough,
7+
docgen::typed_through::TypedThrough, error::InteropError,
88
};
99

1010
use super::{
@@ -77,6 +77,8 @@ impl<T> ArgMeta for Val<T> {}
7777
impl<T> ArgMeta for Ref<'_, T> {}
7878
impl<T> ArgMeta for Mut<'_, T> {}
7979

80+
impl<T> ArgMeta for Result<T, InteropError> {}
81+
8082
impl<T> ArgMeta for Option<T> {
8183
fn default_value() -> Option<ScriptValue> {
8284
Some(ScriptValue::Unit)

crates/bevy_mod_scripting_core/src/bindings/function/from.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,17 @@ where
469469
pub struct Union<T1, T2>(Result<T1, T2>);
470470

471471
impl<T1, T2> Union<T1, T2> {
472+
/// Create a new union with the left value.
473+
pub fn new_left(value: T1) -> Self {
474+
Union(Ok(value))
475+
}
476+
477+
/// Create a new union with the right value.
478+
pub fn new_right(value: T2) -> Self {
479+
Union(Err(value))
480+
}
481+
482+
472483
/// Try interpret the union as the left type
473484
pub fn into_left(self) -> Result<T1, T2> {
474485
match self.0 {
@@ -484,6 +495,14 @@ impl<T1, T2> Union<T1, T2> {
484495
Ok(l) => Err(l),
485496
}
486497
}
498+
499+
/// Map the union to another type
500+
pub fn map_both<U1, U2, F: Fn(T1) -> U1, G: Fn(T2) -> U2>(self, f: F, g: G) -> Union<U1, U2> {
501+
match self.0 {
502+
Ok(t) => Union(Ok(f(t))),
503+
Err(t) => Union(Err(g(t))),
504+
}
505+
}
487506
}
488507

489508
impl<T1: FromScript, T2: FromScript> FromScript for Union<T1, T2>

crates/bevy_mod_scripting_core/src/bindings/function/into.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::{
1111
};
1212

1313
use super::{
14-
from::Val,
14+
from::{Union, Val},
1515
script_function::{DynamicScriptFunction, DynamicScriptFunctionMut},
1616
};
1717

@@ -165,6 +165,15 @@ impl<T: IntoScript, const N: usize> IntoScript for [T; N] {
165165
}
166166
}
167167

168+
impl <T1: IntoScript, T2: IntoScript> IntoScript for Union<T1,T2> {
169+
fn into_script(self, world: WorldGuard) -> Result<ScriptValue, InteropError> {
170+
match self.into_left() {
171+
Ok(left) => left.into_script(world),
172+
Err(right) => right.into_script(world),
173+
}
174+
}
175+
}
176+
168177
impl<V: IntoScript> IntoScript for HashMap<String, V> {
169178
fn into_script(self, world: WorldGuard) -> Result<ScriptValue, InteropError> {
170179
let mut map = HashMap::new();

crates/bevy_mod_scripting_core/src/bindings/function/mod.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,7 @@ mod test {
2121
from::{Ref, Union, Val},
2222
namespace::IntoNamespace,
2323
script_function::AppScriptFunctionRegistry,
24-
},
25-
script_value::ScriptValue,
24+
}, script_value::ScriptValue
2625
},
2726
docgen::typed_through::TypedThrough,
2827
};
@@ -135,6 +134,16 @@ mod test {
135134
test_is_valid_arg::<Ref<'_, T>>();
136135
}
137136

137+
fn test_union<T>()
138+
where
139+
T: TypedScriptArgument + TypedScriptReturn,
140+
T: GetTypeRegistration,
141+
for<'a> T::This<'a>: Into<T>,
142+
{
143+
test_is_valid_arg_and_return::<Union<T, T>>();
144+
test_is_valid_arg_and_return::<Union<T, Union<T, T>>>();
145+
}
146+
138147
fn test_array<T, const N: usize>()
139148
where
140149
T: ScriptArgument + ScriptReturn,

crates/bevy_mod_scripting_core/src/bindings/function/type_dependencies.rs

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ use crate::{
1010
};
1111
use bevy::reflect::{FromReflect, GetTypeRegistration, TypeRegistry, Typed};
1212
use std::collections::HashMap;
13-
use std::hash::Hash;
1413

1514
/// Functionally identical to [`GetTypeRegistration`] but without the 'static bound
1615
pub trait GetTypeDependencies {
@@ -81,13 +80,40 @@ recursive_type_dependencies!(
8180
(Val<T> where T: GetTypeRegistration),
8281
(Ref<'_, T> where T: GetTypeRegistration),
8382
(Mut<'_, T> where T: GetTypeRegistration),
84-
(Result<T, InteropError> where T: GetTypeRegistration),
83+
// (Result<T, InteropError> where T: GetTypeRegistration),
8584
([T; N] where T: GetTypeRegistration;Typed,, const N: usize => with Self),
86-
(Option<T> where T: GetTypeRegistration;FromReflect;Typed => with Self),
87-
(Vec<T> where T: GetTypeRegistration;FromReflect;Typed => with Self),
88-
(HashMap<K,V> where K: GetTypeRegistration;FromReflect;Typed;Hash;Eq, V: GetTypeRegistration;FromReflect;Typed => with Self)
85+
// (Option<T> where T: GetTypeRegistration;FromReflect;Typed => with Self),
86+
(Vec<T> where T: GetTypeRegistration;FromReflect;Typed => with Self)
87+
// (HashMap<K,V> where K: GetTypeRegistration;FromReflect;Typed;Hash;Eq, V: GetTypeRegistration;FromReflect;Typed => with Self)
8988
);
9089

90+
91+
impl <K> GetTypeDependencies for Option<K>
92+
where
93+
K: GetTypeDependencies
94+
{
95+
fn register_type_dependencies(registry: &mut TypeRegistry) {
96+
K::register_type_dependencies(registry);
97+
}
98+
}
99+
100+
impl <K, V> GetTypeDependencies for HashMap<K, V>
101+
where
102+
K: GetTypeDependencies,
103+
V: GetTypeDependencies
104+
{
105+
fn register_type_dependencies(registry: &mut TypeRegistry) {
106+
K::register_type_dependencies(registry);
107+
V::register_type_dependencies(registry);
108+
}
109+
}
110+
111+
impl <T: GetTypeDependencies> GetTypeDependencies for Result<T, InteropError> {
112+
fn register_type_dependencies(registry: &mut TypeRegistry) {
113+
T::register_type_dependencies(registry);
114+
}
115+
}
116+
91117
impl<T1: GetTypeDependencies, T2: GetTypeDependencies> GetTypeDependencies for Union<T1, T2> {
92118
fn register_type_dependencies(registry: &mut TypeRegistry) {
93119
T1::register_type_dependencies(registry);

crates/bevy_mod_scripting_core/src/bindings/globals/core.rs

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
//! Core globals exposed by the BMS framework
22
3+
use std::{collections::HashMap, sync::Arc};
4+
35
use bevy::{app::Plugin, ecs::reflect::AppTypeRegistry};
6+
use bevy_mod_scripting_derive::script_globals;
7+
8+
use crate::{bindings::{function::from::{Union, Val}, ScriptComponentRegistration, ScriptResourceRegistration, ScriptTypeRegistration, WorldGuard}, error::InteropError};
49

510
use super::AppScriptGlobalsRegistry;
611

@@ -10,12 +15,16 @@ pub struct CoreScriptGlobalsPlugin;
1015
impl Plugin for CoreScriptGlobalsPlugin {
1116
fn build(&self, _app: &mut bevy::app::App) {}
1217
fn finish(&self, app: &mut bevy::app::App) {
13-
let global_registry = app
14-
.world_mut()
18+
register_static_core_globals(app.world_mut());
19+
register_core_globals(app.world_mut());
20+
}
21+
}
22+
23+
fn register_static_core_globals(world: &mut bevy::ecs::world::World) {
24+
let global_registry = world
1525
.get_resource_or_init::<AppScriptGlobalsRegistry>()
1626
.clone();
17-
let type_registry = app
18-
.world_mut()
27+
let type_registry = world
1928
.get_resource_or_init::<AppTypeRegistry>()
2029
.clone();
2130
let mut global_registry = global_registry.write();
@@ -34,8 +43,32 @@ impl Plugin for CoreScriptGlobalsPlugin {
3443
None,
3544
global_name.into(),
3645
documentation.into(),
37-
)
46+
);
3847
}
3948
}
40-
}
4149
}
50+
51+
#[script_globals(
52+
bms_core_path = "crate",
53+
name = "core_globals",
54+
)]
55+
impl CoreGlobals {
56+
/// A cache of types normally available through the `world.get_type_by_name` function.
57+
///
58+
/// You can use this to avoid having to store type references.
59+
fn types(guard: WorldGuard) -> Result<HashMap<String, Union<Val<ScriptTypeRegistration>, Union<Val<ScriptComponentRegistration>, Val<ScriptResourceRegistration>>>>, InteropError> {
60+
let type_registry = guard.type_registry();
61+
let type_registry = type_registry.read();
62+
let mut type_cache = HashMap::<String, _>::default();
63+
for registration in type_registry.iter(){
64+
if let Some(ident) = registration.type_info().type_path_table().ident() {
65+
let registration = ScriptTypeRegistration::new(Arc::new(registration.clone()));
66+
let registration = guard.clone().get_type_registration(registration)?;
67+
let registration = registration.map_both(Val::from, |u| u.map_both(Val::from, Val::from));
68+
type_cache.insert(ident.to_string(), registration);
69+
}
70+
}
71+
72+
Ok(type_cache)
73+
}
74+
}

crates/bevy_mod_scripting_core/src/bindings/globals/mod.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -98,11 +98,11 @@ impl ScriptGlobalsRegistry {
9898
F: Fn(WorldGuard) -> Result<T, InteropError> + 'static + Send + Sync,
9999
>(
100100
&mut self,
101-
name: Cow<'static, str>,
101+
name: impl Into<Cow<'static, str>>,
102102
maker: F,
103103
) -> Option<ScriptGlobal> {
104104
self.globals.insert(
105-
name,
105+
name.into(),
106106
ScriptGlobal {
107107
maker: Some(Self::type_erase_maker(maker)),
108108
documentation: None,
@@ -120,15 +120,15 @@ impl ScriptGlobalsRegistry {
120120
F: Fn(WorldGuard) -> Result<T, InteropError> + 'static + Send + Sync,
121121
>(
122122
&mut self,
123-
name: Cow<'static, str>,
123+
name: impl Into<Cow<'static, str>>,
124124
maker: F,
125-
documentation: Cow<'static, str>,
125+
documentation: impl Into<Cow<'static, str>>,
126126
) -> Option<ScriptGlobal> {
127127
self.globals.insert(
128-
name,
128+
name.into(),
129129
ScriptGlobal {
130130
maker: Some(Self::type_erase_maker(maker)),
131-
documentation: Some(documentation),
131+
documentation: Some(documentation.into()),
132132
type_id: TypeId::of::<T>(),
133133
type_information: Some(T::through_type_info()),
134134
},

crates/bevy_mod_scripting_core/src/bindings/world.rs

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@ use super::{
1111
ReflectAccessKind, SubsetAccessMap,
1212
},
1313
function::{
14-
namespace::Namespace,
15-
script_function::{AppScriptFunctionRegistry, DynamicScriptFunction, FunctionCallContext},
14+
from::Union, namespace::Namespace, script_function::{AppScriptFunctionRegistry, DynamicScriptFunction, FunctionCallContext}
1615
},
1716
pretty_print::DisplayWithWorld,
1817
schedule::AppScheduleRegistry,
@@ -549,6 +548,7 @@ impl<'w> WorldAccessGuard<'w> {
549548
/// Impl block for higher level world methods
550549
#[profiling::all_functions]
551550
impl WorldAccessGuard<'_> {
551+
552552
fn construct_from_script_value(
553553
&self,
554554
descriptor: impl Into<Cow<'static, str>>,
@@ -807,7 +807,7 @@ impl WorldAccessGuard<'_> {
807807
})
808808
}
809809

810-
/// get a type registration for the type
810+
/// get a type registration for the type, without checking if it's a component or resource
811811
pub fn get_type_by_name(&self, type_name: String) -> Option<ScriptTypeRegistration> {
812812
let type_registry = self.type_registry();
813813
let type_registry = type_registry.read();
@@ -817,6 +817,38 @@ impl WorldAccessGuard<'_> {
817817
.map(|registration| ScriptTypeRegistration::new(Arc::new(registration.clone())))
818818
}
819819

820+
/// get a type erased type registration for the type including information about whether it's a component or resource
821+
pub(crate) fn get_type_registration(&self, registration: ScriptTypeRegistration) -> Result<Union<ScriptTypeRegistration, Union<ScriptComponentRegistration, ScriptResourceRegistration>>, InteropError> {
822+
823+
let registration = match self.get_resource_type(registration)? {
824+
Ok(res) => {
825+
return Ok(Union::new_right(Union::new_right(res)));
826+
}
827+
Err(registration) => registration,
828+
};
829+
830+
let registration = match self.get_component_type(registration)? {
831+
Ok(comp) => {
832+
return Ok(Union::new_right(Union::new_left(comp)));
833+
}
834+
Err(registration) => registration,
835+
};
836+
837+
Ok(Union::new_left(registration))
838+
}
839+
840+
/// Similar to [`Self::get_type_by_name`] but returns a type erased [`ScriptTypeRegistration`], [`ScriptComponentRegistration`] or [`ScriptResourceRegistration`]
841+
/// depending on the underlying type and state of the world.
842+
pub fn get_type_registration_by_name(&self, type_name: String) -> Result<Option<Union<ScriptTypeRegistration, Union<ScriptComponentRegistration, ScriptResourceRegistration>>>, InteropError> {
843+
let val = self.get_type_by_name(type_name);
844+
Ok(match val {
845+
Some(registration) => {
846+
Some(self.get_type_registration(registration)?)
847+
}
848+
None => None,
849+
})
850+
}
851+
820852
/// get a schedule by name
821853
pub fn get_schedule_by_name(&self, schedule_name: String) -> Option<ReflectSchedule> {
822854
let schedule_registry = self.schedule_registry();

crates/bevy_mod_scripting_functions/src/core.rs

Lines changed: 3 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ use bindings::{
3030
};
3131
use error::InteropError;
3232
use reflection_extensions::{PartialReflectExt, TypeIdExtensions};
33+
3334
pub fn register_bevy_bindings(app: &mut App) {
3435
#[cfg(feature = "bevy_bindings")]
3536
app.add_plugins(crate::bevy_bindings::LuaBevyScriptingPlugin);
@@ -45,39 +46,10 @@ impl World {
4546
fn get_type_by_name(
4647
ctxt: FunctionCallContext,
4748
type_name: String,
48-
) -> Result<Option<ReflectReference>, InteropError> {
49+
) -> Result<Option<Union<Val<ScriptTypeRegistration>, Union<Val<ScriptComponentRegistration>, Val<ScriptResourceRegistration>>>>, InteropError> {
4950
profiling::function_scope!("get_type_by_name");
5051
let world = ctxt.world()?;
51-
let val = world.get_type_by_name(type_name);
52-
53-
Ok(match val {
54-
Some(registration) => {
55-
let allocator = world.allocator();
56-
57-
let registration = match world.get_resource_type(registration)? {
58-
Ok(res) => {
59-
let mut allocator = allocator.write();
60-
return Ok(Some(ReflectReference::new_allocated(res, &mut allocator)));
61-
}
62-
Err(registration) => registration,
63-
};
64-
65-
let registration = match world.get_component_type(registration)? {
66-
Ok(comp) => {
67-
let mut allocator = allocator.write();
68-
return Ok(Some(ReflectReference::new_allocated(comp, &mut allocator)));
69-
}
70-
Err(registration) => registration,
71-
};
72-
73-
let mut allocator = allocator.write();
74-
Some(ReflectReference::new_allocated(
75-
registration,
76-
&mut allocator,
77-
))
78-
}
79-
None => None,
80-
})
52+
world.get_type_registration_by_name(type_name).map(|v| v.map(|v| v.map_both(Val::from, |u| u.map_both(Val::from, Val::from))))
8153
}
8254

8355
/// Retrieves the schedule with the given name, Also ensures the schedule is initialized before returning it.

0 commit comments

Comments
 (0)