Skip to content

Commit 323e477

Browse files
committed
Introduce an Iterator type to deal with the iterator interfaces
1 parent 8b9af4f commit 323e477

File tree

10 files changed

+391
-158
lines changed

10 files changed

+391
-158
lines changed
+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
use rune::testing::*;
2+
3+
#[test]
4+
fn test_range_iter() {
5+
let values = rune!(Vec<i64> =>
6+
use std::iter::range;
7+
8+
pub fn main() {
9+
range(0, 100).map(|n| n * 2).filter(|n| n % 3 == 0).collect_vec()
10+
}
11+
);
12+
13+
assert_eq!(
14+
values,
15+
(0..100)
16+
.map(|n| n * 2)
17+
.filter(|n| n % 3 == 0)
18+
.collect::<Vec<i64>>()
19+
);
20+
}
21+
22+
#[test]
23+
fn test_rev() {
24+
let values = rune!(Vec<i64> =>
25+
use std::iter::range;
26+
27+
pub fn main() {
28+
range(0, 100).map(|n| n * 2).filter(|n| n % 3 == 0).rev().collect_vec()
29+
}
30+
);
31+
32+
assert_eq!(
33+
values,
34+
(0..100)
35+
.map(|n| n * 2)
36+
.filter(|n| n % 3 == 0)
37+
.rev()
38+
.collect::<Vec<i64>>()
39+
);
40+
}
41+
42+
#[test]
43+
fn test_next_back() {
44+
rune! {() =>
45+
const SOURCE = [1, 2, 3, "foo"];
46+
47+
pub fn main() {
48+
let it = SOURCE.iter().rev();
49+
let v = Vec::new();
50+
51+
while let Some(n) = it.next_back() {
52+
v.push(n);
53+
}
54+
55+
assert_eq!(v, SOURCE);
56+
}
57+
};
58+
}
59+
60+
#[test]
61+
fn test_object_rev_error() {
62+
assert_vm_error!(
63+
r#"pub fn main() { #{}.iter().rev() }"#,
64+
Panic { reason } => {
65+
assert_eq!(reason.to_string(), "`std::object::Iter` is not a double-ended iterator");
66+
}
67+
);
68+
}

crates/rune/tests/test_all/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ mod compiler_use;
99
mod compiler_visibility;
1010
mod compiler_warnings;
1111
mod core_macros;
12+
mod iterator;
1213
mod moved;
1314
mod vm_arithmetic;
1415
mod vm_assign_exprs;

crates/runestick/src/iterator.rs

