Skip to content

Commit 68ba256

Browse files
committed
implement the rest of reflect reference functions
1 parent c211f87 commit 68ba256

File tree

13 files changed

+191
-112
lines changed

13 files changed

+191
-112
lines changed

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ impl CallScriptFunction for DynamicFunction<'_> {
4646
) -> Result<ScriptValue, InteropError> {
4747
let args = args.into_iter();
4848

49-
let add_context = self.has_caller_context_arg();
49+
let add_context = self.is_script_function();
5050
let mut args_list = ArgList::new();
5151

5252
if add_context {
@@ -79,13 +79,14 @@ impl CallScriptFunction for DynamicFunction<'_> {
7979
}
8080

8181
pub trait DynamicFunctionExt {
82-
fn has_caller_context_arg(&self) -> bool;
82+
fn is_script_function(&self) -> bool;
8383
}
8484

8585
impl DynamicFunctionExt for DynamicFunction<'_> {
86-
fn has_caller_context_arg(&self) -> bool {
86+
fn is_script_function(&self) -> bool {
8787
self.info().args().first().map_or(false, |arg| {
8888
arg.type_id() == std::any::TypeId::of::<CallerContext>()
89+
|| arg.type_id() == std::any::TypeId::of::<WorldCallbackAccess>()
8990
})
9091
}
9192
}

crates/bevy_mod_scripting_core/src/error.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -649,7 +649,7 @@ impl DisplayWithWorld for InteropErrorInner {
649649
)
650650
},
651651
InteropErrorInner::FunctionCallError { inner } => {
652-
inner.to_string()
652+
format!("Error in function call: {}", inner)
653653
},
654654
InteropErrorInner::BetterConversionExists{ context } => {
655655
format!("Unfinished conversion in context of: {}. A better conversion exists but caller didn't handle the case.", context)

crates/bevy_mod_scripting_core/src/reflection_extensions.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::{
33
borrow::Cow,
44
cmp::max,
55
ffi::{CStr, CString, OsStr, OsString},
6+
ops::Sub,
67
path::{Path, PathBuf},
78
str::FromStr,
89
};
@@ -22,6 +23,13 @@ use crate::{
2223
};
2324
/// Extension trait for [`PartialReflect`] providing additional functionality for working with specific types.
2425
pub trait PartialReflectExt {
26+
fn try_remove_boxed(
27+
&mut self,
28+
key: Box<dyn PartialReflect>,
29+
) -> Result<Option<Box<dyn PartialReflect>>, InteropError>;
30+
31+
fn convert_to_0_indexed_key(&mut self);
32+
2533
fn from_reflect_or_clone(
2634
reflect: &dyn PartialReflect,
2735
world: WorldGuard,
@@ -276,6 +284,19 @@ impl<T: PartialReflect + ?Sized> PartialReflectExt for T {
276284
}
277285
}
278286

287+
fn convert_to_0_indexed_key(&mut self) {
288+
if let Some(type_id) = self.get_represented_type_info().map(|ti| ti.type_id()) {
289+
if type_id == TypeId::of::<usize>() {
290+
let self_ = self
291+
.as_partial_reflect_mut()
292+
.try_downcast_mut::<usize>()
293+
.expect("invariant");
294+
295+
*self_ = self_.saturating_sub(1);
296+
}
297+
}
298+
}
299+
279300
fn try_clear(&mut self) -> Result<(), InteropError> {
280301
match self.reflect_mut() {
281302
bevy::reflect::ReflectMut::List(l) => {
@@ -315,6 +336,25 @@ impl<T: PartialReflect + ?Sized> PartialReflectExt for T {
315336
}
316337
}
317338

339+
fn try_remove_boxed(
340+
&mut self,
341+
key: Box<dyn PartialReflect>,
342+
) -> Result<Option<Box<dyn PartialReflect>>, InteropError> {
343+
match self.reflect_mut() {
344+
bevy::reflect::ReflectMut::List(l) => Ok(Some(l.remove(key.as_usize()?))),
345+
bevy::reflect::ReflectMut::Map(m) => Ok(m.remove(key.as_partial_reflect())),
346+
bevy::reflect::ReflectMut::Set(s) => {
347+
let removed = s.remove(key.as_partial_reflect());
348+
Ok(removed.then_some(key))
349+
}
350+
_ => Err(InteropError::unsupported_operation(
351+
self.get_represented_type_info().map(|ti| ti.type_id()),
352+
Some(key),
353+
"remove".to_owned(),
354+
)),
355+
}
356+
}
357+
318358
fn element_type_id(&self) -> Option<TypeId> {
319359
let elem: TypeId = match self.get_represented_type_info()? {
320360
bevy::reflect::TypeInfo::List(list_info) => list_info.item_ty().id(),

crates/bevy_mod_scripting_functions/src/core.rs

Lines changed: 92 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use bindings::{
2222
ScriptTypeRegistration, WorldAccessGuard, WorldCallbackAccess,
2323
};
2424
use error::InteropError;
25-
use reflection_extensions::TypeIdExtensions;
25+
use reflection_extensions::{PartialReflectExt, TypeIdExtensions};
2626

2727
use crate::{bevy_bindings::LuaBevyScriptingPlugin, namespaced_register::NamespaceBuilder};
2828

@@ -55,7 +55,7 @@ pub fn register_bevy_bindings(app: &mut App) {
5555
}
5656

5757
pub fn register_world_functions(reg: &mut World) -> Result<(), FunctionRegistrationError> {
58-
NamespaceBuilder::<WorldCallbackAccess>::new(reg)
58+
NamespaceBuilder::<World>::new(reg)
5959
.overwrite_script_function("spawn", |s: WorldCallbackAccess| Ok(Val(s.spawn()?)))
6060
.overwrite_script_function(
6161
"get_type_by_name",
@@ -234,7 +234,96 @@ pub fn register_reflect_reference_functions(
234234
}
235235
ScriptValue::Unit
236236
},
237-
);
237+
)
238+
.overwrite_script_function(
239+
"push",
240+
|w: WorldCallbackAccess, s: ReflectReference, v: ScriptValue| {
241+
let world = w.try_read().expect("stale world");
242+
let target_type_id = s.element_type_id(world.clone())?.ok_or_else(|| {
243+
InteropError::unsupported_operation(
244+
s.tail_type_id(world.clone()).unwrap_or_default(),
245+
Some(Box::new(v.clone())),
246+
"Could not get element type id. Are you trying to insert elements into a type that's not a list?".to_owned(),
247+
)
248+
})?;
249+
let other = <Box<dyn PartialReflect>>::from_script_ref(target_type_id, v, world.clone())?;
250+
s.with_reflect_mut(world, |s| s.try_push_boxed(other))?
251+
},
252+
)
253+
.overwrite_script_function("pop", |w: WorldCallbackAccess, s: ReflectReference| {
254+
let world = w.try_read().expect("stale world");
255+
let o = s.with_reflect_mut(world.clone(), |s| s.try_pop_boxed())??;
256+
let reference = {
257+
let allocator = world.allocator();
258+
let mut allocator = allocator.write();
259+
ReflectReference::new_allocated_boxed(o, &mut allocator)
260+
};
261+
262+
ReflectReference::into_script_ref(reference, world)
263+
})
264+
.overwrite_script_function("insert", |caller_context: CallerContext, w: WorldCallbackAccess, s: ReflectReference, k: ScriptValue, v: ScriptValue| {
265+
let world = w.try_read().expect("stale world");
266+
let key_type_id = s.key_type_id(world.clone())?.ok_or_else(|| {
267+
InteropError::unsupported_operation(
268+
s.tail_type_id(world.clone()).unwrap_or_default(),
269+
Some(Box::new(k.clone())),
270+
"Could not get key type id. Are you trying to insert elements into a type that's not a map?".to_owned(),
271+
)
272+
})?;
273+
274+
let mut key = <Box<dyn PartialReflect>>::from_script_ref(key_type_id, k, world.clone())?;
275+
276+
if caller_context.convert_to_0_indexed {
277+
key.convert_to_0_indexed_key();
278+
}
279+
280+
let value_type_id = s.element_type_id(world.clone())?.ok_or_else(|| {
281+
InteropError::unsupported_operation(
282+
s.tail_type_id(world.clone()).unwrap_or_default(),
283+
Some(Box::new(v.clone())),
284+
"Could not get element type id. Are you trying to insert elements into a type that's not a map?".to_owned(),
285+
)
286+
})?;
287+
288+
let value = <Box<dyn PartialReflect>>::from_script_ref(value_type_id, v, world.clone())?;
289+
290+
s.with_reflect_mut(world, |s| s.try_insert_boxed(key, value))?
291+
})
292+
.overwrite_script_function("clear", |w: WorldCallbackAccess, s: ReflectReference| {
293+
let world = w.try_read().expect("stale world");
294+
s.with_reflect_mut(world, |s| s.try_clear())?
295+
})
296+
.overwrite_script_function("len", |w: WorldCallbackAccess, s: ReflectReference| {
297+
let world = w.try_read().expect("stale world");
298+
s.len(world)
299+
})
300+
.overwrite_script_function("remove", |caller_context: CallerContext, w: WorldCallbackAccess, s: ReflectReference, k: ScriptValue| {
301+
let world = w.try_read().expect("stale world");
302+
let key_type_id = s.key_type_id(world.clone())?.ok_or_else(|| {
303+
InteropError::unsupported_operation(
304+
s.tail_type_id(world.clone()).unwrap_or_default(),
305+
Some(Box::new(k.clone())),
306+
"Could not get key type id. Are you trying to remove elements from a type that's not a map?".to_owned(),
307+
)
308+
})?;
309+
310+
let mut key = <Box<dyn PartialReflect>>::from_script_ref(key_type_id, k, world.clone())?;
311+
312+
if caller_context.convert_to_0_indexed {
313+
key.convert_to_0_indexed_key();
314+
}
315+
316+
let removed = s.with_reflect_mut(world.clone(), |s| s.try_remove_boxed(key))??;
317+
318+
removed.map(|some| {
319+
let reference = {
320+
let allocator = world.allocator();
321+
let mut allocator = allocator.write();
322+
ReflectReference::new_allocated_boxed(some, &mut allocator)
323+
};
324+
ReflectReference::into_script_ref(reference, world)
325+
}).transpose()
326+
});
238327

239328
Ok(())
240329
}

crates/languages/bevy_mod_scripting_lua/src/bindings/reference.rs

Lines changed: 17 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,14 @@ fn lookup_function(lua: &Lua, key: &str, type_id: TypeId) -> Option<Result<Funct
8383
})
8484
}
8585

86+
fn lookup_function_typed<T: 'static + ?Sized>(
87+
lua: &Lua,
88+
key: &str,
89+
) -> Option<Result<Function, mlua::Error>> {
90+
let type_id = TypeId::of::<T>();
91+
lookup_function(lua, key, type_id)
92+
}
93+
8694
fn lookup_dynamic_function<'lua>(
8795
lua: &'lua Lua,
8896
key: &str,
@@ -101,11 +109,9 @@ fn lookup_dynamic_function<'lua>(
101109
fn lookup_dynamic_function_typed<'lua, T: 'static + ?Sized>(
102110
lua: &'lua Lua,
103111
key: &str,
104-
) -> Option<Result<DynamicFunction<'static>, mlua::Error>> {
112+
) -> Option<DynamicFunction<'static>> {
105113
let type_id = TypeId::of::<T>();
106-
let function = lookup_dynamic_function(lua, key, type_id);
107-
108-
function.map(Ok)
114+
lookup_dynamic_function(lua, key, type_id)
109115
}
110116

