use crate::{
func::{
args::{Arg, ArgValue, FromArg},
ArgError,
},
PartialReflect, Reflect, TypePath,
};
use alloc::{
boxed::Box,
collections::vec_deque::{Iter, VecDeque},
};
#[derive(Default, Debug)]
pub struct ArgList<'a> {
list: VecDeque<Arg<'a>>,
needs_reindex: bool,
}
impl<'a> ArgList<'a> {
pub fn new() -> Self {
Self {
list: VecDeque::new(),
needs_reindex: false,
}
}
pub fn push_arg(&mut self, arg: ArgValue<'a>) {
if self.needs_reindex {
for (index, arg) in self.list.iter_mut().enumerate() {
arg.set_index(index);
}
self.needs_reindex = false;
}
let index = self.list.len();
self.list.push_back(Arg::new(index, arg));
}
pub fn push_ref(&mut self, arg: &'a dyn PartialReflect) {
self.push_arg(ArgValue::Ref(arg));
}
pub fn push_mut(&mut self, arg: &'a mut dyn PartialReflect) {
self.push_arg(ArgValue::Mut(arg));
}
pub fn push_owned(&mut self, arg: impl PartialReflect) {
self.push_arg(ArgValue::Owned(Box::new(arg)));
}
pub fn push_boxed(&mut self, arg: Box<dyn PartialReflect>) {
self.push_arg(ArgValue::Owned(arg));
}
pub fn with_arg(mut self, arg: ArgValue<'a>) -> Self {
self.push_arg(arg);
self
}
pub fn with_ref(self, arg: &'a dyn PartialReflect) -> Self {
self.with_arg(ArgValue::Ref(arg))
}
pub fn with_mut(self, arg: &'a mut dyn PartialReflect) -> Self {
self.with_arg(ArgValue::Mut(arg))
}
pub fn with_owned(self, arg: impl PartialReflect) -> Self {
self.with_arg(ArgValue::Owned(Box::new(arg)))
}
pub fn with_boxed(self, arg: Box<dyn PartialReflect>) -> Self {
self.with_arg(ArgValue::Owned(arg))
}
pub fn take_arg(&mut self) -> Result<Arg<'a>, ArgError> {
self.needs_reindex = true;
self.list.pop_front().ok_or(ArgError::EmptyArgList)
}
pub fn take<T: FromArg>(&mut self) -> Result<T::This<'a>, ArgError> {
self.take_arg()?.take::<T>()
}
pub fn take_owned<T: Reflect + TypePath>(&mut self) -> Result<T, ArgError> {
self.take_arg()?.take_owned()
}
pub fn take_ref<T: Reflect + TypePath>(&mut self) -> Result<&'a T, ArgError> {
self.take_arg()?.take_ref()
}
pub fn take_mut<T: Reflect + TypePath>(&mut self) -> Result<&'a mut T, ArgError> {
self.take_arg()?.take_mut()
}
pub fn pop_arg(&mut self) -> Result<Arg<'a>, ArgError> {
self.list.pop_back().ok_or(ArgError::EmptyArgList)
}
pub fn pop<T: FromArg>(&mut self) -> Result<T::This<'a>, ArgError> {
self.pop_arg()?.take::<T>()
}
pub fn pop_owned<T: Reflect + TypePath>(&mut self) -> Result<T, ArgError> {
self.pop_arg()?.take_owned()
}
pub fn pop_ref<T: Reflect + TypePath>(&mut self) -> Result<&'a T, ArgError> {
self.pop_arg()?.take_ref()
}
pub fn pop_mut<T: Reflect + TypePath>(&mut self) -> Result<&'a mut T, ArgError> {
self.pop_arg()?.take_mut()
}
pub fn iter(&self) -> Iter<'_, Arg<'a>> {
self.list.iter()
}
pub fn len(&self) -> usize {
self.list.len()
}
pub fn is_empty(&self) -> bool {
self.list.is_empty()
}
}
#[cfg(test)]
mod tests {
use super::*;
use alloc::string::String;
#[test]
fn should_push_arguments_in_order() {
let args = ArgList::new()
.with_owned(123)
.with_owned(456)
.with_owned(789);
assert_eq!(args.len(), 3);
assert_eq!(args.list[0].index(), 0);
assert_eq!(args.list[1].index(), 1);
assert_eq!(args.list[2].index(), 2);
}
#[test]
fn should_push_arg_with_correct_ownership() {
let a = String::from("a");
let b = String::from("b");
let mut c = String::from("c");
let d = String::from("d");
let e = String::from("e");
let f = String::from("f");
let mut g = String::from("g");
let args = ArgList::new()
.with_arg(ArgValue::Owned(Box::new(a)))
.with_arg(ArgValue::Ref(&b))
.with_arg(ArgValue::Mut(&mut c))
.with_owned(d)
.with_boxed(Box::new(e))
.with_ref(&f)
.with_mut(&mut g);
assert!(matches!(args.list[0].value(), &ArgValue::Owned(_)));
assert!(matches!(args.list[1].value(), &ArgValue::Ref(_)));
assert!(matches!(args.list[2].value(), &ArgValue::Mut(_)));
assert!(matches!(args.list[3].value(), &ArgValue::Owned(_)));
assert!(matches!(args.list[4].value(), &ArgValue::Owned(_)));
assert!(matches!(args.list[5].value(), &ArgValue::Ref(_)));
assert!(matches!(args.list[6].value(), &ArgValue::Mut(_)));
}
#[test]
fn should_take_args_in_order() {
let a = String::from("a");
let b = 123_i32;
let c = 456_usize;
let mut d = 5.78_f32;
let mut args = ArgList::new()
.with_owned(a)
.with_ref(&b)
.with_ref(&c)
.with_mut(&mut d);
assert_eq!(args.len(), 4);
assert_eq!(args.take_owned::<String>().unwrap(), String::from("a"));
assert_eq!(args.take::<&i32>().unwrap(), &123);
assert_eq!(args.take_ref::<usize>().unwrap(), &456);
assert_eq!(args.take_mut::<f32>().unwrap(), &mut 5.78);
assert_eq!(args.len(), 0);
}
#[test]
fn should_pop_args_in_reverse_order() {
let a = String::from("a");
let b = 123_i32;
let c = 456_usize;
let mut d = 5.78_f32;
let mut args = ArgList::new()
.with_owned(a)
.with_ref(&b)
.with_ref(&c)
.with_mut(&mut d);
assert_eq!(args.len(), 4);
assert_eq!(args.pop_mut::<f32>().unwrap(), &mut 5.78);
assert_eq!(args.pop_ref::<usize>().unwrap(), &456);
assert_eq!(args.pop::<&i32>().unwrap(), &123);
assert_eq!(args.pop_owned::<String>().unwrap(), String::from("a"));
assert_eq!(args.len(), 0);
}
#[test]
fn should_reindex_on_push_after_take() {
let mut args = ArgList::new()
.with_owned(123)
.with_owned(456)
.with_owned(789);
assert!(!args.needs_reindex);
args.take_arg().unwrap();
assert!(args.needs_reindex);
assert!(args.list[0].value().reflect_partial_eq(&456).unwrap());
assert_eq!(args.list[0].index(), 1);
assert!(args.list[1].value().reflect_partial_eq(&789).unwrap());
assert_eq!(args.list[1].index(), 2);
let args = args.with_owned(123);
assert!(!args.needs_reindex);
assert!(args.list[0].value().reflect_partial_eq(&456).unwrap());
assert_eq!(args.list[0].index(), 0);
assert!(args.list[1].value().reflect_partial_eq(&789).unwrap());
assert_eq!(args.list[1].index(), 1);
assert!(args.list[2].value().reflect_partial_eq(&123).unwrap());
assert_eq!(args.list[2].index(), 2);
}
}