use bevy::reflect::PartialReflect;
use parking_lot::RwLock;
use std::fmt;
use std::fmt::{Debug, Display};
use std::sync::Arc;
use std::{borrow::Cow, sync::Weak};
use bevy::{
prelude::{Entity, ReflectComponent, ReflectResource},
reflect::{Reflect, ReflectMut, ReflectRef},
};
use crate::error::ReflectionError;
use bevy_mod_scripting_core::world::WorldPointer;
#[derive(Clone)]
pub(crate) enum ReflectBase {
Component {
comp: ReflectComponent,
entity: Entity,
},
Resource { res: ReflectResource },
ScriptOwned { val: Weak<RwLock<dyn Reflect>> },
}
unsafe impl Send for ReflectBase {}
unsafe impl Sync for ReflectBase {}
impl fmt::Debug for ReflectBase {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Component { entity, .. } => {
f.debug_struct("Component").field("entity", entity).finish()
}
Self::ScriptOwned { .. } => write!(f, "ScriptOwned"),
Self::Resource { .. } => f.debug_struct("Resource").finish(),
}
}
}
impl fmt::Display for ReflectBase {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ReflectBase::Component { entity, .. } => {
f.write_str("(Component on ")?;
f.write_str(&entity.index().to_string())?;
f.write_str(")")
}
ReflectBase::Resource { .. } => f.write_str("(Resource)"),
ReflectBase::ScriptOwned { .. } => f.write_str("(ScriptOwned)"),
}
}
}
pub type Get = dyn Fn(&dyn Reflect) -> Result<&dyn Reflect, ReflectionError>;
pub type GetMut = dyn Fn(&mut dyn Reflect) -> Result<&mut dyn Reflect, ReflectionError>;
#[derive(Clone)]
pub enum ReflectionPathElement {
SubReflection {
label: &'static str,
get: Arc<Get>,
get_mut: Arc<GetMut>,
},
FieldAccess(Cow<'static, str>),
IndexAccess(usize), }
impl Debug for ReflectionPathElement {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::SubReflection { label, .. } => f
.debug_struct("SubReflection")
.field("label", label)
.finish(),
Self::FieldAccess(arg0) => f.debug_tuple("FieldAccess").field(arg0).finish(),
Self::IndexAccess(arg0) => f.debug_tuple("IndexAccess").field(arg0).finish(),
}
}
}
impl Display for ReflectionPathElement {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ReflectionPathElement::SubReflection { label, .. } => {
f.write_str(".")?;
f.write_str(label)?;
f.write_str("()")
}
ReflectionPathElement::FieldAccess(s) => {
f.write_str(".")?;
f.write_str(s)
}
ReflectionPathElement::IndexAccess(i) => {
f.write_str("[")?;
f.write_str(&i.to_string())?;
f.write_str("]")
}
}
}
}
impl ReflectionPathElement {
pub(crate) fn sub_ref<'a>(
&self,
base: &'a dyn Reflect,
) -> Result<&'a dyn Reflect, ReflectionError> {
match self {
ReflectionPathElement::SubReflection { get, .. } => get(base),
ReflectionPathElement::FieldAccess(field) => match base.reflect_ref() {
ReflectRef::Struct(s) => s
.field(field)
.and_then(PartialReflect::try_as_reflect)
.ok_or_else(|| ReflectionError::InvalidReflectionPath {
path: self.to_string(),
msg: "No such field".to_owned(),
}),
_ => Err(ReflectionError::InvalidReflectionPath {
path: self.to_string(),
msg: "No such field".to_owned(),
}),
},
ReflectionPathElement::IndexAccess(index) => match base.reflect_ref() {
ReflectRef::TupleStruct(s) => s
.field(*index)
.and_then(PartialReflect::try_as_reflect)
.ok_or_else(|| ReflectionError::InvalidReflectionPath {
path: self.to_string(),
msg: "No such element".to_owned(),
}),
ReflectRef::Tuple(s) => s
.field(*index)
.and_then(PartialReflect::try_as_reflect)
.ok_or_else(|| ReflectionError::InvalidReflectionPath {
path: self.to_string(),
msg: "No such element".to_owned(),
}),
ReflectRef::List(s) => s
.get(*index)
.and_then(PartialReflect::try_as_reflect)
.ok_or_else(|| ReflectionError::InvalidReflectionPath {
path: self.to_string(),
msg: "No such element".to_owned(),
}),
ReflectRef::Array(s) => s
.get(*index)
.and_then(PartialReflect::try_as_reflect)
.ok_or_else(|| ReflectionError::InvalidReflectionPath {
path: self.to_string(),
msg: "No such element".to_owned(),
}),
_ => Err(ReflectionError::InvalidReflectionPath {
path: self.to_string(),
msg: "No such element".to_owned(),
}),
},
}
}
pub(crate) fn sub_ref_mut<'a>(
&self,
base: &'a mut dyn Reflect,
) -> Result<&'a mut dyn Reflect, ReflectionError> {
match self {
ReflectionPathElement::SubReflection { get_mut, .. } => get_mut(base),
ReflectionPathElement::FieldAccess(field) => match base.reflect_mut() {
ReflectMut::Struct(s) => s
.field_mut(field)
.and_then(PartialReflect::try_as_reflect_mut)
.ok_or_else(|| ReflectionError::InvalidReflectionPath {
path: self.to_string(),
msg: "No such field".to_owned(),
}),
_ => Err(ReflectionError::InvalidReflectionPath {
path: self.to_string(),
msg: "No such field".to_owned(),
}),
},
ReflectionPathElement::IndexAccess(index) => match base.reflect_mut() {
ReflectMut::TupleStruct(s) => s
.field_mut(*index)
.and_then(PartialReflect::try_as_reflect_mut)
.ok_or_else(|| ReflectionError::InvalidReflectionPath {
path: self.to_string(),
msg: "No such element".to_owned(),
}),
ReflectMut::Tuple(s) => s
.field_mut(*index)
.and_then(PartialReflect::try_as_reflect_mut)
.ok_or_else(|| ReflectionError::InvalidReflectionPath {
path: self.to_string(),
msg: "No such element".to_owned(),
}),
ReflectMut::List(s) => s
.get_mut(*index)
.and_then(PartialReflect::try_as_reflect_mut)
.ok_or_else(|| ReflectionError::InvalidReflectionPath {
path: self.to_string(),
msg: "No such element".to_owned(),
}),
ReflectMut::Array(s) => s
.get_mut(*index)
.and_then(PartialReflect::try_as_reflect_mut)
.ok_or_else(|| ReflectionError::InvalidReflectionPath {
path: self.to_string(),
msg: "No such element".to_owned(),
}),
_ => Err(ReflectionError::InvalidReflectionPath {
path: self.to_string(),
msg: "No such element".to_owned(),
}),
},
}
}
}
#[derive(Clone, Debug)]
pub(crate) struct ReflectionPath {
base: ReflectBase,
accesses: Vec<ReflectionPathElement>,
}
impl Display for ReflectionPath {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.base.to_string())?;
for access in &self.accesses {
f.write_str(&access.to_string())?
}
Ok(())
}
}
impl ReflectionPath {
pub fn new(base: ReflectBase) -> Self {
Self {
base,
accesses: Vec::default(),
}
}
pub fn new_sub(&self, elem: ReflectionPathElement) -> Self {
let mut accesses = self.accesses.clone();
accesses.push(elem);
Self {
accesses,
..self.clone()
}
}
fn walk_path<'a>(&self, ref_: &'a dyn Reflect) -> Result<&'a dyn Reflect, ReflectionError> {
let first = self.accesses.first().map(|s| s.sub_ref(ref_));
if let Some(first) = first {
if self.accesses.len() > 1 {
self.accesses[1..]
.iter()
.try_fold(first?, |a, access| access.sub_ref(a))
} else {
first
}
} else {
Ok(ref_)
}
}
fn walk_path_mut<'a>(
&self,
ref_: &'a mut dyn Reflect,
) -> Result<&'a mut dyn Reflect, ReflectionError> {
if let Some(first) = self.accesses.first() {
if self.accesses.len() > 1 {
self.accesses[1..]
.iter()
.try_fold(first.sub_ref_mut(ref_)?, |a, access| access.sub_ref_mut(a))
} else {
first.sub_ref_mut(ref_)
}
} else {
Ok(ref_)
}
}
pub fn get<O, F>(&self, world_ptr: WorldPointer, f: F) -> Result<O, ReflectionError>
where
F: FnOnce(&dyn Reflect) -> O,
{
match &self.base {
ReflectBase::Component { comp, entity } => {
let g = world_ptr.read();
let entity_ref =
g.get_entity(*entity)
.map_err(|e| ReflectionError::InvalidBaseReference {
base: self.base.to_string(),
reason: format!("This entity could not be retrieved. {e}"),
})?;
let ref_ = self.walk_path(comp.reflect(entity_ref).ok_or_else(|| {
ReflectionError::InvalidBaseReference {
base: self.base.to_string(),
reason: "Given component does not exist on this entity".to_owned(),
}
})?)?;
Ok(f(ref_))
}
ReflectBase::Resource { res } => {
let g = world_ptr.read();
let ref_ = self.walk_path(res.reflect(&g).ok_or_else(|| {
ReflectionError::InvalidBaseReference {
base: self.base.to_string(),
reason: "Given resource does not exist in this world".to_owned(),
}
})?)?;
Ok(f(ref_))
}
ReflectBase::ScriptOwned { val } => {
let g = val
.upgrade()
.expect("Trying to access cached value from previous frame");
let g = g.try_read().expect("Rust safety violation: attempted to borrow value {self:?} while it was already mutably borrowed");
Ok(f(self.walk_path(&*g)?))
}
}
}
pub fn get_mut<O, F>(&mut self, world_ptr: WorldPointer, f: F) -> Result<O, ReflectionError>
where
F: FnOnce(&mut dyn Reflect) -> O,
{
match &self.base {
ReflectBase::Component { comp, entity } => {
let mut g = world_ptr.write();
let mut e = g.entity_mut(*entity);
let ref_ = self.walk_path_mut(
comp.reflect_mut(&mut e)
.ok_or_else(|| ReflectionError::InvalidBaseReference {
base: self.base.to_string(),
reason: "Given component does not exist on this entity".to_owned(),
})?
.into_inner(),
)?;
Ok(f(ref_))
}
ReflectBase::Resource { res } => {
let mut g = world_ptr.write();
let ref_ = self.walk_path_mut(
res.reflect_mut(&mut g)
.ok_or_else(|| ReflectionError::InvalidBaseReference {
base: self.base.to_string(),
reason: "Given resource does not exist in this world".to_owned(),
})?
.into_inner(),
)?;
Ok(f(ref_))
}
ReflectBase::ScriptOwned { val } => {
let g = val
.upgrade()
.expect("Trying to access cached value from previous frame");
let mut g = g.try_write().expect("Rust safety violation: attempted to borrow value {self:?} while it was already mutably borrowed");
Ok(f(self.walk_path_mut(&mut *g)?))
}
}
}
}