Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@chris-morgan
Created February 20, 2014 02:19
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chris-morgan/9105842 to your computer and use it in GitHub Desktop.
Save chris-morgan/9105842 to your computer and use it in GitHub Desktop.
A prototype of a `Result<T, E>`-based `Iterator<T, E>` replacing the `Option<T>`-based `Iterator<T>`.
#[feature(macro_rules)];
// There must be two variants of the macro for this simple prototype, each of
// them lacking one important feature and with one remaining feature completely
// infeasible in a macro_rules! macro. Done properly in the compiler these
// would be entirely reasonable.
// A variant with support for an output value from the else clause, but with no
// support for breaking out of the `for` block.
macro_rules! forr1 (
(for $p1:pat in $e1:expr $b1:expr else |$p2:pat| $b2:expr) => ({
// b1 and b2 should be block, but if they were then I would need to use
// `if true $b1` in the macro body and that would prevent non-() value.
// And sorry, but something must go between $p2 and $b2 or the latter's
// ``{`` may be perceived as part of the pattern
let mut e1 = $e1;
let mut out;
loop {
match e1.next2() {
Ok($p1) => $b1,
Err($p2) => {
out = $b2;
break;
},
}
}
out
})
)
// A variant with no support for an output value from the else clause, so that
// the `for` part *can* break.
macro_rules! forr2 (
(for $p1:pat in $e1:expr $b1:expr else |$p2:pat| $b2:expr) => ({
// b1 and b2 should be block, but if they were then I would need to use
// `if true $b1` in the macro body and that would prevent non-() value.
// And sorry, but something must go between $p2 and $b2 or the latter's
// ``{`` may be perceived as part of the pattern
let mut e1 = $e1;
loop {
match e1.next2() {
Ok($p1) => $b1,
Err($p2) => {
$b2;
break;
},
}
}
})
)
pub trait Iterator<T, E> {
fn next2(&mut self) -> Result<T, E>;
// Yeah, I've skipped size_hint and all the helper methods, and I haven't
// really considered the impact this would have on the helper methods and
// how they handle error types. I guess they'd need to have the same E
// until we get something like https://github.com/mozilla/rust/issues/8277.
}
/* I'd do this, but it would prevent other implementations of it
impl<T, I: ::std::iter::Iterator<T>> Iterator<T, ()> for I {
fn next2(&mut self) -> Result<T, ()> {
match self.next() {
Some(t) => Ok(t),
None => Err(()),
}
}
}*/
impl<A: Add<A, A> + Ord + Clone + ToPrimitive> Iterator<A, ()>
for ::std::iter::Range<A> {
fn next2(&mut self) -> Result<A, ()> {
match self.next() {
Some(a) => Ok(a),
None => Err(()),
}
}
}
fn main() {
println!("===== DEMO 1 =====");
demo1();
println!("===== DEMO 2 =====");
demo2();
println!("===== DEMO 3 =====");
demo3();
println!("====== DONE ======");
}
fn demo1() {
println!("That there for loop's else clause returned {}", forr1!(
for x in range(1, 3) {
println!("x = {}", x);
// Theoretically, `break 9;` would work here, provided the value is
// the same type as the else block's type. (A simple `break;` will
// of course *not* work when the else branch evaluates to non-().)
// In practice, tweaking the macro to allow it is… rather complex.
} else |()| {
println!("You didn't break!");
42
}
));
}
struct X {
steps: int,
value: int,
}
struct Done(int);
impl Iterator<int, Done> for X {
fn next2(&mut self) -> Result<int, Done> {
if self.steps == self.value {
Err(Done(self.steps))
} else {
self.value += 1;
Ok(self.value)
}
}
}
fn demo2() {forr2!(
for x in X { steps: 4, value: 1 } {
println!("x = {}", x);
if x == 3 {
println!("Breaking early");
break;
}
} else |Done(n)| {
println!("Iteration finished at {}", n);
}
)}
fn demo3() {forr2!(
for x in X { steps: 4, value: 1 } {
println!("x = {}", x);
} else |Done(n)| {
println!("Iteration finished at {}", n);
}
)}
===== DEMO 1 =====
x = 1
x = 2
You didn't break!
That there for loop's else clause returned 42
===== DEMO 2 =====
x = 2
x = 3
Breaking early
===== DEMO 3 =====
x = 2
x = 3
x = 4
Iteration finished at 4
====== DONE ======
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment