Skip to content

Commit bbac943

Browse files
committed
Set & get for map
1 parent 4c3953f commit bbac943

File tree

5 files changed

+96
-40
lines changed

5 files changed

+96
-40
lines changed

assets/tests/set/set_primitives_works.lua

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,16 @@ resource.int = 42
77
resource.float = 3.0
88
resource.vec_usize = { 1, 2 }
99
resource.string_map = { foo = "hello", zoo = "world" }
10+
local map_string = resource.string_map.foo
1011

1112
assert(resource.string == "Hello, World!", "Expected 'Hello, World!', got " .. resource.string)
1213
assert(resource.bool == true, "Expected true, got " .. tostring(resource.bool))
1314
assert(resource.int == 42, "Expected 42, got " .. resource.int)
1415
assert(resource.float == 3.0, "Expected 3.14, got " .. resource.float)
1516
assert(resource.vec_usize[1] == 1, "Expected 1, got " .. resource.vec_usize[1])
1617
assert(resource.string_map:len() == 2, "Expected 2, got " .. resource.string_map:len())
17-
-- assert(resource.string_map["foo"] == "hello", "Expected 'hello', got " .. resource.string_map["foo"])
18-
-- assert(resource.string_map["zoo"] == "world", "Expected 'world', got " .. resource.string_map["zoo"])
18+
assert(resource.string_map.foo == "hello", "Expected 'hello', got " .. resource.string_map.foo)
19+
assert(resource.string_map.zoo == "world", "Expected 'world', got " .. resource.string_map.zoo)
1920

