Created
February 20, 2014 02:19
-
-
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>`.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#[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); | |
} | |
)} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
===== 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