use bevy::prelude::*;
use parking_lot::RwLock;
use std::fmt::Debug;
use std::{borrow::Cow, sync::Weak};
use bevy_mod_scripting_core::world::WorldPointer;
use crate::{
error::ReflectionError,
sub_reflect::{ReflectBase, ReflectionPath, ReflectionPathElement},
};
#[derive(Clone, Debug)]
pub struct ReflectReference {
pub(crate) path: ReflectionPath,
pub(crate) world_ptr: WorldPointer,
}
unsafe impl Send for ReflectReference {}
unsafe impl Sync for ReflectReference {}
impl ReflectReference {
pub fn new_component_ref(
comp: ReflectComponent,
entity: Entity,
world_ptr: WorldPointer,
) -> Self {
Self {
path: ReflectionPath::new(ReflectBase::Component { comp, entity }),
world_ptr,
}
}
pub fn new_resource_ref(res: ReflectResource, world_ptr: WorldPointer) -> Self {
Self {
path: ReflectionPath::new(ReflectBase::Resource { res }),
world_ptr,
}
}
pub fn new_script_ref<T: Reflect>(ptr: Weak<RwLock<T>>, world_ptr: WorldPointer) -> Self {
Self {
path: ReflectionPath::new(ReflectBase::ScriptOwned { val: ptr }),
world_ptr,
}
}
pub(crate) fn sub_ref(&self, elem: ReflectionPathElement) -> ReflectReference {
let path = self.path.new_sub(elem);
Self {
path,
..self.clone()
}
}
#[inline(always)]
pub fn get<O, F>(&self, f: F) -> Result<O, ReflectionError>
where
F: FnOnce(&dyn Reflect) -> O,
{
self.path.get(self.world_ptr.clone(), f)
}
pub fn get_typed<T, O, F>(&self, f: F) -> Result<O, ReflectionError>
where
F: FnOnce(&T) -> O,
T: Reflect,
{
self.path.get(self.world_ptr.clone(), |reflect| {
(f)(reflect.downcast_ref::<T>().unwrap_or_else(|| {
panic!(
"Expected `{}` found `{}`",
::std::any::type_name::<T>(),
reflect.get_represented_type_info().unwrap().type_path()
)
}))
})
}
#[inline(always)]
pub fn get_mut<O, F>(&mut self, f: F) -> Result<O, ReflectionError>
where
F: FnOnce(&mut dyn Reflect) -> O,
{
self.path.get_mut(self.world_ptr.clone(), f)
}
pub fn get_mut_typed<T, O, F>(&mut self, f: F) -> Result<O, ReflectionError>
where
F: FnOnce(&mut T) -> O,
T: Reflect,
{
self.path.get_mut(self.world_ptr.clone(), |reflect| {
(f)(reflect.downcast_mut().unwrap())
})
}
pub fn apply(&mut self, other: &ReflectReference) -> Result<(), ReflectionError> {
let cloned = other.get(|s| s.clone_value())?;
self.get_mut(|s| s.apply(&*cloned))
}
pub fn set<T>(&mut self, other: &Self) -> Result<(), ReflectionError>
where
T: Reflect + Clone,
{
let other: T = other.get_typed(|s: &T| s.clone())?;
self.get_mut_typed(|s| *s = other)
}
pub fn set_val<T>(&mut self, other: T) -> Result<(), ReflectionError>
where
T: Reflect,
{
self.get_mut_typed(|s| *s = other)
}
}
pub trait ValueIndex<Idx> {
type Output;
fn index(&self, index: Idx) -> Self::Output;
}
impl ValueIndex<usize> for ReflectReference {
type Output = Self;
fn index(&self, index: usize) -> Self::Output {
self.sub_ref(ReflectionPathElement::IndexAccess(index))
}
}
impl ValueIndex<Cow<'static, str>> for ReflectReference {
type Output = Self;
fn index(&self, index: Cow<'static, str>) -> Self::Output {
self.sub_ref(ReflectionPathElement::FieldAccess(index))
}
}
#[derive(Clone, Debug)]
pub struct ReflectedValue {
pub(crate) ref_: ReflectReference,
}
impl From<ReflectedValue> for ReflectReference {
fn from(ref_: ReflectedValue) -> Self {
ref_.ref_
}
}