2021
resource.string = "Goodbye, World!"
2122
resource.bool = false
@@ -29,6 +30,11 @@ assert(resource.bool == false, "Expected false, got " .. tostring(resource.bool)
2930
assert(resource.int == 24, "Expected 24, got " .. resource.int)
3031
assert(resource.float == 1.0, "Expected 1.41, got " .. resource.float)
3132
assert(resource.string_map:len() == 2, "Expected 2, got " .. resource.string_map:len())
32-
-- assert(resource.string_map["foo"] == "goodbye", "Expected 'goodbye', got " .. resource.string_map["foo"])
33-
-- assert(resource.string_map["zoo"] == "world", "Expected 'world', got " .. resource.string_map["zoo"])
33+
assert(resource.string_map.foo == "goodbye", "Expected 'goodbye', got " .. resource.string_map.foo)
34+
assert(resource.string_map.zoo == "world", "Expected 'world', got " .. resource.string_map.zoo)
3435

36+
resource.string_map.foo = "hello"
37+
resource.string_map.zoo = "once more"
38+
39+
assert(resource.string_map.foo == "hello", "Expected 'hello', got " .. resource.string_map.foo)
40+
assert(resource.string_map.zoo == "once more", "Expected 'once more', got " .. resource.string_map.zoo)

crates/bevy_mod_scripting_core/src/bindings/reference.rs

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,8 @@
44
//! reflection gives us access to `dyn PartialReflect` objects via their type name,
55
//! Scripting languages only really support `Clone` objects so if we want to support references,
66
//! we need wrapper types which have owned and ref variants.
7-
use super::{access_map::ReflectAccessId, WorldGuard};
8-
use crate::{
9-
bindings::ReflectAllocationId,
10-
error::InteropError,
11-
reflection_extensions::{PartialReflectExt, TypeIdExtensions},
12-
with_access_read, with_access_write, ReflectAllocator,
13-
};
7+
use std::{any::TypeId, fmt::Debug};
8+
149
use bevy::{
1510
ecs::{
1611
change_detection::MutUntyped, component::ComponentId, entity::Entity,
@@ -20,7 +15,14 @@ use bevy::{
2015
ptr::Ptr,
2116
reflect::{ParsedPath, PartialReflect, Reflect, ReflectFromPtr, ReflectPath},
2217
};
23-
use std::{any::TypeId, fmt::Debug};
18+
19+
use super::{access_map::ReflectAccessId, WorldGuard};
20+
use crate::{
21+
bindings::ReflectAllocationId,
22+
error::InteropError,
23+
reflection_extensions::{PartialReflectExt, TypeIdExtensions},
24+
with_access_read, with_access_write, ReflectAllocator,
25+
};
2426

2527
/// An accessor to a `dyn PartialReflect` struct, stores a base ID of the type and a reflection path
2628
/// safe to build but to reflect on the value inside you need to ensure aliasing rules are upheld
@@ -91,6 +93,15 @@ impl ReflectReference {
9193
})
9294
}
9395

96+
/// If this is a reference to a map
97+
pub fn is_map(&self, world: WorldGuard) -> bool {
98+
self.with_reflect(world, |r| match r.reflect_ref() {
99+
bevy::reflect::ReflectRef::Map(_) => true,
100+
_ => false,
101+
})
102+
.unwrap_or_default()
103+
}
104+
94105
/// Create a new reference to a value by allocating it.
95106
///
96107
/// You can retrieve the allocator from the world using [`WorldGuard::allocator`].
@@ -115,7 +126,7 @@ impl ReflectReference {
115126
///
116127
/// Prefer using [`Self::new_allocated`] if you have a value that implements [`Reflect`].
117128
/// Will fail if the value does not have represented type info with a specific type id.
118-
pub fn new_allocated_boxed_parial_reflect(
129+
pub fn new_allocated_boxed_partial_reflect(
119130
value: Box<dyn PartialReflect>,
120131
allocator: &mut ReflectAllocator,
121132
) -> Result<ReflectReference, InteropError> {
@@ -594,12 +605,11 @@ impl Iterator for ReflectRefIter {
594605
mod test {
595606
use bevy::prelude::{AppTypeRegistry, World};
596607

608+
use super::*;
597609
use crate::bindings::{
598610
function::script_function::AppScriptFunctionRegistry, AppReflectAllocator,
599611
};
600612

601-
use super::*;
602-
603613
#[derive(Reflect, Component, Debug, Clone, PartialEq)]
604614
struct Component(Vec<String>);
605615

crates/bevy_mod_scripting_core/src/reflection_extensions.rs

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
//! Various utility functions for working with reflection types.
22
3-
use crate::{
4-
bindings::{ReflectReference, WorldGuard},
5-
error::InteropError,
6-
};
7-
use bevy::reflect::{PartialReflect, Reflect, ReflectFromReflect, ReflectMut, TypeInfo};
83
use std::{
94
any::{Any, TypeId},
105
cmp::max,
116
};
7+
8+
use bevy::reflect::{PartialReflect, Reflect, ReflectFromReflect, ReflectMut, TypeInfo};
9+
10+
use crate::{
11+
bindings::{ReflectReference, WorldGuard},
12+
error::InteropError,
13+
};
1214
/// Extension trait for [`PartialReflect`] providing additional functionality for working with specific types.
1315
pub trait PartialReflectExt {
1416
/// Try to remove the value at the given key, if the type supports removing with the given key.
@@ -66,6 +68,12 @@ pub trait PartialReflectExt {
6668
value: Box<dyn PartialReflect>,
6769
) -> Result<(), InteropError>;
6870

71+
/// Gets value of a map using index key, if possible
72+
fn try_get_boxed(
73+
&self,
74+
index: Box<dyn PartialReflect>,
75+
) -> Result<Option<Box<dyn PartialReflect>>, InteropError>;
76+
6977
/// Tries to insert the given value into the type, if the type is a container type.
7078
/// The insertion will happen at the natural `end` of the container.
7179
/// For lists, this is the length of the list.
@@ -263,6 +271,20 @@ impl<T: PartialReflect + ?Sized> PartialReflectExt for T {
263271
}
264272
}
265273

274+
fn try_get_boxed(
275+
&self,
276+
key: Box<dyn PartialReflect>,
277+
) -> Result<Option<Box<dyn PartialReflect>>, InteropError> {
278+
match self.reflect_ref() {
279+
bevy::reflect::ReflectRef::Map(m) => Ok(m.get(key.as_ref()).map(|v| v.clone_value())),
280+
_ => Err(InteropError::unsupported_operation(
281+
self.get_represented_type_info().map(|ti| ti.type_id()),
282+
Some(key),
283+
"get".to_owned(),
284+
)),
285+
}
286+
}
287+
266288
fn try_push_boxed(&mut self, value: Box<dyn PartialReflect>) -> Result<(), InteropError> {
267289
match self.reflect_mut() {
268290
bevy::reflect::ReflectMut::List(l) => {

crates/bevy_mod_scripting_functions/src/core.rs

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -351,13 +351,36 @@ impl ReflectReference {
351351
key: ScriptValue,
352352
) -> Result<ScriptValue, InteropError> {
353353
profiling::function_scope!("get");
354-
let mut path: ParsedPath = key.try_into()?;
355-
if ctxt.convert_to_0_indexed() {
356-
path.convert_to_0_indexed();
357-
}
358-
self_.index_path(path);
359354
let world = ctxt.world()?;
360-
ReflectReference::into_script_ref(self_, world)
355+
let is_map = self_.is_map(world.clone());
356+
if is_map {
357+
let key_type_id = self_.key_type_id(world.clone())?.ok_or_else(|| {
358+
InteropError::unsupported_operation(
359+
self_.tail_type_id(world.clone()).unwrap_or_default(),
360+
Some(Box::new(key.clone())),
361+
"Could not get key type id. Are you trying to get element from a type that's not a map?".to_owned(),
362+
)
363+
})?;
364+
let key = <Box<dyn PartialReflect>>::from_script_ref(key_type_id, key, world.clone())?;
365+
let result = self_.with_reflect(world.clone(), |s| s.try_get_boxed(key).ok()?)?;
366+
if let Some(value) = result {
367+
let value_ref = {
368+
let allocator = world.allocator();
369+
let mut allocator = allocator.write();
370+
ReflectReference::new_allocated_boxed_partial_reflect(value, &mut allocator)?
371+
};
372+
ReflectReference::into_script_ref(value_ref, world)
373+
} else {
374+
Ok(ScriptValue::Unit)
375+
}
376+
} else {
377+
let mut path: ParsedPath = key.try_into()?;
378+
if ctxt.convert_to_0_indexed() {
379+
path.convert_to_0_indexed();
380+
}
381+
self_.index_path(path);
382+
ReflectReference::into_script_ref(self_, world)
383+
}
361384
}
362385

363386
fn set(
@@ -420,7 +443,7 @@ impl ReflectReference {
420443
let reference = {
421444
let allocator = world.allocator();
422445
let mut allocator = allocator.write();
423-
ReflectReference::new_allocated_boxed_parial_reflect(o, &mut allocator)?
446+
ReflectReference::new_allocated_boxed_partial_reflect(o, &mut allocator)?
424447
};
425448

426449
ReflectReference::into_script_ref(reference, world)
@@ -500,7 +523,7 @@ impl ReflectReference {
500523
let reference = {
501524
let allocator = world.allocator();
502525
let mut allocator = allocator.write();
503-
ReflectReference::new_allocated_boxed_parial_reflect(removed, &mut allocator)?
526+
ReflectReference::new_allocated_boxed_partial_reflect(removed, &mut allocator)?
504527
};
505528
ReflectReference::into_script_ref(reference, world)
506529
}

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

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use bevy_mod_scripting_core::{
66
ThreadWorldContainer, WorldContainer,
77
},
88
error::InteropError,
9-
reflection_extensions::{TypeIdExtensions, TypeInfoExtensions},
9+
reflection_extensions::TypeIdExtensions,
1010
};
1111
use mlua::{MetaMethod, UserData, UserDataMethods};
1212

@@ -81,18 +81,13 @@ impl UserData for LuaReflectReference {
8181
let key: ScriptValue = key.into();
8282
let value: ScriptValue = value.into();
8383
let type_id = self_.tail_type_id(world.clone())?.or_fake_id();
84-
84+
let is_map = self_.is_map(world.clone());
8585
let func_name = {
86-
let type_registry = world.type_registry();
87-
let type_registry = type_registry.read();
88-
let type_info = type_registry.get_type_info(type_id).ok_or_else(|| {
89-
InteropError::missing_type_data(
90-
type_id,
91-
"Type was not registered, could not determine conversion strategy."
92-
.to_owned(),
93-
)
94-
})?;
95-
if type_info.is_map() { "insert" } else { "set" }
86+
if is_map {
87+
"insert"
88+
} else {
89+
"set"
90+
}
9691
};
9792
let func = world
9893
.lookup_function([type_id, TypeId::of::<ReflectReference>()], func_name)

0 commit comments

Comments
 (0)