Created
April 19, 2019 10:19
-
-
Save DutchGhost/5a6712f3d8b611ccbed6a9f120929e90 to your computer and use it in GitHub Desktop.
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
use std::{ | |
ops::{Generator, GeneratorState}, | |
pin::Pin, | |
}; | |
/// A wrapper struct around Generators, | |
/// providing a safe implementation of the [`Iterator`] trait. | |
pub struct GenIter<G>(Option<G>); | |
impl<G: Generator + Unpin> GenIter<G> { | |
/// Creates a new `GenIter` instance from a generator. | |
/// The returned instance can be iterated over, | |
/// consuming the generator. | |
#[inline] | |
pub fn new(gen: G) -> Self { | |
Self(Some(gen)) | |
} | |
} | |
impl<G: Generator + Unpin> Iterator for GenIter<G> { | |
type Item = G::Yield; | |
#[inline] | |
fn next(&mut self) -> Option<Self::Item> { | |
Pin::new(self).next() | |
} | |
} | |
impl<G: Generator> GenIter<G> { | |
/// Creates a new `GenIter` instance from a generator. | |
/// | |
/// The returned instance can be iterated over, | |
/// consuming the generator. | |
/// | |
/// # Safety | |
/// This function is marked unsafe, | |
/// because the caller must ensure the generator is in a valid state. | |
/// A valid state means that the generator has not been moved ever since it's creation. | |
#[inline] | |
pub unsafe fn new_unchecked(gen: G) -> Self { | |
Self(Some(gen)) | |
} | |
/// Creates a new `GenIter` instance from a Pinned, Boxed generator. | |
/// Te returned instance can be iterated over, | |
/// consuming the generator. | |
#[inline] | |
pub fn pinned(gen: Pin<Box<G>>) -> GenIter<Pin<Box<G>>> { | |
Self(Some(gen)) | |
} | |
} | |
impl<G: Generator> Iterator for Pin<&mut GenIter<G>> { | |
type Item = G::Yield; | |
fn next(&mut self) -> Option<Self::Item> { | |
let this: Pin<&mut GenIter<G>> = self.as_mut(); | |
// This should be safe. | |
// this Iterator implementation is on a Pin<&mut GenIter<G>> where G: Generator. | |
// In order to acquire such a Pin<&mut GenIter<G>> if G does *NOT* implement Unpin, | |
// the unsafe `new_unchecked` function from the Pin type must be used anyway. | |
// | |
// Note that if G: Unpin, the Iterator implementation of GenIter<G> itself is used, | |
// which just creates a Pin safely, and then delegates to this implementation. | |
let gen: Pin<&mut Option<G>> = unsafe { this.map_unchecked_mut(|geniter| &mut geniter.0) }; | |
let gen: Option<Pin<&mut G>> = Option::as_pin_mut(gen); | |
match gen.map(Generator::resume) { | |
Some(GeneratorState::Yielded(y)) => Some(y), | |
Some(GeneratorState::Complete(_)) => { | |
self.set(GenIter(None)); | |
None | |
} | |
None => None, | |
} | |
} | |
} | |
/// Creates a new instance of a `GenIter` with the provided generator `$x`. | |
/// # Examples | |
/// ``` | |
/// #![feature(generators, generator_trait)] | |
/// | |
/// let mut iter = gen_iter! { | |
/// let x = 10; | |
/// let r = &x; | |
/// | |
/// for i in 0..5u32 { | |
/// yield i * *r | |
/// } | |
/// }; | |
/// ``` | |
#[macro_export] | |
macro_rules! gen_iter { | |
($($x:tt)*) => { | |
// Safe, the Generator is directly passed into new_unchecked, | |
// so it has not been moved | |
unsafe { | |
$crate::iter::GenIter::new_unchecked(static || { | |
$($x)* | |
}) | |
} | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment