pub mod gen { use std::marker::PhantomData; #[cfg_attr(std, lang = "yield")] pub enum Yield<T, R> { Value(T), Return(R) } #[cfg_attr(std, lang = "generator_base")] pub trait GeneratorBase { type Value; type Return; } fn type_name<T: ?Sized>() -> &'static str { "<unknown>" /*unsafe { ::std::intrinsics::type_name::<T>() }*/ } #[cfg_attr(std, lang = "generator")] pub trait Generator<Input>: GeneratorBase { fn next(&mut self, _: Input) -> Yield<Self::Value, Self::Return> { panic!("generator `{}` does not take `{}` as input", type_name::<Self>(), type_name::<Input>()) } } #[cfg(std)] impl<G: Generator<(), Return=()>> Iterator for G { type Item = G::Value; fn next(&mut self) -> Option<G::Value> { match self.next(()) { Yield::Value(x) => Some(x), Yield::Return(_) => None } } } pub trait Generate { type G: GeneratorBase; /// Run up to the first yield, return that and the generator. fn generate(self) -> Yield<(<Self::G as GeneratorBase>::Value, Self::G), <Self::G as GeneratorBase>::Return>; } pub struct YieldAnd<V, G>(pub V, pub G); impl<V, G: GeneratorBase<Value = V>> Generate for YieldAnd<V, G> { type G = G; fn generate(self) -> Yield<(V, G), G::Return> { Yield::Value((self.0, self.1)) } } pub struct Mirror<V, R> { _data: PhantomData<(V, R)> } impl<V, R> Mirror<V, R> { pub fn new() -> Mirror<V, R> { Mirror { _data: PhantomData } } } impl<V, R> GeneratorBase for Mirror<V, R> { type Value = V; type Return = R; } impl<V, R> Generator<R> for Mirror<V, R> { fn next(&mut self, value: R) -> Yield<V, R> { Yield::Return(value) } } pub type YieldAndMirror<V, R> = YieldAnd<V, Mirror<V, R>>; } pub mod io { use gen::{Generate, GeneratorBase, Yield}; use fs; pub use std::io::{Error, Result}; pub enum Action { File(fs::File, fs::Action) } pub trait Async<R>: Generate where Self::G: GeneratorBase<Value=Action, Return=Result<R>> + fs::Async { fn run_sync(self) -> Result<R> where Self: Sized { match self.generate() { Yield::Value((mut action, mut gen)) => { loop { match Self::do_io(&mut gen, action) { Yield::Value(next) => action = next, Yield::Return(res) => return res }; } } Yield::Return(res) => res } } fn do_io(gen: &mut Self::G, action: Action) -> Yield<Action, Result<R>> { match action { Action::File(file, action) => fs::Async::do_file(gen, file, action) } } } impl<T: Generate, R> Async<R> for T where T::G: GeneratorBase<Value=Action, Return=Result<R>> + fs::Async {} macro_rules! await { ($x:expr) => (try!(yield+ $x)) } } pub mod fs { use gen::{Generator, Mirror, Yield, YieldAnd, YieldAndMirror}; use io; use std::fs as sync; use std::io::prelude::*; use std::os::unix::prelude::*; use std::path::Path; pub struct File { sync: sync::File } pub use std::fs::Metadata; impl File { pub fn open<P: AsRef<Path>>(path: P) -> io::Result<File> { sync::File::open(path).map(|file| File { sync: file }) } pub fn create<P: AsRef<Path>>(path: P) -> io::Result<File> { sync::File::create(path).map(|file| File { sync: file }) } } impl Clone for File { fn clone(&self) -> File { extern "C" { fn dup(fd: i32) -> i32; } File { sync: unsafe { sync::File::from_raw_fd(dup(self.sync.as_raw_fd())) } } } } pub enum Action { Read(Vec<u8>), Write(Vec<u8>), GetMetadata } pub trait Async: Generator<io::Result<Vec<u8>>> + Generator<io::Result<sync::Metadata>> { fn do_file(&mut self, mut file: File, action: Action) -> Yield<Self::Value, Self::Return> { match action { Action::Read(mut buffer) => { // Nasty zero-fill because read takes &mut [u8]. let extra = buffer.capacity() - buffer.len(); buffer.extend((0..extra).map(|_| 0)); self.next(file.sync.read(&mut buffer).map(|bytes| { buffer.truncate(bytes); buffer })) } Action::Write(buffer) => { self.next(file.sync.write(&buffer).map(|_| buffer)) } Action::GetMetadata => { self.next(file.sync.metadata()) } } } } impl<G> Async for G where G: Generator<io::Result<Vec<u8>>> + Generator<io::Result<Metadata>> {} macro_rules! action { ($fun:ident => $act:ident -> $ret:ty) => { pub fn $fun(&self) -> YieldAndMirror<io::Action, io::Result<$ret>> { YieldAnd(io::Action::File(self.clone(), Action::$act), Mirror::new()) } }; ($fun:ident => $act:ident($($arg:ident: $ty:ty),+) -> $ret:ty) => { pub fn $fun(&self, $($arg: $ty),+) -> YieldAndMirror<io::Action, io::Result<$ret>> { YieldAnd(io::Action::File(self.clone(), Action::$act($($arg),+)), Mirror::new()) } } } impl File { action!(read => Read(buffer: Vec<u8>) -> Vec<u8>); action!(write => Write(buffer: Vec<u8>) -> Vec<u8>); action!(metadata => GetMetadata -> Metadata); } }