Skip to content

Commit 70302f8

Browse files
authored
feat: add map_get function for cloning and returning values on a map (#343)
feat: add `map_get` function for cloning and returning values on a hashmap
1 parent 9b368be commit 70302f8

File tree

4 files changed

+79
-0
lines changed

4 files changed

+79
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
let Resource = world.get_type_by_name.call("TestResourceWithVariousFields");
2+
let resource = world.get_resource.call(Resource);
3+
4+
assert(resource.string_map.map_get.call("foo") == "bar", "Expected bar, got " + resource.string_map.map_get.call("foo"));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
local Resource = world.get_type_by_name("TestResourceWithVariousFields")
2+
local resource = world.get_resource(Resource)
3+
4+
assert(resource.string_map:map_get("foo") == "bar", "Expected bar, got " .. resource.string_map:map_get("foo"))

crates/bevy_mod_scripting_core/src/reflection_extensions.rs

+20
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@ use std::{
1111
};
1212
/// Extension trait for [`PartialReflect`] providing additional functionality for working with specific types.
1313
pub trait PartialReflectExt {
14+
/// Try to get a reference to the given key in an underyling map, if the type is a map.
15+
fn try_map_get(
16+
&self,
17+
key: &dyn PartialReflect,
18+
) -> Result<Option<&dyn PartialReflect>, InteropError>;
19+
1420
/// Try to remove the value at the given key, if the type supports removing with the given key.
1521
fn try_remove_boxed(
1622
&mut self,
@@ -312,6 +318,20 @@ impl<T: PartialReflect + ?Sized> PartialReflectExt for T {
312318
}
313319
}
314320

321+
fn try_map_get(
322+
&self,
323+
key: &dyn PartialReflect,
324+
) -> Result<Option<&dyn PartialReflect>, InteropError> {
325+
match self.reflect_ref() {
326+
bevy::reflect::ReflectRef::Map(m) => Ok(m.get(key)),
327+
_ => Err(InteropError::unsupported_operation(
328+
self.get_represented_type_info().map(|ti| ti.type_id()),
329+
None,
330+
"map_get".to_owned(),
331+
)),
332+
}
333+
}
334+
315335
fn try_pop_boxed(&mut self) -> Result<Box<dyn PartialReflect>, InteropError> {
316336
match self.reflect_mut() {
317337
bevy::reflect::ReflectMut::List(l) => l.pop().ok_or_else(|| {

crates/bevy_mod_scripting_functions/src/core.rs

+51
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,7 @@ impl World {
321321
name = "reflect_reference_functions"
322322
)]
323323
impl ReflectReference {
324+
/// If this type is an enum, will return the name of the variant it represents on the type.
324325
fn variant_name(
325326
ctxt: FunctionCallContext,
326327
s: ReflectReference,
@@ -330,12 +331,14 @@ impl ReflectReference {
330331
s.variant_name(world)
331332
}
332333

334+
/// Displays this reference without printing the exact contents.
333335
fn display_ref(ctxt: FunctionCallContext, s: ReflectReference) -> Result<String, InteropError> {
334336
profiling::function_scope!("display_ref");
335337
let world = ctxt.world()?;
336338
Ok(s.display_with_world(world))
337339
}
338340

341+
/// Displays the "value" of this reference
339342
fn display_value(
340343
ctxt: FunctionCallContext,
341344
s: ReflectReference,
@@ -345,6 +348,43 @@ impl ReflectReference {
345348
Ok(s.display_value_with_world(world))
346349
}
347350

351+
/// Gets and clones the value under the specified key if the underlying type is a map type.
352+
fn map_get(
353+
ctxt: FunctionCallContext,
354+
self_: ReflectReference,
355+
key: ScriptValue,
356+
) -> Result<Option<ScriptValue>, InteropError> {
357+
profiling::function_scope!("map_get");
358+
let world = ctxt.world()?;
359+
let key = <Box<dyn PartialReflect>>::from_script_ref(
360+
self_.key_type_id(world.clone())?.ok_or_else(|| {
361+
InteropError::unsupported_operation(
362+
self_.tail_type_id(world.clone()).unwrap_or_default(),
363+
Some(Box::new(key.clone())),
364+
"Could not get key type id. Are you trying to index into a type that's not a map?".to_owned(),
365+
)
366+
})?,
367+
key,
368+
world.clone(),
369+
)?;
370+
self_.with_reflect_mut(world.clone(), |s| match s.try_map_get(key.as_ref())? {
371+
Some(value) => {
372+
let reference = {
373+
let allocator = world.allocator();
374+
let mut allocator = allocator.write();
375+
let owned_value = <dyn PartialReflect>::from_reflect(value, world.clone())?;
376+
ReflectReference::new_allocated_boxed(owned_value, &mut allocator)
377+
};
378+
Ok(Some(ReflectReference::into_script_ref(reference, world)?))
379+
}
380+
None => Ok(None),
381+
})?
382+
}
383+
384+
/// Indexes into the given reference and if the nested type is a reference type, returns a deeper reference, otherwise
385+
/// returns the concrete value.
386+
///
387+
/// Does not support map types at the moment, for maps see `map_get`
348388
fn get(
349389
ctxt: FunctionCallContext,
350390
mut self_: ReflectReference,
@@ -360,6 +400,7 @@ impl ReflectReference {
360400
ReflectReference::into_script_ref(self_, world)
361401
}
362402

403+
/// Sets the value under the specified path on the underlying value.
363404
fn set(
364405
ctxt: FunctionCallContext,
365406
self_: ScriptValue,
@@ -395,6 +436,7 @@ impl ReflectReference {
395436
Ok(ScriptValue::Unit)
396437
}
397438

439+
/// Pushes the value into the reference, if the reference is an appropriate container type.
398440
fn push(
399441
ctxt: FunctionCallContext,
400442
s: ReflectReference,
@@ -413,6 +455,7 @@ impl ReflectReference {
413455
s.with_reflect_mut(world, |s| s.try_push_boxed(other))?
414456
}
415457

458+
/// Pops the value from the reference, if the reference is an appropriate container type.
416459
fn pop(ctxt: FunctionCallContext, s: ReflectReference) -> Result<ScriptValue, InteropError> {
417460
profiling::function_scope!("pop");
418461
let world = ctxt.world()?;
@@ -426,6 +469,7 @@ impl ReflectReference {
426469
ReflectReference::into_script_ref(reference, world)
427470
}
428471

472+
/// Inserts the value into the reference at the specified index, if the reference is an appropriate container type.
429473
fn insert(
430474
ctxt: FunctionCallContext,
431475
s: ReflectReference,
@@ -461,18 +505,21 @@ impl ReflectReference {
461505
s.with_reflect_mut(world, |s| s.try_insert_boxed(key, value))?
462506
}
463507

508+
/// Clears the container, if the reference is an appropriate container type.
464509
fn clear(ctxt: FunctionCallContext, s: ReflectReference) -> Result<(), InteropError> {
465510
profiling::function_scope!("clear");
466511
let world = ctxt.world()?;
467512
s.with_reflect_mut(world, |s| s.try_clear())?
468513
}
469514

515+
/// Retrieves the length of the reference, if the reference is an appropriate container type.
470516
fn len(ctxt: FunctionCallContext, s: ReflectReference) -> Result<Option<usize>, InteropError> {
471517
profiling::function_scope!("len");
472518
let world = ctxt.world()?;
473519
s.len(world)
474520
}
475521

522+
/// Removes the value at the specified key from the reference, if the reference is an appropriate container type.
476523
fn remove(
477524
ctxt: FunctionCallContext,
478525
s: ReflectReference,
@@ -508,6 +555,9 @@ impl ReflectReference {
508555
}
509556
}
510557

558+
/// Iterates over the reference, if the reference is an appropriate container type.
559+
///
560+
/// Returns an "next" iterator function.
511561
fn iter(
512562
ctxt: FunctionCallContext,
513563
s: ReflectReference,
@@ -536,6 +586,7 @@ impl ReflectReference {
536586
Ok(iter_function.into_dynamic_script_function_mut())
537587
}
538588

589+
/// Lists the functions available on the reference.
539590
fn functions(
540591
ctxt: FunctionCallContext,
541592
s: ReflectReference,

0 commit comments

Comments
 (0)