use crate::value::{Iter, Object, RefValue, RefValueIter};
use crate::{Context, Error};
extern crate self as tokay;
#[derive(Clone)]
pub struct MethodIter {
pub object: RefValue, pub object_method: &'static str, pub index: Option<RefValue>, pub index_op: &'static str, }
impl MethodIter {
pub fn new(object: RefValue) -> Iter {
Self::new_method_iter(object, "get_item", None, "iinc")
}
pub fn new_method_iter(
object: RefValue,
object_method: &'static str,
index: Option<RefValue>,
index_op: &'static str,
) -> Iter {
Iter::new(Box::new(Self {
object: object.clone(),
object_method,
index: index.or_else(|| Some(tokay::value!(0))),
index_op,
}))
}
}
impl RefValueIter for MethodIter {
fn next(&mut self, context: Option<&mut Context>) -> Option<RefValue> {
if let Some(index) = &self.index {
match self
.object
.call_method(self.object_method, context, vec![index.clone()])
{
Ok(Some(next)) => {
if !next.is_void() {
self.index = Some(index.clone().unary_op(self.index_op).unwrap());
return Some(next);
}
}
_ => {
if !index.is_true() {
self.index = None; return Some(self.object.clone());
}
}
}
self.index = None; }
None
}
fn repr(&self) -> String {
if let Some(index) = &self.index {
format!(
"<MethodIter on {}_{} at {}, using {}>",
self.object.name(),
self.object_method,
index.repr(),
self.index_op,
)
} else {
format!(
"<MethodIter on {}_{} finished, used {}>",
self.object.name(),
self.object_method,
self.index_op,
)
}
}
fn rev(&mut self) -> Result<(), Error> {
match self.index_op {
"iinc" => {
self.index_op = "idec";
if self.object.is("str") {
self.index = Some(tokay::value!(-1));
Ok(())
} else {
match self
.object
.call_method("len", None, Vec::new())
.unwrap_or_else(|_| Some(tokay::value!(1)))
{
Some(len) => {
self.index = Some(len.unary_op(self.index_op)?);
Ok(())
}
None => Err(Error::from("This iterator cannot be reversed.")),
}
}
}
"idec" => {
self.index_op = "iinc";
self.index = Some(tokay::value!(0));
Ok(())
}
_ => Err(Error::from("This iterator cannot be reversed.")),
}
}
}