111117
impl UserData for LuaReflectReference {
@@ -123,11 +129,15 @@ impl UserData for LuaReflectReference {
123129
if let Some(func) = lookup_function(lua, key, type_id) {
124130
return func?.into_lua(lua);
125131
}
132+
// try look up the function under the reflect reference namespace as well
133+
if let Some(func) = lookup_function_typed::<ReflectReference>(lua, key) {
134+
return func?.into_lua(lua);
135+
}
126136
};
127137

128-
// lookup get function
138+
// lookup get index function
129139
let index_func = lookup_dynamic_function_typed::<ReflectReference>(lua, "get")
130-
.expect("No 'get' function registered for a ReflectReference")?;
140+
.expect("No 'get' function registered for a ReflectReference");
131141

132142
// call the function with the key
133143
let out = index_func.call_script_function(
@@ -147,7 +157,7 @@ impl UserData for LuaReflectReference {
147157
let value: ScriptValue = value.into();
148158

149159
lookup_dynamic_function_typed::<ReflectReference>(lua, "set")
150-
.expect("No 'set' function registered for a ReflectReference")?
160+
.expect("No 'set' function registered for a ReflectReference")
151161
.call_script_function(
152162
vec![ScriptValue::Reference(self_), key, value],
153163
lua.get_world(),
@@ -158,103 +168,6 @@ impl UserData for LuaReflectReference {
158168
},
159169
);
160170

161-
// m.add_meta_function(
162-
// MetaMethod::Index,
163-
// |l, (mut self_, key): (LuaReflectReference, Value)| {
164-
// bevy::log::debug!(
165-
// "ReflectReference::Index with key: {:?} and value: {:?}",
166-
// key,
167-
// self_
168-
// );
169-
// // catchall, parse the path
170-
// let mut elem = Self::parse_value_index(key)?;
171-
// Self::to_host_index(&mut elem);
172-
// self_.0.index_path(elem);
173-
// bevy::log::debug!("Target reflect reference after indexing key: {:?}", self_.0);
174-
// self_.to_lua_proxy(l)
175-
// },
176-
// );
177-
// m.add_meta_function(
178-
// MetaMethod::NewIndex,
179-
// |l, (mut self_, key, value): (LuaReflectReference, Value, Value)| {
180-
// bevy::log::debug!(
181-
// "ReflectReference::NewIndex with key: {:?} and value: {:?}",
182-
// key,
183-
// value
184-
// );
185-
186-
// let mut elem = Self::parse_value_index(key)?;
187-
// Self::to_host_index(&mut elem);
188-
// self_.0.index_path(elem);
189-
// bevy::log::debug!("Target reflect reference after indexing key: {:?}", self_.0);
190-
// self_.set_with_lua_proxy(l, value)
191-
// },
192-
// );
193-
194-
// m.add_function_mut(
195-
// "insert",
196-
// |l, (self_, key, value): (LuaReflectReference, Value, Value)| {
197-
// let world = l.get_world();
198-
// bevy::log::debug!(
199-
// "ReflectReference::insert with key: {:?} and value: {:?}",
200-
// key,
201-
// value
202-
// );
203-
// let key = self_
204-
// .clone()
205-
// .concrete_from_value(key, l, TypeIdSource::Key)?;
206-
// bevy::log::debug!("Key: {:?}", key);
207-
// let value = self_
208-
// .clone()
209-
// .concrete_from_value(value, l, TypeIdSource::Element)?;
210-
// bevy::log::debug!("Value: {:?}", value);
211-
// self_
212-
// .0
213-
// .with_reflect_mut(&world, |r| r.try_insert_boxed(key, value))??;
214-
// Ok(())
215-
// },
216-
// );
217-
218-
// m.add_function_mut("push", |l, (self_, value): (LuaReflectReference, Value)| {
219-
// let world = l.get_world();
220-
// bevy::log::debug!("ReflectReference::push with value: {:?}", value);
221-
// let value = self_
222-
// .clone()
223-
// .concrete_from_value(value, l, TypeIdSource::Element)?;
224-
// self_
225-
// .0
226-
// .with_reflect_mut(&world, |r| r.try_push_boxed(value))??;
227-
// Ok(())
228-
// });
229-
230-
// m.add_function_mut("pop", |l, self_: LuaReflectReference| {
231-
// let world = l.get_world();
232-
// bevy::log::debug!("ReflectReference::pop");
233-
// let ref_ = self_.0.with_reflect_mut(&world, |r| {
234-
// let last_elem = r.try_pop_boxed()?;
235-
// let allocator = world.allocator();
236-
// let mut allocator = allocator.write();
237-
// let reflect_ref = LuaReflectReference(ReflectReference::new_allocated_boxed(
238-
// last_elem,
239-
// &mut allocator,
240-
// ));
241-
// Ok::<_, ScriptError>(reflect_ref)
242-
// })??;
243-
244-
// Ok(ref_)
245-
// });
246-
247-
// m.add_function("clear", |l, self_: LuaReflectReference| {
248-
// let world = l.get_world();
249-
// bevy::log::debug!("ReflectReference::clear");
250-
// self_.0.with_reflect_mut(&world, |r| r.try_clear())??;
251-
// Ok(())
252-
// });
253-
254-
// m.add_meta_function(MetaMethod::Len, |l, self_: LuaReflectReference| {
255-
// self_.len(l)
256-
// });
257-
258171
// #[cfg(any(
259172
// feature = "lua54",
260173
// feature = "lua53",

crates/languages/bevy_mod_scripting_lua/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ pub fn with_world<F: FnOnce(&mut Lua) -> Result<(), ScriptError>>(
208208
.globals()
209209
.set(
210210
"world",
211-
LuaStaticReflectReference(std::any::TypeId::of::<WorldCallbackAccess>()),
211+
LuaStaticReflectReference(std::any::TypeId::of::<World>()),
212212
)
213213
.map_err(ScriptError::from_mlua_error)?;
214214
context.set_app_data(guard.clone());
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
local res_type = world.get_type_by_name("TestResourceWithVariousFields")
2+
local res = world.get_resource(res_type)
3+
4+
res.vec_usize:clear()
5+
6+
assert(res.vec_usize:len() == 0, "Clear did not work")

0 commit comments

Comments
 (0)