+280
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,280 @@
1+
use crate::{FromValue, Function, ToValue, Value, VmError};
2+
use std::iter;
3+
use std::vec;
4+
5+
/// An owning iterator.
6+
pub struct Iterator {
7+
inner: Inner,
8+
}
9+
10+
crate::__internal_impl_any!(Iterator);
11+
12+
impl Iterator {
13+
/// Construct a new owning iterator.
14+
///
15+
/// The name is only intended to identify the iterator in case of errors.
16+
pub fn from<T>(name: &'static str, iter: T) -> Self
17+
where
18+
T: IteratorTrait,
19+
{
20+
Self {
21+
inner: Inner::Iterator(Box::new(IteratorObj { name, iter })),
22+
}
23+
}
24+
25+
/// Construct a new double-ended owning iterator, with a human-readable
26+
/// name.
27+
///
28+
/// The name is only intended to identify the iterator in case of errors.
29+
pub fn from_double_ended<T>(name: &'static str, iter: T) -> Self
30+
where
31+
T: DoubleEndedIteratorTrait,
32+
{
33+
Self {
34+
inner: Inner::DoubleEndedIterator(Box::new(IteratorObj { name, iter })),
35+
}
36+
}
37+
38+
/// Get the size hint for the iterator.
39+
pub fn size_hint(&self) -> (usize, Option<usize>) {
40+
self.inner.size_hint()
41+
}
42+
43+
/// Get the next value out of the iterator.
44+
pub fn next(&mut self) -> Result<Option<Value>, VmError> {
45+
self.inner.next()
46+
}
47+
48+
/// Get the next back value out of the iterator.
49+
pub fn next_back(&mut self) -> Result<Option<Value>, VmError> {
50+
self.inner.next_back()
51+
}
52+
53+
/// Map the iterator using the given function.
54+
pub fn map(self, map: Function) -> Self {
55+
Self {
56+
inner: Inner::Map(Box::new(Map {
57+
inner: self.inner,
58+
map,
59+
})),
60+
}
61+
}
62+
63+
/// Filter the iterator using the given function.
64+
pub fn filter(self, filter: Function) -> Self {
65+
Self {
66+
inner: Inner::Filter(Box::new(Filter {
67+
inner: self.inner,
68+
filter,
69+
})),
70+
}
71+
}
72+
73+
/// Map the iterator using the given function.
74+
pub fn rev(self) -> Result<Self, VmError> {
75+
if !self.inner.is_double_ended() {
76+
let name = self.inner.name();
77+
78+
return Err(VmError::panic(format!(
79+
"`{}` is not a double-ended iterator",
80+
name
81+
)));
82+
}
83+
84+
Ok(Self {
85+
inner: match self.inner {
86+
// NB: reversing a reversed iterator restores the original
87+
// iterator.
88+
Inner::Rev(inner) => *inner,
89+
inner => Inner::Rev(Box::new(inner)),
90+
},
91+
})
92+
}
93+
94+
/// Collect results from the iterator.
95+
pub fn collect<T>(mut self) -> Result<vec::Vec<T>, VmError>
96+
where
97+
T: FromValue,
98+
{
99+
let (cap, _) = self.inner.size_hint();
100+
let mut vec = vec::Vec::with_capacity(cap);
101+
102+
while let Some(value) = self.next()? {
103+
vec.push(T::from_value(value)?);
104+
}
105+
106+
Ok(vec)
107+
}
108+
}
109+
110+
enum Inner {
111+
Iterator(Box<IteratorObj<dyn IteratorTrait>>),
112+
DoubleEndedIterator(Box<IteratorObj<dyn DoubleEndedIteratorTrait>>),
113+
Map(Box<Map>),
114+
Filter(Box<Filter>),
115+
Rev(Box<Inner>),
116+
}
117+
118+
impl Inner {
119+
/// Test if this iterator is double-ended.
120+
fn name(&self) -> &'static str {
121+
match self {
122+
Inner::Iterator(iter) => iter.name,
123+
Inner::DoubleEndedIterator(iter) => iter.name,
124+
Inner::Map(map) => map.inner.name(),
125+
Inner::Filter(filter) => filter.inner.name(),
126+
Inner::Rev(inner) => inner.name(),
127+
}
128+
}
129+
130+
/// Test if this iterator is double-ended.
131+
fn is_double_ended(&self) -> bool {
132+
match self {
133+
Inner::Iterator(..) => false,
134+
Inner::DoubleEndedIterator(..) => true,
135+
Inner::Map(map) => map.inner.is_double_ended(),
136+
Inner::Filter(filter) => filter.inner.is_double_ended(),
137+
Inner::Rev(..) => true,
138+
}
139+
}
140+
141+
/// The length of the remaining iterator.
142+
fn size_hint(&self) -> (usize, Option<usize>) {
143+
match self {
144+
Inner::Iterator(iter) => iter.iter.size_hint(),
145+
Inner::DoubleEndedIterator(iter) => iter.iter.size_hint(),
146+
Inner::Map(map) => map.inner.size_hint(),
147+
Inner::Filter(filter) => filter.inner.size_hint(),
148+
Inner::Rev(inner) => inner.size_hint(),
149+
}
150+
}
151+
152+
fn next(&mut self) -> Result<Option<Value>, VmError> {
153+
match self {
154+
Self::Iterator(owned) => owned.iter.next(),
155+
Self::DoubleEndedIterator(owned) => owned.iter.next(),
156+
Self::Map(map) => map.advance(Self::next),
157+
Self::Filter(filter) => filter.advance(Self::next),
158+
Self::Rev(rev) => rev.next_back(),
159+
}
160+
}
161+
162+
fn next_back(&mut self) -> Result<Option<Value>, VmError> {
163+
match self {
164+
Self::Iterator(iter) => {
165+
return Err(VmError::panic(format!(
166+
"`{}` is not a double-ended iterator",
167+
iter.name
168+
)));
169+
}
170+
Self::DoubleEndedIterator(owned) => owned.iter.next_back(),
171+
Self::Map(map) => map.advance(Self::next_back),
172+
Self::Filter(filter) => filter.advance(Self::next_back),
173+
Self::Rev(rev) => rev.next(),
174+
}
175+
}
176+
}
177+
178+
struct Map {
179+
inner: Inner,
180+
map: Function,
181+
}
182+
183+
impl Map {
184+
fn advance(
185+
&mut self,
186+
advance: impl FnOnce(&mut Inner) -> Result<Option<Value>, VmError>,
187+
) -> Result<Option<Value>, VmError> {
188+
if let Some(value) = advance(&mut self.inner)? {
189+
let out = self.map.call::<_, Value>((value,))?;
190+
return Ok(Some(out));
191+
}
192+
193+
Ok(None)
194+
}
195+
}
196+
197+
struct Filter {
198+
inner: Inner,
199+
filter: Function,
200+
}
201+
202+
impl Filter {
203+
fn advance(
204+
&mut self,
205+
advance: impl Fn(&mut Inner) -> Result<Option<Value>, VmError>,
206+
) -> Result<Option<Value>, VmError> {
207+
while let Some(value) = advance(&mut self.inner)? {
208+
if self.filter.call::<_, bool>((value.clone(),))? {
209+
return Ok(Some(value));
210+
}
211+
}
212+
213+
Ok(None)
214+
}
215+
}
216+
217+
/// The trait for interacting with an iterator.
218+
///
219+
/// This has a blanket implementation, and is primarily used to restrict the
220+
/// arguments that can be used in [Iterator::from_iterator].
221+
pub trait IteratorTrait: 'static {
222+
/// Size hint of the iterator.
223+
fn size_hint(&self) -> (usize, Option<usize>);
224+
225+
/// Get the next value out of the iterator.
226+
fn next(&mut self) -> Result<Option<Value>, VmError>;
227+
}
228+
229+
impl<T> IteratorTrait for T
230+
where
231+
T: 'static,
232+
T: iter::Iterator,
233+
T::Item: ToValue,
234+
{
235+
fn size_hint(&self) -> (usize, Option<usize>) {
236+
iter::Iterator::size_hint(self)
237+
}
238+
239+
fn next(&mut self) -> Result<Option<Value>, VmError> {
240+
let value = match iter::Iterator::next(self) {
241+
Some(value) => value,
242+
None => return Ok(None),
243+
};
244+
245+
Ok(Some(value.to_value()?))
246+
}
247+
}
248+
249+
/// The trait for interacting with an iterator.
250+
///
251+
/// This has a blanket implementation, and is primarily used to restrict the
252+
/// arguments that can be used in [Iterator::from_double_ended].
253+
pub trait DoubleEndedIteratorTrait: IteratorTrait {
254+
/// Get the next back value out of the iterator.
255+
fn next_back(&mut self) -> Result<Option<Value>, VmError>;
256+
}
257+
258+
impl<T> DoubleEndedIteratorTrait for T
259+
where
260+
T: 'static,
261+
T: iter::DoubleEndedIterator,
262+
T::Item: ToValue,
263+
{
264+
fn next_back(&mut self) -> Result<Option<Value>, VmError> {
265+
let value = match iter::DoubleEndedIterator::next_back(self) {
266+
Some(value) => value,
267+
None => return Ok(None),
268+
};
269+
270+
Ok(Some(value.to_value()?))
271+
}
272+
}
273+
274+
struct IteratorObj<T>
275+
where
276+
T: ?Sized,
277+
{
278+
name: &'static str,
279+
iter: T,
280+
}

crates/runestick/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ mod hash;
7575
mod id;
7676
mod inst;
7777
mod item;
78+
mod iterator;
7879
mod label;
7980
pub mod module;
8081
pub mod modules;
@@ -153,6 +154,7 @@ pub use self::generator::Generator;
153154
pub use self::generator_state::GeneratorState;
154155
pub use self::guarded_args::GuardedArgs;
155156
pub use self::id::Id;
157+
pub use self::iterator::Iterator;
156158
pub use self::label::{DebugLabel, Label};
157159
pub use self::module::{InstFnNameHash, Module};
158160
pub use self::named::Named;

0 commit comments

Comments
 (0)