1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
//! Abstraction of types implementing RefValueIter into an `iter` object.
use crate::value::{MethodIter, Object, RefValue, Value};
use crate::{Context, Error};
use tokay_macros::tokay_method;
extern crate self as tokay;

// BoxedRefValueIter type
type BoxedRefValueIter = Box<dyn RefValueIter>;

/// CloneBoxedRefValueIter is used internally to allow for dyn RefValueIter + Clone
pub trait CloneBoxedRefValueIter {
    fn dyn_clone(&self) -> BoxedRefValueIter;
}

impl<T> CloneBoxedRefValueIter for T
where
    T: 'static + RefValueIter + Clone,
{
    fn dyn_clone(&self) -> BoxedRefValueIter {
        Box::new(self.clone())
    }
}

impl Clone for BoxedRefValueIter {
    fn clone(&self) -> Self {
        self.dyn_clone()
    }
}

/// RefValueIter is a trait for iterators generating RefValues, which can optionally be reversed.
pub trait RefValueIter: CloneBoxedRefValueIter {
    fn next(&mut self, context: Option<&mut Context>) -> Option<RefValue>;
    fn repr(&self) -> String;
    fn rev(&mut self) -> Result<(), Error> {
        Err(Error::from("This iterator cannot be reversed."))
    }
}

/// Iter implementing Object to be used as RefValue
#[derive(Clone)]
pub struct Iter {
    pub iter: BoxedRefValueIter,
}

impl Iter {
    pub fn new(iter: BoxedRefValueIter) -> Self {
        return Self { iter };
    }

    tokay_method!("iter : @value", {
        // If parameter is already an iterator, just return it
        if value.is("iter") || value.is_void() {
            Ok(value)
        }
        // Check for an available iter() method on the provided value first
        else if let Ok(Some(iter)) = value.call_method("iter", context, Vec::new()) {
            Ok(iter)
        }
        // Default fallback to Iter on the object
        else {
            Ok(RefValue::from(MethodIter::new(value)))
        }
    });

    tokay_method!("iter_next : @iter", {
        let mut iter = iter.borrow_mut();

        if let Some(iter) = iter.object_mut::<Iter>() {
            Ok(RefValue::from(
                iter.iter
                    .next(context)
                    .unwrap_or_else(|| tokay::value!(void)),
            ))
        } else {
            Err(Error::from(format!(
                "{} only accepts '{}' as parameter, not '{}'",
                __function,
                "iter",
                iter.name()
            )))
        }
    });

    tokay_method!("iter_len : @iter", {
        let mut iter = iter.borrow_mut();

        Ok(RefValue::from(
            if let Some(iter) = iter.object_mut::<Iter>() {
                iter.count()
            } else {
                1
            },
        ))
    });

    tokay_method!("iter_rev : @iter", {
        {
            let mut iter = iter.borrow_mut();

            if let Some(iter) = iter.object_mut::<Iter>() {
                iter.iter.rev()?;
            } else {
                return Err(Error::from(format!(
                    "{} only accepts '{}' as parameter, not '{}'",
                    __function,
                    "iter",
                    iter.name()
                )));
            }
        }

        Ok(iter)
    });

    tokay_method!("iter_collect : @iter", {
        let mut iter = iter.borrow_mut();

        if let Some(iter) = iter.object_mut::<Iter>() {
            let mut context = context;
            let mut list = Vec::new();

            while let Some(item) = iter.iter.next(context.as_deref_mut()) {
                list.push(item);
            }

            Ok(RefValue::from(list))
        } else {
            return Err(Error::from(format!(
                "{} only accepts '{}' as parameter, not '{}'",
                __function,
                "iter",
                iter.name()
            )));
        }
    });
}

impl Iterator for Iter {
    type Item = RefValue;

    fn next(&mut self) -> Option<Self::Item> {
        self.iter.next(None)
    }
}

impl Object for Iter {
    fn name(&self) -> &'static str {
        "iter"
    }

    fn repr(&self) -> String {
        self.iter.repr()
    }
}

impl std::fmt::Debug for Iter {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.repr())
    }
}

impl PartialEq for Iter {
    fn eq(&self, other: &Self) -> bool {
        self.id() == other.id()
    }
}

impl PartialOrd for Iter {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        self.id().partial_cmp(&other.id())
    }
}

impl From<Iter> for RefValue {
    fn from(iter: Iter) -> Self {
        Value::Object(Box::new(iter)).into()
    }
}