Skip to content

Commit a0a2fcf

Browse files
committed
feat: add hashmap support
1 parent 638aaea commit a0a2fcf

File tree

5 files changed

+65
-10
lines changed

5 files changed

+65
-10
lines changed

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

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ impl From<LuaScriptValue> for ScriptValue {
3838
}
3939

4040
impl FromLua for LuaScriptValue {
41-
fn from_lua(value: mlua::Value, _lua: &mlua::Lua) -> mlua::Result<Self> {
41+
fn from_lua(value: mlua::Value, lua: &mlua::Lua) -> mlua::Result<Self> {
4242
Ok(match value {
4343
Value::Nil => ScriptValue::Unit,
4444
Value::Boolean(b) => ScriptValue::Bool(b),
@@ -50,12 +50,34 @@ impl FromLua for LuaScriptValue {
5050
Value::Number(n) => ScriptValue::Float(n),
5151
Value::String(s) => ScriptValue::String(s.to_str()?.to_owned().into()),
5252
Value::Table(table) => {
53-
let mut vec = Vec::with_capacity(table.len()? as usize);
54-
for i in table.sequence_values() {
55-
let v: LuaScriptValue = i?;
56-
vec.push(v.into());
53+
// check the key types, if strings then it's a map
54+
let mut iter = table.pairs::<Value, LuaScriptValue>();
55+
56+
match iter.next() {
57+
Some(v) => {
58+
let (k, v) = v?;
59+
// if the key is a string, then it's a map
60+
if k.is_string() {
61+
let mut map = HashMap::new();
62+
map.insert(k.to_string()?, v.into());
63+
for pair in iter {
64+
let (k, v) = pair?;
65+
let str_: String = String::from_lua(k, lua)?;
66+
map.insert(str_, v.into());
67+
}
68+
return Ok(LuaScriptValue::from(ScriptValue::Map(map)));
69+
} else {
70+
// if the key is an integer, then it's a list
71+
let mut vec = Vec::with_capacity(table.len()? as usize);
72+
vec.push(v.into());
73+
for pair in iter {
74+
vec.push(pair?.1.into());
75+
}
76+
return Ok(LuaScriptValue::from(ScriptValue::List(vec)));
77+
}
78+
}
79+
None => return Ok(LuaScriptValue::from(ScriptValue::List(vec![]))),
5780
}
58-
ScriptValue::List(vec)
5981
}
6082
// Value::Thread(thread) => todo!(),
6183
Value::UserData(ud) => {
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
local map = make_hashmap({
2+
key1 = 2,
3+
key2 = 3,
4+
})
5+
6+
assert(map["key1"] == 2, "map[\"key1\"] should be 2")
7+
assert(map["key2"] == 3, "map[\"key2\"] should be 3")

crates/languages/bevy_mod_scripting_rhai/src/bindings/script_value.rs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ pub trait FromDynamic: Sized {
129129
fn from_dynamic(dynamic: Dynamic) -> Result<Self, Box<EvalAltResult>>;
130130
}
131131

132-
#[allow(clippy::unwrap_used, clippy::todo)]
132+
#[allow(clippy::unwrap_used)]
133133
impl FromDynamic for ScriptValue {
134134
fn from_dynamic(dynamic: Dynamic) -> Result<Self, Box<EvalAltResult>> {
135135
match dynamic {
@@ -140,6 +140,18 @@ impl FromDynamic for ScriptValue {
140140
d if d.is_string() => Ok(ScriptValue::String(
141141
d.into_immutable_string().unwrap().to_string().into(),
142142
)),
143+
mut d if d.is_map() => Ok(ScriptValue::Map(
144+
d.as_map_mut()
145+
.map_err(|_| {
146+
Box::new(EvalAltResult::ErrorSystem(
147+
"FromDynamic".to_string(),
148+
InteropError::invariant("d is proved to be a map").into(),
149+
))
150+
})?
151+
.iter()
152+
.map(|(k, v)| Ok((k.to_string(), ScriptValue::from_dynamic(v.clone())?)))
153+
.collect::<Result<_, Box<EvalAltResult>>>()?,
154+
)),
143155
d if d.is_array() => Ok(ScriptValue::List(
144156
d.into_array()
145157
.map_err(|_| InteropError::invariant("d is proved to be an array"))?
@@ -151,7 +163,13 @@ impl FromDynamic for ScriptValue {
151163
if let Some(v) = d.try_cast::<RhaiReflectReference>() {
152164
Ok(ScriptValue::Reference(v.0))
153165
} else {
154-
todo!("from conversion not implemented yet")
166+
Err(Box::new(EvalAltResult::ErrorSystem(
167+
"FromDynamic".to_string(),
168+
Box::new(InteropError::impossible_conversion(std::any::TypeId::of::<
169+
ScriptValue,
170+
>(
171+
))),
172+
)))
155173
}
156174
}
157175
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
let my_map = make_hashmap.call(#{
2+
key1: 2,
3+
key2: 3,
4+
});
5+
6+
assert(my_map["key1"] == 2, "map[\"key1\"] should be 2");
7+
assert(my_map["key2"] == 3, "map[\"key2\"] should be 3");

crates/script_integration_test_harness/src/test_functions.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::sync::Arc;
1+
use std::{collections::HashMap, sync::Arc};
22

33
use bevy::{
44
app::App,
@@ -102,5 +102,6 @@ pub fn register_test_functions(world: &mut App) {
102102
);
103103

104104
NamespaceBuilder::<GlobalNamespace>::new_unregistered(world)
105-
.register("global_hello_world", || Ok("hi!"));
105+
.register("global_hello_world", || Ok("hi!"))
106+
.register("make_hashmap", |map: HashMap<String, usize>| map);
106107
}

0 commit comments

Comments
 (0)