use crate::{
func::args::{ArgError, FromArg, Ownership},
PartialReflect, Reflect, TypePath,
};
use alloc::{boxed::Box, string::ToString};
use core::ops::Deref;
#[derive(Debug)]
pub struct Arg<'a> {
index: usize,
value: ArgValue<'a>,
}
impl<'a> Arg<'a> {
pub fn new(index: usize, value: ArgValue<'a>) -> Self {
Self { index, value }
}
pub fn index(&self) -> usize {
self.index
}
pub(crate) fn set_index(&mut self, index: usize) {
self.index = index;
}
pub fn value(&self) -> &ArgValue<'a> {
&self.value
}
pub fn take_value(self) -> ArgValue<'a> {
self.value
}
pub fn take<T: FromArg>(self) -> Result<T::This<'a>, ArgError> {
T::from_arg(self)
}
pub fn take_owned<T: Reflect + TypePath>(self) -> Result<T, ArgError> {
match self.value {
ArgValue::Owned(arg) => arg.try_take().map_err(|arg| ArgError::UnexpectedType {
index: self.index,
expected: alloc::borrow::Cow::Borrowed(T::type_path()),
received: alloc::borrow::Cow::Owned(arg.reflect_type_path().to_string()),
}),
ArgValue::Ref(_) => Err(ArgError::InvalidOwnership {
index: self.index,
expected: Ownership::Owned,
received: Ownership::Ref,
}),
ArgValue::Mut(_) => Err(ArgError::InvalidOwnership {
index: self.index,
expected: Ownership::Owned,
received: Ownership::Mut,
}),
}
}
pub fn take_ref<T: Reflect + TypePath>(self) -> Result<&'a T, ArgError> {
match self.value {
ArgValue::Owned(_) => Err(ArgError::InvalidOwnership {
index: self.index,
expected: Ownership::Ref,
received: Ownership::Owned,
}),
ArgValue::Ref(arg) => {
Ok(arg
.try_downcast_ref()
.ok_or_else(|| ArgError::UnexpectedType {
index: self.index,
expected: alloc::borrow::Cow::Borrowed(T::type_path()),
received: alloc::borrow::Cow::Owned(arg.reflect_type_path().to_string()),
})?)
}
ArgValue::Mut(_) => Err(ArgError::InvalidOwnership {
index: self.index,
expected: Ownership::Ref,
received: Ownership::Mut,
}),
}
}
pub fn take_mut<T: Reflect + TypePath>(self) -> Result<&'a mut T, ArgError> {
match self.value {
ArgValue::Owned(_) => Err(ArgError::InvalidOwnership {
index: self.index,
expected: Ownership::Mut,
received: Ownership::Owned,
}),
ArgValue::Ref(_) => Err(ArgError::InvalidOwnership {
index: self.index,
expected: Ownership::Mut,
received: Ownership::Ref,
}),
ArgValue::Mut(arg) => {
let received = alloc::borrow::Cow::Owned(arg.reflect_type_path().to_string());
Ok(arg
.try_downcast_mut()
.ok_or_else(|| ArgError::UnexpectedType {
index: self.index,
expected: alloc::borrow::Cow::Borrowed(T::type_path()),
received,
})?)
}
}
}
pub fn is<T: TypePath>(&self) -> bool {
self.value
.try_as_reflect()
.map(<dyn Reflect>::is::<T>)
.unwrap_or_default()
}
}
#[derive(Debug)]
pub enum ArgValue<'a> {
Owned(Box<dyn PartialReflect>),
Ref(&'a dyn PartialReflect),
Mut(&'a mut dyn PartialReflect),
}
impl<'a> Deref for ArgValue<'a> {
type Target = dyn PartialReflect;
fn deref(&self) -> &Self::Target {
match self {
ArgValue::Owned(arg) => arg.as_ref(),
ArgValue::Ref(arg) => *arg,
ArgValue::Mut(arg) => *arg,
}
}
}