use super::{FromScriptRef, FunctionCallContext, IntoScriptRef};
use crate::{ReferencePart, ReflectReference, ScriptValue, error::InteropError};
use bevy_mod_scripting_derive::DebugWithTypeInfo;
use bevy_mod_scripting_display::OrFakeId;
use bevy_reflect::PartialReflect;
#[derive(DebugWithTypeInfo)]
#[debug_with_type_info(bms_display_path = "bevy_mod_scripting_display")]
pub struct MagicFunctions {
#[debug_with_type_info(skip)]
pub get:
fn(FunctionCallContext, ReflectReference, ScriptValue) -> Result<ScriptValue, InteropError>,
#[debug_with_type_info(skip)]
pub set: fn(
FunctionCallContext,
ReflectReference,
ScriptValue,
ScriptValue,
) -> Result<(), InteropError>,
}
impl MagicFunctions {
pub fn get(
&self,
ctxt: FunctionCallContext,
reference: ReflectReference,
key: ScriptValue,
) -> Result<ScriptValue, InteropError> {
(self.get)(ctxt, reference, key)
}
pub fn set(
&self,
ctxt: FunctionCallContext,
reference: ReflectReference,
key: ScriptValue,
value: ScriptValue,
) -> Result<(), InteropError> {
(self.set)(ctxt, reference, key, value)
}
pub fn default_get(
ctxt: FunctionCallContext,
mut reference: ReflectReference,
key: ScriptValue,
) -> Result<ScriptValue, InteropError> {
let world = ctxt.world()?;
let path: ReferencePart =
ReferencePart::new_from_script_val(key, ctxt.language(), Some(world.clone())).map_err(
|e| InteropError::InvalidIndex {
index: Box::new(e),
reason: Box::new("Cannot convert to valid reflection path".to_owned()),
},
)?;
reference
.reflect_path
.set_is_one_indexed(ctxt.convert_to_0_indexed());
reference.push_path(path);
ReflectReference::into_script_ref(reference, world)
}
pub fn default_set(
ctxt: FunctionCallContext,
mut reference: ReflectReference,
key: ScriptValue,
value: ScriptValue,
) -> Result<(), InteropError> {
let world = ctxt.world()?;
let path: ReferencePart =
ReferencePart::new_from_script_val(key, ctxt.language(), Some(world.clone())).map_err(
|e| InteropError::InvalidIndex {
index: Box::new(e),
reason: Box::new("Cannot convert to valid reflection path".to_owned()),
},
)?;
reference
.reflect_path
.set_is_one_indexed(ctxt.convert_to_0_indexed());
reference.push_path(path);
reference.with_reflect_mut(world.clone(), |r| {
let target_type_id = r
.get_represented_type_info()
.map(|i| i.type_id())
.or_fake_id();
let other =
<Box<dyn PartialReflect>>::from_script_ref(target_type_id, value, world.clone())?;
r.try_apply(other.as_partial_reflect())
.map_err(InteropError::reflect_apply_error)?;
Ok::<_, InteropError>(())
})?
}
}
impl Default for MagicFunctions {
fn default() -> Self {
Self {
get: MagicFunctions::default_get,
set: MagicFunctions::default_set,
}
}
}