Skip to content

Commit b5f85e7

Browse files
initial from_script_ref
1 parent db825a5 commit b5f85e7

File tree

8 files changed

+133
-30
lines changed

8 files changed

+133
-30
lines changed

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

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,27 @@ impl FromScript for () {
3939
}
4040
}
4141

42+
impl FromScript for bool {
43+
type This<'w> = Self;
44+
45+
fn from_script(
46+
value: ScriptValue,
47+
world: WorldGuard<'_>,
48+
) -> Result<Self::This<'_>, InteropError>
49+
where
50+
Self: Sized,
51+
{
52+
match value {
53+
ScriptValue::Bool(b) => Ok(b),
54+
ScriptValue::Reference(r) => r.downcast::<Self>(world),
55+
_ => Err(InteropError::value_mismatch(
56+
std::any::TypeId::of::<Self>(),
57+
value,
58+
)),
59+
}
60+
}
61+
}
62+
4263
macro_rules! impl_from_with_downcast {
4364
($($ty:ty),*) => {
4465
$(
@@ -79,6 +100,28 @@ macro_rules! impl_from_stringlike {
79100

80101
impl_from_stringlike!(String, PathBuf, OsString);
81102

103+
impl FromScript for char {
104+
type This<'w> = Self;
105+
106+
fn from_script(
107+
value: ScriptValue,
108+
world: WorldGuard<'_>,
109+
) -> Result<Self::This<'_>, InteropError>
110+
where
111+
Self: Sized,
112+
{
113+
match value {
114+
ScriptValue::Integer(i) => Ok(i as u8 as char),
115+
ScriptValue::String(c) if c.len() == 1 => Ok(c.chars().next().expect("invariant")),
116+
ScriptValue::Reference(r) => r.downcast::<Self>(world),
117+
_ => Err(InteropError::value_mismatch(
118+
std::any::TypeId::of::<Self>(),
119+
value,
120+
)),
121+
}
122+
}
123+
}
124+
82125
impl FromScript for ReflectReference {
83126
type This<'w> = Self;
84127
fn from_script(value: ScriptValue, _world: WorldGuard) -> Result<Self, InteropError> {

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

Lines changed: 67 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1-
use std::any::TypeId;
1+
use std::{any::TypeId, ffi::OsString, path::PathBuf};
22

3-
use bevy::reflect::PartialReflect;
3+
use bevy::reflect::{DynamicEnum, DynamicTuple, DynamicVariant, PartialReflect};
44

55
use crate::{
6-
bindings::{ReflectReference, WorldGuard},
6+
bindings::{function::from::FromScript, ReflectReference, WorldGuard},
7+
downcast_into_value,
78
error::InteropError,
9+
match_by_type,
810
prelude::ScriptValue,
11+
reflection_extensions::TypeInfoExtensions,
912
};
1013

1114
/// Converts from a [`ScriptValue`] to a value equivalent to the given [`TypeId`].
@@ -30,6 +33,66 @@ impl FromScriptRef for Box<dyn PartialReflect> {
3033
where
3134
Self: Sized,
3235
{
33-
todo!()
36+
match_by_type! (
37+
match target {
38+
ta : usize => return <usize>::from_script(value, world).map(|a| Box::new(a) as _),
39+
tb : isize => return <isize>::from_script(value, world).map(|a| Box::new(a) as _),
40+
tc : u8 => return <u8>::from_script(value, world).map(|a| Box::new(a) as _),
41+
td : u16 => return <u16>::from_script(value, world).map(|a| Box::new(a) as _),
42+
te : u32 => return <u32>::from_script(value, world).map(|a| Box::new(a) as _),
43+
tf : u64 => return <u64>::from_script(value, world).map(|a| Box::new(a) as _),
44+
tg : u128 => return <u128>::from_script(value, world).map(|a| Box::new(a) as _),
45+
th : i8 => return <i8>::from_script(value, world).map(|a| Box::new(a) as _),
46+
ti : i16 => return <i16>::from_script(value, world).map(|a| Box::new(a) as _),
47+
tj : i32 => return <i32>::from_script(value, world).map(|a| Box::new(a) as _),
48+
tk : i64 => return <i64>::from_script(value, world).map(|a| Box::new(a) as _),
49+
tl : i128 => return <i128>::from_script(value, world).map(|a| Box::new(a) as _),
50+
tm : f32 => return <f32>::from_script(value, world).map(|a| Box::new(a) as _),
51+
tn : f64 => return <f64>::from_script(value, world).map(|a| Box::new(a) as _),
52+
to : bool => return <bool>::from_script(value, world).map(|a| Box::new(a) as _),
53+
tp : char => return <char>::from_script(value, world).map(|a| Box::new(a) as _),
54+
tq : String => return <String>::from_script(value, world).map(|a| Box::new(a) as _),
55+
tr : PathBuf => return <PathBuf>::from_script(value, world).map(|a| Box::new(a) as _),
56+
ts : OsString=> return <OsString>::from_script(value, world).map(|a| Box::new(a) as _),
57+
tn : () => return <()>::from_script(value, world).map(|a| Box::new(a) as _)
58+
}
59+
);
60+
61+
let type_registry = world.type_registry();
62+
let type_registry = type_registry.read();
63+
64+
let type_info = type_registry.get_type_info(target).ok_or_else(|| {
65+
InteropError::missing_type_data(
66+
target,
67+
"Type was not registered, could not determine conversion strategy.".to_owned(),
68+
)
69+
})?;
70+
71+
if type_info.is_option() {
72+
let inner_type = type_info.option_inner_type().expect("invariant");
73+
let mut dynamic_enum = match value {
74+
ScriptValue::Unit => {
75+
// build none variant
76+
let mut dynamic_enum = DynamicEnum::new("None", DynamicVariant::Unit);
77+
dynamic_enum
78+
}
79+
_ => {
80+
let inner = Self::from_script_ref(inner_type, value, world)?;
81+
let mut dynamic_enum = DynamicEnum::new(
82+
"Some",
83+
DynamicVariant::Tuple(DynamicTuple::from_iter(vec![inner])),
84+
);
85+
dynamic_enum
86+
}
87+
};
88+
89+
dynamic_enum.set_represented_type(Some(type_info));
90+
return Ok(Box::new(dynamic_enum));
91+
}
92+
93+
match value {
94+
ScriptValue::Reference(reflect_reference) => reflect_reference.to_owned_value(world),
95+
value => Err(InteropError::value_mismatch(target, value)),
96+
}
3497
}
3598
}

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

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
use std::{any::TypeId, ffi::OsString, path::PathBuf};
22

3-
use bevy::{
4-
reflect::{ParsedPath, PartialReflect},
5-
text::cosmic_text::rustybuzz::Script,
6-
};
3+
use bevy::reflect::{ParsedPath, PartialReflect};
74

85
use crate::{
96
bindings::{function::into::IntoScript, ReflectReference, WorldGuard},
@@ -26,6 +23,7 @@ pub trait IntoScriptRef {
2623
) -> Result<ScriptValue, InteropError>;
2724
}
2825

26+
#[macro_export]
2927
macro_rules! match_by_type {
3028
(match $on:ident {$($id:ident : $ty:ty => $conv:expr),*}) => {
3129
$(
@@ -42,6 +40,7 @@ macro_rules! match_by_type {
4240
};
4341
}
4442

43+
#[macro_export]
4544
macro_rules! downcast_into_value {
4645
($r:ident, $ty:ty) => {
4746
*$r.try_downcast_ref::<$ty>().ok_or_else(|| {

crates/bevy_mod_scripting_core/src/bindings/reference.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ impl ReflectReference {
176176

177177
/// Attempts to create a [`Box<dyn PartialReflect>`] from the reference. This is possible using a few strategies:
178178
/// - If the reference is to a world, a [`WorldCallbackAccess`] is created and boxed
179-
/// - If the reference is to an allocation with no reflection path, the value is taken as is.
179+
/// - If the reference is to an allocation with no reflection path and references to it, the value is taken as is.
180180
/// - If the reference has a [`bevy::reflect::ReflectFromReflect`] type data associated with it, the value is cloned using that impl.
181181
/// - If all above fails, [`bevy::reflect::PartialReflect::clone_value`] is used to clone the value.
182182
///

crates/bevy_mod_scripting_core/src/reflection_extensions.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ use std::{
33
borrow::Cow,
44
cmp::max,
55
ffi::{CStr, CString, OsStr, OsString},
6-
os::unix::ffi::OsStrExt,
76
path::{Path, PathBuf},
87
str::FromStr,
98
};

crates/bevy_mod_scripting_functions/src/core.rs

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,11 @@ use bevy_mod_scripting_core::*;
1212
use bindings::{
1313
function::{
1414
from::{Mut, Ref, Val},
15+
from_ref::FromScriptRef,
1516
into_ref::IntoScriptRef,
1617
script_function::ScriptFunction,
1718
},
18-
script_value::{FromScriptValue, IntoScriptValue, ScriptValue},
19+
script_value::ScriptValue,
1920
ReflectReference, ReflectionPathExt, ScriptTypeRegistration, WorldAccessGuard,
2021
WorldCallbackAccess,
2122
};
@@ -96,7 +97,7 @@ fn register_world_functions(reg: &mut FunctionRegistry) -> Result<(), FunctionRe
9697
NamespaceBuilder::<ReflectReference>::new(reg)
9798
.overwrite_script_function(
9899
"get",
99-
|world: WorldCallbackAccess, self_: ReflectReference, key: ScriptValue| {
100+
|world: WorldCallbackAccess, mut self_: ReflectReference, key: ScriptValue| {
100101
let mut path: ParsedPath = key.try_into()?;
101102
self_.index_path(path);
102103
let world = world.read().expect("Stale world");
@@ -105,7 +106,7 @@ fn register_world_functions(reg: &mut FunctionRegistry) -> Result<(), FunctionRe
105106
)
106107
.overwrite_script_function(
107108
"get_1_indexed",
108-
|world: WorldCallbackAccess, self_: ReflectReference, key: ScriptValue| {
109+
|world: WorldCallbackAccess, mut self_: ReflectReference, key: ScriptValue| {
109110
let mut path: ParsedPath = key.try_into()?;
110111
path.convert_to_0_indexed();
111112
self_.index_path(path);
@@ -130,13 +131,11 @@ fn register_world_functions(reg: &mut FunctionRegistry) -> Result<(), FunctionRe
130131
.get_represented_type_info()
131132
.map(|i| i.type_id())
132133
.or_fake_id();
133-
let other = <dyn PartialReflect>::from_script_value(
134+
let other = <Box<dyn PartialReflect>>::from_script_ref(
135+
target_type_id,
134136
value,
135137
world.clone(),
136-
target_type_id,
137-
)
138-
.ok_or_else(|| InteropError::impossible_conversion(target_type_id))??;
139-
138+
)?;
140139
r.try_apply(other.as_partial_reflect()).unwrap();
141140
Ok::<_, InteropError>(())
142141
})
@@ -149,7 +148,7 @@ fn register_world_functions(reg: &mut FunctionRegistry) -> Result<(), FunctionRe
149148
.overwrite_script_function(
150149
"set_1_indexed",
151150
|world: WorldCallbackAccess,
152-
self_: ReflectReference,
151+
mut self_: ReflectReference,
153152
key: ScriptValue,
154153
value: ScriptValue| {
155154
let world = world.read().expect("stale world");
@@ -163,12 +162,11 @@ fn register_world_functions(reg: &mut FunctionRegistry) -> Result<(), FunctionRe
163162
.get_represented_type_info()
164163
.map(|i| i.type_id())
165164
.or_fake_id();
166-
let other = <dyn PartialReflect>::from_script_value(
165+
let other = <Box<dyn PartialReflect>>::from_script_ref(
166+
target_type_id,
167167
value,
168168
world.clone(),
169-
target_type_id,
170-
)
171-
.ok_or_else(|| InteropError::impossible_conversion(target_type_id))??;
169+
)?;
172170

173171
r.try_apply(other.as_partial_reflect()).unwrap();
174172
Ok::<_, InteropError>(())

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

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ use bevy::{
1616
};
1717
use bevy_mod_scripting_core::{
1818
bindings::{
19-
function::CallAsScriptFunction,
19+
function::CallScriptFunction,
2020
pretty_print::{DisplayWithWorld, ReflectReferencePrinter},
21-
script_value::{FromScriptValue, IntoScriptValue, ScriptValue},
21+
script_value::ScriptValue,
2222
ReflectAllocator, ReflectRefIter, ReflectReference, ReflectionPathExt, TypeIdSource,
2323
WorldCallbackAccess,
2424
},
@@ -66,7 +66,7 @@ fn lookup_function(lua: &Lua, key: &str, type_id: TypeId) -> Option<Result<Funct
6666
function.map(|function| {
6767
lua.create_function(move |lua, args: Variadic<LuaScriptValue>| {
6868
let world = lua.get_world();
69-
let out = function.dynamic_call(args.into_iter().map(Into::into), world)?;
69+
let out = function.call_script_function(args.into_iter().map(Into::into), world)?;
7070

7171
Ok(LuaScriptValue::from(out))
7272
})
@@ -121,8 +121,10 @@ impl UserData for LuaReflectReference {
121121
.expect("No 'get' function registered for a ReflectReference")?;
122122

123123
// call the function with the key
124-
let out = index_func
125-
.dynamic_call(vec![ScriptValue::Reference(self_), key], world.clone())?;
124+
let out = index_func.call_script_function(
125+
vec![ScriptValue::Reference(self_), key],
126+
world.clone(),
127+
)?;
126128
LuaScriptValue::from(out).into_lua(lua)
127129
},
128130
);
@@ -136,7 +138,7 @@ impl UserData for LuaReflectReference {
136138

137139
lookup_dynamic_function_typed::<ReflectReference>(lua, "set_1_indexed")
138140
.expect("No 'set' function registered for a ReflectReference")?
139-
.dynamic_call(
141+
.call_script_function(
140142
vec![ScriptValue::Reference(self_), key, value],
141143
lua.get_world(),
142144
)?;

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ use std::sync::Arc;
33
use bevy::ecs::{component::ComponentId, reflect::AppTypeRegistry, world::Mut};
44
use bevy::prelude::{AppFunctionRegistry, Entity, World};
55

6-
use bevy_mod_scripting_core::bindings::function::CallAsScriptFunction;
76
use bevy_mod_scripting_core::bindings::WorldGuard;
87
use bevy_mod_scripting_core::error::InteropError;
98
use bevy_mod_scripting_core::{

0 commit comments

Comments
 (0)