{"id":13995401,"url":"https://github.com/Hexilee/async-io-demo","last_synced_at":"2025-07-22T21:32:55.059Z","repository":{"id":105871888,"uuid":"160719215","full_name":"Hexilee/async-io-demo","owner":"Hexilee","description":"demo for rust asynchronous io: from mio to stackless coroutine","archived":false,"fork":false,"pushed_at":"2021-03-04T02:05:50.000Z","size":145,"stargazers_count":349,"open_issues_count":0,"forks_count":19,"subscribers_count":11,"default_branch":"master","last_synced_at":"2024-04-04T18:34:38.343Z","etag":null,"topics":["async-await","asynchronous","coroutine","rust"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Hexilee.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2018-12-06T19:04:35.000Z","updated_at":"2024-04-02T14:59:05.000Z","dependencies_parsed_at":"2023-04-22T13:03:36.296Z","dependency_job_id":null,"html_url":"https://github.com/Hexilee/async-io-demo","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Hexilee%2Fasync-io-demo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Hexilee%2Fasync-io-demo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Hexilee%2Fasync-io-demo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Hexilee%2Fasync-io-demo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Hexilee","download_url":"https://codeload.github.com/Hexilee/async-io-demo/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":214675555,"owners_count":15768175,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["async-await","asynchronous","coroutine","rust"],"created_at":"2024-08-09T14:03:23.219Z","updated_at":"2024-08-09T14:16:22.537Z","avatar_url":"https://github.com/Hexilee.png","language":"Rust","funding_links":[],"categories":["Rust"],"sub_categories":[],"readme":"Table of Contents\n=================\n\n* [Introduction](#introduction)\n* [mio: The Footstone of Asynchronous IO](#mio-the-footstone-of-asynchronous-io)\n    * [Asynchronous Network IO](#asynchronous-network-io)\n    * [Spurious Events](#spurious-events)\n    * [Poll Option](#poll-option)\n    * [Still Block](#still-block)\n    * [Custom Event](#custom-event)\n    * [Callback is Evil](#callback-is-evil)\n* [stackless coroutine](#stackless-coroutine)\n    * [generator](#generator)\n    * [self-referential structs](#self-referential-structs)\n        * [Pin](#pin)\n    * [Reasonable Abstraction](#reasonable-abstraction)\n        * [Poll\u0026lt;T\u0026gt;](#pollt)\n        * [await](#await)\n        * [async](#async)\n    * [non-blocking coroutine](#non-blocking-coroutine)\n        * [Executor](#executor)\n        * [block_on](#block_on)\n        * [spawn](#spawn)\n        * [TcpListener](#tcplistener)\n        * [TcpStream](#tcpstream)\n        * [echo server](#echo-server)\n* [Afterword](#afterword)\n\n\n\n### Introduction\n\n2019 is approaching. The rust team keeps their promise about asynchronous IO: `async` is introduced as keywords, `Pin, Future, Poll` and `await` is introduced into standard library. \n\nI have never used rust for asynchronous IO programming earlier, so I almost know nothing about it. However, I would use it for a project recently but couldn't find many documents that are remarkably helpful for newbie of rust asynchronous programming.\n\nEventually, I wrote several demo and implemented simple asynchronous IO based on `mio` and `coroutine` with the help of both of this blog ([Tokio internals: Understanding Rust's asynchronous I/O framework from the bottom up](https://cafbit.com/post/tokio_internals/)) and source code of \"new tokio\" [romio](https://github.com/withoutboats/romio) .\n\nThis is the final file server:\n\n```rust\n// examples/file-server.rs\n\n#[macro_use]\nextern crate log;\n\nuse asyncio::executor::{block_on, spawn, TcpListener, TcpStream};\nuse asyncio::fs_future::{read_to_string};\nuse failure::Error;\n\nfn main() -\u003e Result\u003c(), Error\u003e {\n    env_logger::init();\n    block_on(new_server())?\n}\n\n\nconst CRLF: \u0026[char] = \u0026['\\r', '\\n'];\n\nasync fn new_server() -\u003e Result\u003c(), Error\u003e {\n    let mut listener = TcpListener::bind(\u0026\"127.0.0.1:7878\".parse()?)?;\n    info!(\"Listening on 127.0.0.1:7878\");\n    while let Ok((stream, addr)) = listener.accept().await {\n        info!(\"connection from {}\", addr);\n        spawn(handle_stream(stream))?;\n    }\n    Ok(())\n}\n\nasync fn handle_stream(mut stream: TcpStream) -\u003e Result\u003c(), Error\u003e {\n    stream.write_str(\"Please enter filename: \").await?;\n    let file_name_vec = stream.read().await?;\n    let file_name = String::from_utf8(file_name_vec)?.trim_matches(CRLF).to_owned();\n    let file_contents = read_to_string(file_name).await?;\n    stream.write_str(\u0026file_contents).await?;\n    stream.close();\n    Ok(())\n}\n\n```\n\nMy purpose of writing this blog is to review and summarize, I will be happy if it can help someone who are interested in rust asynchronous programming. Given that the readability is the primary consideration when I wrote the code appearing in this blog, there may be some performance problem in code, please forgive me. If there are obvious problems in blog or code, you are welcome to point them up.\n\nMost of the code appearing in this blog is collected in this [repo](https://github.com/Hexilee/async-io-demo) (some code is too long, you had better clone and view it in editor), all examples work well at rustc-1.39`. \n\n\u003e When executing examples/async-echo, set environment variable `RUST_LOG=info` for basic runtime information; set `RUST_LOG=debug`  for events polling information.\n\n\n\n### mio: The Footstone of Asynchronous IO\n\n`mio` is a tidy, low-level asynchronous IO library. Nowadays, almost all asynchronous IO libraries in rust ecosystem are based on `mio`.\n\nAs sub modules like `channel, timer` have been marked as deprecated since version-0.6.5, `mio` provides only two core functions:\n\n- basic encapsulation for OS asynchronous network IO\n- custom events\n\nThe first core function corresponded to API in different OS respectively are:\n\n- Linux(Android) =\u003e epoll\n- Windows =\u003e iocp\n- MacOS(iOS), FreeBSD =\u003e kqueue\n- Fuchsia =\u003e \\\u003cunknow\u003e\n\n`mio` wraps different asynchronous network API in different OS into a common epoll-like asynchronous API, which supports both of `udp` and `tcp`.\n\n\u003e besides `udp` and `tcp`, `mio` also provides some OS-specific API, like `uds`, we won't talk about them, you can find the usage in source code of mio.\n\u003e\n\u003e\n\n\n\n#### Asynchronous Network IO\n\nThis is a demo of asynchronous tcp IO:\n\n```rust\n// examples/tcp.rs\n\nuse mio::*;\nuse mio::net::{TcpListener, TcpStream};\nuse std::io::{Read, Write, self};\nuse failure::Error;\nuse std::time::{Duration, Instant};\n\nconst SERVER_ACCEPT: Token = Token(0);\nconst SERVER: Token = Token(1);\nconst CLIENT: Token = Token(2);\nconst SERVER_HELLO: \u0026[u8] = b\"PING\";\nconst CLIENT_HELLO: \u0026[u8] = b\"PONG\";\n\nfn main() -\u003e Result\u003c(), Error\u003e {\n    let addr = \"127.0.0.1:13265\".parse()?;\n\n// Setup the server socket\n    let server = TcpListener::bind(\u0026addr)?;\n\n// Create a poll instance\n    let poll = Poll::new()?;\n\n// Start listening for incoming connections\n    poll.register(\u0026server, SERVER_ACCEPT, Ready::readable(),\n                  PollOpt::edge())?;\n\n// Setup the client socket\n    let mut client = TcpStream::connect(\u0026addr)?;\n\n    let mut server_handler = None;\n\n// Register the client\n    poll.register(\u0026client, CLIENT, Ready::readable() | Ready::writable(),\n                  PollOpt::edge())?;\n\n// Create storage for events\n    let mut events = Events::with_capacity(1024);\n\n    let start = Instant::now();\n    let timeout = Duration::from_millis(10);\n    'top: loop {\n        poll.poll(\u0026mut events, None)?;\n        for event in events.iter() {\n            if start.elapsed() \u003e= timeout {\n                break 'top\n            }\n            match event.token() {\n                SERVER_ACCEPT =\u003e {\n                    let (handler, addr) = server.accept()?;\n                    println!(\"accept from addr: {}\", \u0026addr);\n                    poll.register(\u0026handler, SERVER, Ready::readable() | Ready::writable(), PollOpt::edge())?;\n                    server_handler = Some(handler);\n                }\n\n                SERVER =\u003e {\n                    if event.readiness().is_writable() {\n                        if let Some(ref mut handler) = \u0026mut server_handler {\n                            match handler.write(SERVER_HELLO) {\n                                Ok(_) =\u003e {\n                                    println!(\"server wrote\");\n                                }\n                                Err(ref err) if err.kind() == io::ErrorKind::WouldBlock =\u003e continue,\n                                err =\u003e {\n                                    err?;\n                                }\n                            }\n                        }\n                    }\n                    if event.readiness().is_readable() {\n                        let mut hello = [0; 4];\n                        if let Some(ref mut handler) = \u0026mut server_handler {\n                            match handler.read_exact(\u0026mut hello) {\n                                Ok(_) =\u003e {\n                                    assert_eq!(CLIENT_HELLO, \u0026hello);\n                                    println!(\"server received\");\n                                }\n                                Err(ref err) if err.kind() == io::ErrorKind::WouldBlock =\u003e continue,\n                                err =\u003e {\n                                    err?;\n                                }\n                            }\n                        }\n                    }\n                }\n                CLIENT =\u003e {\n                    if event.readiness().is_writable() {\n                        match client.write(CLIENT_HELLO) {\n                            Ok(_) =\u003e {\n                                println!(\"client wrote\");\n                            }\n                            Err(ref err) if err.kind() == io::ErrorKind::WouldBlock =\u003e continue,\n                            err =\u003e {\n                                err?;\n                            }\n                        }\n                    }\n                    if event.readiness().is_readable() {\n                        let mut hello = [0; 4];\n                        match client.read_exact(\u0026mut hello) {\n                            Ok(_) =\u003e {\n                                assert_eq!(SERVER_HELLO, \u0026hello);\n                                println!(\"client received\");\n                            }\n                            Err(ref err) if err.kind() == io::ErrorKind::WouldBlock =\u003e continue,\n                            err =\u003e {\n                                err?;\n                            }\n                        }\n                    }\n                }\n                _ =\u003e unreachable!(),\n            }\n        }\n    };\n    Ok(())\n}\n```\n\n\n\nThis demo is a little long, let's talk about its main loop first:\n\n```rust\nfn main() {\n    // ...\n    loop {\n        poll.poll(\u0026mut events, None).unwrap();\n        // ...\n    }\n}\n```\n\nWe need call `Poll::poll` in each loop, the first parameter `events` is used for store events, we set it   with capacity 1024 here.\n\n```rust\nlet mut events = Events::with_capacity(1024);\n```\n\nThe type of second parameter `timeout` is `Option\u003cDuration\u003e`, method will return `Ok(usize)` when some events occur or timeout if `Some(duration) = timeout`. \n\n\u003e The usize in Ok refers to the number of events, this value is deprecated and will be removed in 0.7.0.\n\nHere we deliver `timeout = None` ，so when the method return without error, there must be some events. Let's traverse events:\n\n```rust\nmatch event.token() {\n      SERVER_ACCEPT =\u003e {\n          let (handler, addr) = server.accept()?;\n          println!(\"accept from addr: {}\", \u0026addr);\n          poll.register(\u0026handler, SERVER, Ready::readable() | Ready::writable(), PollOpt::edge())?;\n          server_handler = Some(handler);\n      }\n\n      SERVER =\u003e {\n          if event.readiness().is_writable() {\n              if let Some(ref mut handler) = \u0026mut server_handler {\n                  match handler.write(SERVER_HELLO) {\n                      Ok(_) =\u003e {\n                          println!(\"server wrote\");\n                      }\n                      Err(ref err) if err.kind() == io::ErrorKind::WouldBlock =\u003e continue,\n                      err =\u003e {\n                          err?;\n                      }\n                  }\n              }\n          }\n          if event.readiness().is_readable() {\n              let mut hello = [0; 4];\n              if let Some(ref mut handler) = \u0026mut server_handler {\n                  match handler.read_exact(\u0026mut hello) {\n                      Ok(_) =\u003e {\n                          assert_eq!(CLIENT_HELLO, \u0026hello);\n                          println!(\"server received\");\n                      }\n                      Err(ref err) if err.kind() == io::ErrorKind::WouldBlock =\u003e continue,\n                      err =\u003e {\n                          err?;\n                      }\n                  }\n              }\n          }\n      }\n      CLIENT =\u003e {\n          if event.readiness().is_writable() {\n              match client.write(CLIENT_HELLO) {\n                  Ok(_) =\u003e {\n                      println!(\"client wrote\");\n                  }\n                  Err(ref err) if err.kind() == io::ErrorKind::WouldBlock =\u003e continue,\n                  err =\u003e {\n                      err?;\n                  }\n              }\n          }\n          if event.readiness().is_readable() {\n              let mut hello = [0; 4];\n              match client.read_exact(\u0026mut hello) {\n                  Ok(_) =\u003e {\n                      assert_eq!(SERVER_HELLO, \u0026hello);\n                      println!(\"client received\");\n                  }\n                  Err(ref err) if err.kind() == io::ErrorKind::WouldBlock =\u003e continue,\n                  err =\u003e {\n                      err?;\n                  }\n              }\n          }\n      }\n      _ =\u003e unreachable!(),\n  }\n```\n\nWe need match token of each event, these tokens are just those we used to register. For example, we register `server` using token `SERVER_ACCEPT`.\n\n```rust\nconst SERVER_ACCEPT: Token = Token(0);\n\n...\n\n// Start listening for incoming connections\npoll.register(\u0026server, SERVER_ACCEPT, Ready::readable(),\n                  PollOpt::edge()).unwrap();\n```\n\nIn this case, when we find `event.token() == SERVER_ACCEPT`, we should think it's relevant to `server`, so we try to accept a new `TcpStream` and register it, using token `SERVER`:\n\n```rust\nlet (handler, addr) = server.accept()?;\nprintln!(\"accept from addr: {}\", \u0026addr);\npoll.register(\u0026handler, SERVER, Ready::readable() | Ready::writable(),       PollOpt::edge()).unwrap();\nserver_handler = Some(handler);\n```\n\nAs the same, if we find `event.token() == SERVER`，we should think it's relevant to `handler`:\n\n```rust\nif event.readiness().is_writable() {\n    if let Some(ref mut handler) = \u0026mut server_handler {\n        match handler.write(SERVER_HELLO) {\n            Ok(_) =\u003e {\n                println!(\"server wrote\");\n            }\n            Err(ref err) if err.kind() == io::ErrorKind::WouldBlock =\u003e continue,\n            err =\u003e {\n                err?;\n            }\n        }\n    }\n}\nif event.readiness().is_readable() {\n    let mut hello = [0; 4];\n    if let Some(ref mut handler) = \u0026mut server_handler {\n        match handler.read_exact(\u0026mut hello) {\n            Ok(_) =\u003e {\n                assert_eq!(CLIENT_HELLO, \u0026hello);\n                println!(\"server received\");\n            }\n            Err(ref err) if err.kind() == io::ErrorKind::WouldBlock =\u003e continue,\n            err =\u003e {\n                err?;\n            }\n        }\n    }\n}\n```\n\nIn this case, we shoud response differently to different `event.readiness()`, this is the third parameter of register, which named `interest`. As its name, `interest` means 'something you are interested', its type is `Ready`. `mio` support four kinds of `Ready`, `readable`, `writable`, `error` and `hup`, you can union them.\n\nWe register `handler`with `Ready::readable() | Ready::writable()`, so event can be `readable` or `writable` or both, you can see it in control flow: \n\nusing\n\n```rust\nif event.readiness().is_writable() {\n    ...\n}\n\nif event.readiness().is_readable() {\n    ...\n}\n```\n\ninstead of\n\n```rust\nif event.readiness().is_writable() {\n    ...\n} else if event.readiness().is_readable() {\n    ...\n}\n```\n\n#### Spurious Events\n\nThe code for dealing with event `SERVER_ACCEPT` above is:\n\n```rust\nmatch event.token() {\n     SERVER_ACCEPT =\u003e {\n         let (handler, addr) = server.accept()?;\n         println!(\"accept from addr: {}\", \u0026addr);\n         poll.register(\u0026handler, SERVER, Ready::readable() | Ready::writable(), PollOpt::edge()).unwrap();\n         server_handler = Some(handler);\n     }\n```\n\n\n\nThe result `server.accept()` returned is `io::Result\u003c(TcpStream, SocketAddr)\u003e`.  If we trust `event` entirely, using `try` is the right choise (if there should be a new `TcpStream` is ready, `server.accept()` returning `Err` is unforeseen and unmanageable).\n\nHowever, we should think event may be spurious, the possibility depends on OS and custom implement. There may not be a new `TcpStream` is ready, in this case, `server.accept()` will return `WouldBlock Error`. We should regard `WouldBlock Error ` as a friendly warning: \"there isn't a new `TcpStream` is ready, please do it later again.\" So we should ignore it and continue the loop.\n\nLike the code for dealing with event `SERVER`\n\n```rust\nmatch handler.write(SERVER_HELLO) {\n    Ok(_) =\u003e {\n        println!(\"server wrote\");\n    }\n    Err(ref err) if err.kind() == io::ErrorKind::WouldBlock =\u003e continue,\n    err =\u003e {\n        err?;\n    }\n}\n```\n\n#### Poll Option\n\nNow we can execute:\n\n```bash\ncargo run --example tcp\n```\n\nThe terminal print some log:\n\n```bash\nclient wrote\naccept from addr: 127.0.0.1:53205\nclient wrote\nserver wrote\nserver received\n...\n```\n\nWe can see, in 10 milliseconds (`let timeout = Duration::from_millis(10);`), `server` and `client` did dozens of  writing and reading!\n\nHow should we do if we don't need dozens of writing and reading? In a pretty network environment, `client ` and `server` is almost always writable, so `Poll::poll` may return in dozens of microseconds.\n\nIn this case, we should change the forth parameter of `register`:\n\n```rust\npoll.register(\u0026server, SERVER_ACCEPT, Ready::readable(),\n                  PollOpt::edge()).unwrap();\n```\n\nThe type of `PollOpt::edge()` is `PollOpt`, means poll option. There are three kinds of poll options: `level`, `edge` and `oneshot`, what's the difference of them?\n\nFor example, in this code:\n\n```rust\nif event.readiness().is_readable() {\n    let mut hello = [0; 4];\n    match client.read_exact(\u0026mut hello) {\n        Ok(_) =\u003e {\n            assert_eq!(SERVER_HELLO, \u0026hello);\n            println!(\"client received\");\n        }\n        Err(ref err) if err.kind() == io::ErrorKind::WouldBlock =\u003e continue,\n        err =\u003e {\n            err?;\n        }\n    }\n}\n```\n\n\n\nWhen I receive a readable readiness, I read 4 bytes only. If there are 8 bytes in buffer:\n\n- if I register this `TcpStream` with `PollOpt::level()`, I **MUST** receive a `readable readiness event` in next polling;\n- if I register this `TcpStream` with `PollOpt::edge()`, I **MAY** cannot receive a `readable readiness event` in next polling;\n\nSo, we can say that readiness using edge-triggered mode is a `Draining readiness`, once a readiness event is received, the corresponding operation must be performed repeatedly until it returns `WouldBlock`. We should alter code above into:\n\n```rust\nif event.readiness().is_readable() {\n    let mut hello = [0; 4];\n    loop {\n        match client.read_exact(\u0026mut hello) {\n            Ok(_) =\u003e {\n                assert_eq!(SERVER_HELLO, \u0026hello);\n                println!(\"client received\");\n            }\n            Err(ref err) if err.kind() == io::ErrorKind::WouldBlock =\u003e break,\n            err =\u003e {\n                err?;\n            }\n        }\n    }\n}\n```\n\n\n\nThen, what's the behavior of `PollOpt::onshot()`? Let's talk about the first question of this section: if we want `handler` to write only once, how should we do? The answer is: register it using `PollOpt::oneshot()`\n\n```rust\nlet (handler, addr) = server.accept()?;\nprintln!(\"accept from addr: {}\", \u0026addr);\npoll.register(\u0026handler, SERVER, Ready::readable() | Ready::writable(), PollOpt::oneshot())?;\nserver_handler = Some(handler);\n```\n\nIn this case, you can only receive event `SERVER` once, unless you re-register `handler` using `Poll::reregister`.\n\n\u003e `Poll::reregister` can using different `PollOpt` and `interest` from the last registering\n\n\n\n#### Still Block\n\nThere is still a problem in the code above: we using blocking IO macro `println!`. We should avoid using blocking IO in the code for dealing events.\n\nGiven that FS(file-system) IO(including `stdin, stdout, stderr`) is slow, we can send all FS-IO task to a worker thread.\n\n```rust\nuse std::sync::mpsc::{Sender, Receiver, channel, SendError};\n\n#[derive(Clone)]\npub struct Fs {\n    task_sender: Sender\u003cTask\u003e,\n}\n\nimpl Fs {\n    pub fn new() -\u003e Self {\n        let (sender, receiver) = channel();\n        std::thread::spawn(move || {\n            loop {\n                match receiver.recv() {\n                    Ok(task) =\u003e {\n                        match task {\n                            Task::Println(ref string) =\u003e println!(\"{}\", string),\n                            Task::Exit =\u003e return\n                        }\n                    },\n                    Err(_) =\u003e {\n                        return;\n                    }\n                }\n            }\n        });\n        Fs { task_sender: sender }\n    }\n\n    pub fn println(\u0026self, string: String) {\n        self.task_sender.send(Task::Println(string)).unwrap()\n    }\n}\n\npub enum Task {\n    Exit,\n    Println(String),\n}\n```\n\nNow, we can replace all `println!` with `Fs::println`.\n\n#### Custom Event \n\nImplementing non-blocking `println` is easy, because this function has no return. How should we do if we want other non-blocking FS-IO functions? For example, opening a file, then reading it to string, then printing the string, how should we do?\n\nThe easiest way is using callback, like this:\n\n```rust\n// src/fs.rs\n\nuse crossbeam_channel::{unbounded, Sender};\nuse failure::Error;\nuse std::fs::File;\nuse std::io::Read;\nuse std::thread;\n\n#[derive(Clone)]\npub struct Fs {\n    task_sender: Sender\u003cTask\u003e,\n}\n\npub struct FsHandler {\n    io_worker: thread::JoinHandle\u003cResult\u003c(), Error\u003e\u003e,\n    executor: thread::JoinHandle\u003cResult\u003c(), Error\u003e\u003e,\n}\n\npub fn fs_async() -\u003e (Fs, FsHandler) {\n    let (task_sender, task_receiver) = unbounded();\n    let (result_sender, result_receiver) = unbounded();\n    let io_worker = std::thread::spawn(move || {\n        while let Ok(task) = task_receiver.recv() {\n            match task {\n                Task::Println(ref string) =\u003e println!(\"{}\", string),\n                Task::Open(path, callback, fs) =\u003e {\n                    result_sender.send(TaskResult::Open(File::open(path)?, callback, fs))?\n                }\n                Task::ReadToString(mut file, callback, fs) =\u003e {\n                    let mut value = String::new();\n                    file.read_to_string(\u0026mut value)?;\n                    result_sender.send(TaskResult::ReadToString(value, callback, fs))?\n                }\n                Task::Exit =\u003e {\n                    result_sender.send(TaskResult::Exit)?;\n                    break;\n                }\n            }\n        }\n        Ok(())\n    });\n    let executor = std::thread::spawn(move || {\n        loop {\n            let result = result_receiver.recv()?;\n            match result {\n                TaskResult::ReadToString(value, callback, fs) =\u003e callback(value, fs)?,\n                TaskResult::Open(file, callback, fs) =\u003e callback(file, fs)?,\n                TaskResult::Exit =\u003e break,\n            };\n        }\n        Ok(())\n    });\n\n    (\n        Fs { task_sender },\n        FsHandler {\n            io_worker,\n            executor,\n        },\n    )\n}\n\nimpl Fs {\n    pub fn println(\u0026self, string: String) -\u003e Result\u003c(), Error\u003e {\n        Ok(self.task_sender.send(Task::Println(string))?)\n    }\n\n    pub fn open\u003cF\u003e(\u0026self, path: \u0026str, callback: F) -\u003e Result\u003c(), Error\u003e\n    where\n        F: FnOnce(File, Fs) -\u003e Result\u003c(), Error\u003e + Sync + Send + 'static,\n    {\n        Ok(self.task_sender.send(Task::Open(\n            path.to_string(),\n            Box::new(callback),\n            self.clone(),\n        ))?)\n    }\n\n    pub fn read_to_string\u003cF\u003e(\u0026self, file: File, callback: F) -\u003e Result\u003c(), Error\u003e\n    where\n        F: FnOnce(String, Fs) -\u003e Result\u003c(), Error\u003e + Sync + Send + 'static,\n    {\n        Ok(self\n            .task_sender\n            .send(Task::ReadToString(file, Box::new(callback), self.clone()))?)\n    }\n\n    pub fn close(\u0026self) -\u003e Result\u003c(), Error\u003e {\n        Ok(self.task_sender.send(Task::Exit)?)\n    }\n}\n\nimpl FsHandler {\n    pub fn join(self) -\u003e Result\u003c(), Error\u003e {\n        self.io_worker.join().unwrap()?;\n        self.executor.join().unwrap()\n    }\n}\n\ntype FileCallback = Box\u003cdyn FnOnce(File, Fs) -\u003e Result\u003c(), Error\u003e + Sync + Send\u003e;\ntype StringCallback = Box\u003cdyn FnOnce(String, Fs) -\u003e Result\u003c(), Error\u003e + Sync + Send\u003e;\n\npub enum Task {\n    Exit,\n    Println(String),\n    Open(String, FileCallback, Fs),\n    ReadToString(File, StringCallback, Fs),\n}\n\npub enum TaskResult {\n    Exit,\n    Open(File, FileCallback, Fs),\n    ReadToString(String, StringCallback, Fs),\n}\n```\n\n\n\n```rust\n// examples/fs.rs\n\nuse asyncio::fs::fs_async;\nuse failure::Error;\n\nconst TEST_FILE_VALUE: \u0026str = \"Hello, World!\\n\";\n\nfn main() -\u003e Result\u003c(), Error\u003e {\n    let (fs, fs_handler) = fs_async();\n    fs.open(\"./examples/test.txt\", |file, fs| {\n        fs.read_to_string(file, |value, fs| {\n            assert_eq!(TEST_FILE_VALUE, \u0026value);\n            fs.println(value)?;\n            fs.close()\n        })\n    })?;\n    fs_handler.join()?;\n    Ok(())\n}\n```\n\nrunning this example:\n\n```bash\ncargo run --example fs\n```\n\nThis implementation work well, but the executor thread is still blocked by the io-worker thread `(result_receiver.recv()`). Can we run a polling loop in executor thread to not be blocked by IO? (executor should execute `(result_receiver.recv()` only when there are some results in result channel).\n\nTo implement a non-blocking executor, we can use custom events supported by `mio`.\n\nAltering the code above:\n\n```rust\n// src/fs_mio.rs\n\nuse crossbeam_channel::{unbounded, Sender, TryRecvError};\nuse failure::Error;\nuse mio::*;\nuse std::fs::File;\nuse std::io::Read;\nuse std::thread;\nuse std::time::Duration;\n\n#[derive(Clone)]\npub struct Fs {\n    task_sender: Sender\u003cTask\u003e,\n}\n\npub struct FsHandler {\n    io_worker: thread::JoinHandle\u003cResult\u003c(), Error\u003e\u003e,\n    executor: thread::JoinHandle\u003cResult\u003c(), Error\u003e\u003e,\n}\n\nconst FS_TOKEN: Token = Token(0);\n\npub fn fs_async() -\u003e (Fs, FsHandler) {\n    let (task_sender, task_receiver) = unbounded();\n    let (result_sender, result_receiver) = unbounded();\n    let poll = Poll::new().unwrap();\n    let (registration, set_readiness) = Registration::new2();\n    poll.register(\n        \u0026registration,\n        FS_TOKEN,\n        Ready::readable(),\n        PollOpt::oneshot(),\n    )\n    .unwrap();\n    let io_worker = std::thread::spawn(move || {\n        while let Ok(task) = task_receiver.recv() {\n            match task {\n                Task::Println(ref string) =\u003e println!(\"{}\", string),\n                Task::Open(path, callback, fs) =\u003e {\n                    result_sender.send(TaskResult::Open(File::open(path)?, callback, fs))?;\n                    set_readiness.set_readiness(Ready::readable())?;\n                }\n                Task::ReadToString(mut file, callback, fs) =\u003e {\n                    let mut value = String::new();\n                    file.read_to_string(\u0026mut value)?;\n                    result_sender.send(TaskResult::ReadToString(value, callback, fs))?;\n                    set_readiness.set_readiness(Ready::readable())?;\n                }\n                Task::Exit =\u003e {\n                    result_sender.send(TaskResult::Exit)?;\n                    set_readiness.set_readiness(Ready::readable())?;\n                    break;\n                }\n            }\n        }\n        Ok(())\n    });\n\n    let executor = thread::spawn(move || {\n        let mut events = Events::with_capacity(1024);\n        'outer: loop {\n            poll.poll(\u0026mut events, Some(Duration::from_secs(1)))?;\n            for event in events.iter() {\n                match event.token() {\n                    FS_TOKEN =\u003e {\n                        loop {\n                            match result_receiver.try_recv() {\n                                Ok(result) =\u003e match result {\n                                    TaskResult::ReadToString(value, callback, fs) =\u003e {\n                                        callback(value, fs)?\n                                    }\n                                    TaskResult::Open(file, callback, fs) =\u003e callback(file, fs)?,\n                                    TaskResult::Exit =\u003e break 'outer,\n                                },\n                                Err(e) =\u003e match e {\n                                    TryRecvError::Empty =\u003e break,\n                                    TryRecvError::Disconnected =\u003e return Err(e.into()),\n                                },\n                            }\n                        }\n                        poll.reregister(\n                            \u0026registration,\n                            FS_TOKEN,\n                            Ready::readable(),\n                            PollOpt::oneshot(),\n                        )?;\n                    }\n                    _ =\u003e unreachable!(),\n                }\n            }\n        }\n        Ok(())\n    });\n    (\n        Fs { task_sender },\n        FsHandler {\n            io_worker,\n            executor,\n        },\n    )\n}\n\nimpl Fs {\n    pub fn println(\u0026self, string: String) -\u003e Result\u003c(), Error\u003e {\n        Ok(self.task_sender.send(Task::Println(string))?)\n    }\n\n    pub fn open\u003cF\u003e(\u0026self, path: \u0026str, callback: F) -\u003e Result\u003c(), Error\u003e\n    where\n        F: FnOnce(File, Fs) -\u003e Result\u003c(), Error\u003e + Sync + Send + 'static,\n    {\n        Ok(self.task_sender.send(Task::Open(\n            path.to_string(),\n            Box::new(callback),\n            self.clone(),\n        ))?)\n    }\n\n    pub fn read_to_string\u003cF\u003e(\u0026self, file: File, callback: F) -\u003e Result\u003c(), Error\u003e\n    where\n        F: FnOnce(String, Fs) -\u003e Result\u003c(), Error\u003e + Sync + Send + 'static,\n    {\n        Ok(self\n            .task_sender\n            .send(Task::ReadToString(file, Box::new(callback), self.clone()))?)\n    }\n\n    pub fn close(\u0026self) -\u003e Result\u003c(), Error\u003e {\n        Ok(self.task_sender.send(Task::Exit)?)\n    }\n}\n\nimpl FsHandler {\n    pub fn join(self) -\u003e Result\u003c(), Error\u003e {\n        self.io_worker.join().unwrap()?;\n        self.executor.join().unwrap()\n    }\n}\n\ntype FileCallback = Box\u003cdyn FnOnce(File, Fs) -\u003e Result\u003c(), Error\u003e + Sync + Send\u003e;\ntype StringCallback = Box\u003cdyn FnOnce(String, Fs) -\u003e Result\u003c(), Error\u003e + Sync + Send\u003e;\n\npub enum Task {\n    Exit,\n    Println(String),\n    Open(String, FileCallback, Fs),\n    ReadToString(File, StringCallback, Fs),\n}\n\npub enum TaskResult {\n    Exit,\n    Open(File, FileCallback, Fs),\n    ReadToString(String, StringCallback, Fs),\n}\n\n// examples/fs-mio.rs\n\nuse asyncio::fs_mio::fs_async;\nuse failure::Error;\n\nconst TEST_FILE_VALUE: \u0026str = \"Hello, World!\\n\";\n\nfn main() -\u003e Result\u003c(), Error\u003e {\n    let (fs, fs_handler) = fs_async();\n    fs.open(\"./examples/test.txt\", |file, fs| {\n        fs.read_to_string(file, |value, fs| {\n            assert_eq!(TEST_FILE_VALUE, \u0026value);\n            fs.println(value)?;\n            fs.close()\n        })\n    })?;\n    fs_handler.join()?;\n    Ok(())\n}\n```\n\n\n\nrunning this example:\n\n```bash\ncargo run --example fs-mio\n```\n\n\n\nWe can see the difference between two implementations. On the one hand, executor will never be blocking by `result_receiver.recv()`, instead, it will wait for `Poll::poll` returning; on the other hand, io worker thread will execute `set_readiness.set_readiness(Ready::readable())?` after executing `result_sender.send`, to inform executor there are some events happens.\n\nIn this case, executor will never be blocked by io worker, because we can register all events in executor, and `mio::Poll` will listen to all events (eg. combine `fs-mio` with `tcp` into a file server).\n\n\n\n#### Callback is Evil\n\nBefore writing a file server, we should talk about the problems of callback.\n\nCallback can make code confusing, you can realize it more clearly when handling error, like this:\n\n```rust\nuse asyncio::fs_mio::fs_async;\nuse failure::Error;\n\nconst TEST_FILE_VALUE: \u0026str = \"Hello, World!\";\n\nfn main() -\u003e Result\u003c(), Error\u003e {\n    let (fs, fs_handler) = fs_async();\n    fs.open(\"./examples/test.txt\", \n        |file, fs| {\n            fs.read_to_string(file, \n                |value, fs| {\n                    assert_eq!(TEST_FILE_VALUE, \u0026value);\n                    fs.println(value, \n                        |err| {\n                            ...\n                        }\n                    );\n                    fs.close()\n                },\n                |err| {\n                    ...\n                }\n            )\n        },\n        |err| {\n            ...\n        }\n    )?;\n    fs_handler.join()?;\n    Ok(())\n}\n```\n\n\n\nMoreover, there is a lifetime problem in rust when we use closure, which means, we have to clone a environment variable if we want to borrow it in closure (if it implements `Clone`), otherwise we should deliver its reference as a parameter of closure (you should change signature of closure as you need, what a shit!).\n\nConsidering a variety of reasons, `rust` eventully uses `coroutine` as its asynchronous API abstraction.\n\n### stackless coroutine\n\n`coroutine` in this blog refers to `stackless coroutine` based on `rust generator` instead of `green thread(stackful coroutine)` which is obsoleted earlier.\n\n#### generator\n\n`rust` introduced `generator` at May of this year, however, it's still unstable and unsafe. Here is a typical Fibonacci sequence generator:\n\n```rust\n// examples/fab.rs\n// cargo +nightly run --example fab\n\n#![feature(generators, generator_trait)]\n\nuse std::ops::{Generator, GeneratorState};\nuse std::pin::Pin;\n\nfn main() {\n    let mut gen = fab(5);\n    loop {\n        match unsafe { Pin::new_unchecked(\u0026mut gen).resume() } {\n            GeneratorState::Yielded(value) =\u003e println!(\"yield {}\", value),\n            GeneratorState::Complete(ret) =\u003e {\n                println!(\"return {}\", ret);\n                break;\n            }\n        }\n    }\n}\n\nfn fab(mut n: u64) -\u003e impl Generator\u003cYield = u64, Return = u64\u003e {\n    move || {\n        let mut last = 0u64;\n        let mut current = 1;\n        yield last;\n        while n \u003e 0 {\n            yield current;\n            let tmp = last;\n            last = current;\n            current = tmp + last;\n            n -= 1;\n        }\n        return last;\n    }\n}\n\n```\n\nBecause of the \"interrupt behaviors\" of `generator`, we will naturally consider to combine it with `mio`: assign a `token` for each `generator`, then poll, resume corresponding `generator` when receive a event; register an awaking event and yield before each generator is going to block. Can we implement non-blocking IO in \"synchronous code\" on this way?\n\nIt seems to work well in theory, but there are still \"two dark clouds\"。\n\n#### self-referential structs\n\nThe first \"dark cloud\" is relevant to memory management of `rust`.\n\nIf you write a `generator` like this:\n\n```rust\nfn self_ref_generator() -\u003e impl Generator\u003cYield=u64, Return=()\u003e {\n    || {\n        let x: u64 = 1;\n        let ref_x: \u0026u64 = \u0026x;\n        yield 0;\n        yield *ref_x;\n    }\n}\n```\n\n`rustc` will refuse to compile and tell you \"borrow may still be in use when generator yields\". You may be a little panic because `rustc` doesn't tell you how to fix it. Going to google it, you will find it is relevant to implementation of `generator`.\n\nAs memtioned earlier, `generator` is stackless, which means `rustc` doesn't reserve a complete \"stack\" for each generator, instead, only variables and values required by a specific \"state\" will be reserved.\n\nThis code is valid:\n\n```rust\nfn no_ref_generator() -\u003e impl Generator\u003cYield=u64, Return=()\u003e {\n    || {\n        let x: u64 = 1;\n        let ref_x: \u0026u64 = \u0026x;\n        yield *ref_x;\n        yield 0;\n    }\n}\n```\n\nBecause `rustc` knows the only variable or value need be reserved after the first \"yield\" is literal `0` . However, for the `self_ref_generator`, `rustc` should reserve both of variable `x` and its reference `ref_x` after the first \"yield\". In this case, generator should be compiled into a structure like this:\n\n```rust\nenum SomeGenerator\u003c'a\u003e {\n    ...\n    SomeState {\n        x: u64\n        ref_x: \u0026'a u64\n    }\n    ...\n}\n```\n\n\n\nThis is the notorious \"self-referential structs\" in `rust`, what will happen when you try to compile code like this?\n\n```rust\nstruct A\u003c'a\u003e {\n    b: u64,\n    ref_b: Option\u003c\u0026'a u64\u003e\n}\n\nimpl\u003c'a\u003e A\u003c'a\u003e {\n    fn new() -\u003e Self {\n        let mut a = A{b: 1, ref_b: None};\n\t\ta.ref_b = Some(\u0026a.b);\n        a\n    }\n}\n```\n\nOf course, `rustc` will refuse to compile it. It's reasonable, variable `a` on stack will be copied and dropped and its field ref_b will be invalid when function `new` returns. Lifetime rules of `rust` helps you avoid this memory problem.\n\nHowever, even if you write code like this:\n\n```rust\nuse std::borrow::{BorrowMut};\n\nstruct A\u003c'a\u003e {\n    b: u64,\n    ref_b: Option\u003c\u0026'a u64\u003e\n}\n\nimpl\u003c'a\u003e A\u003c'a\u003e {\n    fn boxed() -\u003e Box\u003cSelf\u003e {\n        let mut a = Box::new(A{b: 1, ref_b: None});\n        let mut_ref: \u0026mut A = a.borrow_mut();\n\t\tmut_ref.ref_b = Some(\u0026mut_ref.b);\n        a\n    }\n}\n```\n\n`rustc` still refuses to compile it. It's unreasonable，variable `a` on heap will not be dropped after function `new` returns, and its field `ref_b` should be always valid. However, `rustc` doesn't know, and you cannot prove it in the language that compiler can understand.\n\nMoreover, you even cannot mutably borrow self-referential structs, like this:\n\n```rust\nstruct A\u003c'a\u003e {\n    b: u64,\n    ref_b: Option\u003c\u0026'a u64\u003e\n}\n\nimpl\u003c'a\u003e A\u003c'a\u003e {\n    fn new() -\u003e Self {\n        A{b: 1, ref_b: None}\n    }\n\n    fn mute(\u0026mut self) {\n\n    }\n}\n\nfn main() {\n    let mut a = A::new();\n    a.ref_b = Some(\u0026a.b);\n    a.mute();\n}\n```\n\n`rustc` still refuses to compile it. It's awful, because the signature of earlier `Future::poll` is:\n\n```rust\nfn poll(\u0026mut self) -\u003e Poll\u003cSelf::Item, Self::Error\u003e;\n```\n\nand the signature of `Generator::resume` is still:\n\n```rust\nunsafe fn resume(\u0026mut self) -\u003e GeneratorState\u003cSelf::Yield, Self::Return\u003e;\n```\n\nAs a result, self-reference will lead to unable implementation of `trait Generator` and `trait Future` .  In this case, we can use `NonNull` to avoid compiler checking: \n\n```rust\nuse std::ptr::NonNull;\n\nstruct A {\n    b: u64,\n    ref_b: NonNull\u003cu64\u003e\n}\n\nimpl A {\n    fn new() -\u003e Self {\n        A{b: 1, ref_b: NonNull::dangling()}\n    }\n}\n\nfn main() {\n    let mut a = A::new();\n    a.ref_b = NonNull::from(\u0026a.b);\n}\n```\n\nHowever, you should guarantee memory safety by yourself (self-referential structs **MUST NOT** be moved, and you **MUST NOT** deliver its mutable reference to `mem::replace` or `mem::swap`), it's not a nice solution.\n\nCan we find some ways to guarantee its moving and mutably borrowing cannot be safe? `rust` introduces `Pin` to hold this job. Specifications of `pin` can be found in this [RFC](https://github.com/rust-lang/rfcs/blob/master/text/2349-pin.md), this blog will only introduce it simply.\n\n##### Pin\n\n`rust` implement `trait std::marker::Unpin` for almost all types by default. It's only a marker to indicate safely moving of a type. For types marked as `Unpin`, `Pin\u003c\u0026'a mut T\u003e` and `\u0026'a mut T` have no difference, you can safely exchange them by `Pin::new(\u0026mut T)` and `Pin::get_mut(this: Pin\u003c\u0026mut T\u003e)`.\n\nHowever, for types that cannot be moved safely, like the `A` mentioned earlier, we should mark it as `!Unpin` first, a safe way is to give it a field whose type is marked `!Unpin`, for example, `Pinned`.\n\n```rust\n#![feature(pin)]\nuse std::marker::{Pinned};\n\nuse std::ptr::NonNull;\n\nstruct A {\n    b: u64,\n    ref_b: NonNull\u003cu64\u003e,\n    _pin: Pinned,\n}\n\nimpl A {\n    fn new() -\u003e Self {\n        A {\n            b: 1,\n            ref_b: NonNull::dangling(),\n            _pin: Pinned,\n        }\n    }\n}\n\nfn main() {\n    let mut a = A::new();\n    let mut pinned = unsafe { Pin::new_unchecked(\u0026mut a) };\n    let ref_b = NonNull::from(\u0026pinned.b);\n    let mut_ref: Pin\u003c\u0026mut A\u003e = pinned.as_mut();\n    unsafe {Pin::get_mut_unchecked(mut_ref).ref_b = ref_b};\n    let unmoved = pinned;\n    assert_eq!(unmoved.ref_b, NonNull::from(\u0026unmoved.b));\n}\n```\n\nFor types marked as `!Unpin`, `Pin\u003c\u0026'a mut T\u003e` and `\u0026'a mut T`  cannot be safely exchanged, you can unsafely exchange them by `Pin::new_unchecked` and `Pin::get_mut_unchecked`. We can always guarantee the safety in the scope we construct it, so after calling two unsafe methods, we can guarantee:\n\n- we can never get mutable reference safely: `Pin::get_mut_unchecked` is unsafe\n- we can never move it: because `Pin` only owns a mutable reference, and `Pin::get_mut_unchecked` is unsafe, so deliver the mutable reference into `mem::replace` and `mem::swap` is unsafe\n\nOf course, if you don't want to construct `Pin` in unsafe way or you want `Pin` to own the ownership of the instance, you can use `Box::pin` thus allocate instance on the heap.\n\n```rust\nstruct A {\n    b: u64,\n    ref_b: NonNull\u003cu64\u003e,\n    _pin: Pinned,\n}\n\nimpl A {\n    fn boxed() -\u003e Pin\u003cBox\u003cSelf\u003e\u003e {\n        let mut boxed = Box::pin(A {\n            b: 1,\n            ref_b: NonNull::dangling(),\n            _pin: Pinned,\n        });\n        let ref_b = NonNull::from(\u0026boxed.b);\n        let mut_ref: Pin\u003c\u0026mut A\u003e = boxed.as_mut();\n        unsafe { Pin::get_mut_unchecked(mut_ref).ref_b = ref_b };\n        boxed\n    }\n}\n\nfn main() {\n    let boxed = A::boxed();\n    let unmoved = boxed;\n    assert_eq!(unmoved.ref_b, NonNull::from(\u0026unmoved.b));\n}\n```\n\nAfter introducing of `Pin`, the new `Future` is defined as:\n\n```rust\npub trait Future {\n    type Output;\n    fn poll(self: Pin\u003c\u0026mut Self\u003e, cx: \u0026mut Context\u003c'_\u003e) -\u003e Poll\u003cSelf::Output\u003e;\n}\n```\n\n#### Reasonable Abstraction\n\nThe second \"dark cloud\" is relevant to API abstraction.\n\nNow that `rust` chooses `coroutine` as API abstraction of non-blocking IO, what should be introduced into key words,  what should be introduced into standard library and what should be implemented by community? Let developers call unsafe `Generator::resume` is inapposite, using `mio` as the only specified low-level non-blocking IO implementation is also unreasonable.\n\nUp to now, `rust` supports:\n\n- key words\n  - `async`\n  - `await`\n- standard libraries\n  - `std::future`\n    - `trait Future`\n    - `trait GenFuture`\n  - `std::task`\n    - `enum Poll\u003cT\u003e`\n    - `struct Context`\n    - `struct Waker`\n    - `struct RawWaker`\n\n`RawWaker` consists of an data ptr and a virtual table, you can construct one with `SetReadiness` and implement `fn wake(*const ())` by `SetReadiness::set_readiness`. Then you should wrap your raw waker in `Waker ` and `Context`.\n\n##### Poll\\\u003cT\u003e\n\n`Poll\u003cT\u003e` is defined as:\n\n```rust\npub enum Poll\u003cT\u003e {\n    Ready(T),\n    Pending,\n}\n```\n\n\n\n ##### await\n\n `await` is the first suffix keyword in rust, which can only be used in `async` block or function.\n\n`future.await` will be expanded into:\n\n```rust\nloop {\n    if let Poll::Ready(x) = std::future::poll_with_tls_context(unsafe{\n        Pin::new_unchecked(\u0026mut future)\n    }) {\n        break x;\n    }\n    yield\n}\n```\n\n`std::future::poll_with_tls_context` will poll with \"thread local context\" via a thread-local variable `TLS_CX`.\n\n##### async\n\n`async` is used to wrap a `Generator` into a `GenFuture`. `GenFuture` is defined as:\n\n```rust\nstruct GenFuture\u003cT: Generator\u003cYield = ()\u003e\u003e(T);\n\nimpl\u003cT: Generator\u003cYield = ()\u003e\u003e !Unpin for GenFuture\u003cT\u003e {}\n\nimpl\u003cT: Generator\u003cYield = ()\u003e\u003e Future for GenFuture\u003cT\u003e {\n    type Output = T::Return;\n    fn poll(self: Pin\u003c\u0026mut Self\u003e, cx: \u0026mut Context\u003c'_\u003e) -\u003e Poll\u003cSelf::Output\u003e {\n        let gen = unsafe { Pin::map_unchecked_mut(self, |s| \u0026mut s.0) };\n        set_task_context(cx, || match gen.resume() {\n            GeneratorState::Yielded(()) =\u003e Poll::Pending,\n            GeneratorState::Complete(x) =\u003e Poll::Ready(x),\n        })\n    }\n}\n\npub fn from_generator\u003cT: Generator\u003cYield = ()\u003e\u003e(x: T) -\u003e impl Future\u003cOutput = T::Return\u003e {\n    GenFuture(x)\n}\n```\n\nWe can see, `GenFuture` will call `set_task_context` before calling `self.0.resume`, thus code in generator can get this `Context` via `TLS_CX`.\n\nSo, code like this:\n\n```rust\nasync fn async_recv(string_channel: Receiver\u003cString\u003e) -\u003e String {\n    string_channel.recv_future().await\n}\n```\n\nwill be expanded into:\n\n```rust\nfn async_recv(string_channel: Receiver\u003cString\u003e) -\u003e impl Future\u003cOutput = T::Return\u003e {\n\tfrom_generator(move || {\n        let recv_future = string_channel.recv_future();\n        loop {\n            if let Poll::Ready(x) = std::future::poll_with_tls_context(unsafe{\n                Pin::new_unchecked(\u0026mut recv_future)\n            }) {\n                break x;\n            }\n            yield\n        }\n    })\n}\n```\n\n#### non-blocking coroutine\n\nMastering all the basic knowledge mentioned above, we can do some practices.\n\n`coroutine` doesn't mean \"non-blocking\", you can invoke blocking API in async blocks or functions. The key to non-blocking IO is, when `GenFuture` is going to block (eg. an API returns `io::ErrorKind::WouldBlock`), register a source task by local waker and sleep (`yield`), lower-level non-blocking scheduler will awake this `GenFuture` after task completed.\n\nIn [src/executor.rs](https://github.com/Hexilee/async-io-demo/blob/master/src/executor.rs), I implement `Executor`, `block_on`, `spawn`, `TcpListener` and `TcpStream`. Code is a little long, you had better clone and view it in editor.\n\n\u003e Be careful to distinguish `Poll`(`mio::Poll`) from `task::Poll` and to distinguish  `net::{TcpListener, TcpStream}`(`mio::net::{TcpListener, TcpStream}`) from `TcpListener, TcpStream`\n\n##### Executor\n\n`Executor` is a struct containing `mio::Poll`, main task waker and two `Slab`s for managing `Task` and `Source`. I don't implement any special methods for it, its only duty is to be initialized as thread local variable `EXECUTOR` and to be borrowed by other functions.\n\n##### block_on\n\nThis function will block current thread, the only parameter is `main_task: Future\u003cOutput=T\u003e`; type of return value is `T`. This function is generally called by main function.\n\n`block_on` borrows thread local variable `EXECUTOR`, its main logic loop will call `mio::Poll::poll` to wait for events. I classify all tokens (`0 - MAX_RESOURCE_NUM(1 \u003c\u003c 31)`) into three kinds:\n\n- main task token\n\n  receiving `Token` whose value is `MAIN_TASK_TOKEN (1 \u003c\u003c 31)` means main task need be awaked, `main_task.poll` will be called, `block_on` will return `Ok(ret)` if `main_task.poll` returns `task::Poll::Ready(ret)`.\n\n- task token\n\n  odd `Token` means corresponding task (spawned by function `spawn`) need be awaked, `task.poll` will be invoked, `block_on` will return `Err(err)` if `task.poll` returns `Err(err)`.\n\n- source token\n\n  even `Token` means corresponding source (registered by function `register_source`) is completed, `source.task_waker.waker` will be invoked to awake task which registered it.\n\n##### spawn\n\nFunction to spawn tasks.\n\n##### TcpListener\n\n`wrapper` for `mio::net::TcpListener`, method `accept` will return a `Future`.\n\n##### TcpStream\n\n`wrapper` for `mio::net::TcpStream`, method `read` and `write` will both return a `Future`.\n\n##### echo server\n\nImplemented `executor`, we can write a simple echo server:\n\n```rust\n// examples/async-echo\n\n#[macro_use]\nextern crate log;\n\nuse asyncio::executor::{block_on, spawn, TcpListener};\nuse failure::Error;\n\nfn main() -\u003e Result\u003c(), Error\u003e {\n    env_logger::init();\n    block_on(\n        async {\n            let mut listener = TcpListener::bind(\u0026\"127.0.0.1:7878\".parse()?)?;\n            info!(\"Listening on 127.0.0.1:7878\");\n            while let Ok((mut stream, addr)) = listener.accept().await {\n                info!(\"connection from {}\", addr);\n                spawn(\n                    async move {\n                        let client_hello = stream.read().await?;\n                        let read_length = client_hello.len();\n                        let write_length =\n                            stream.write(client_hello).await?;\n                        assert_eq!(read_length, write_length);\n                        stream.close();\n                        Ok(())\n                    },\n                )?;\n            };\n            Ok(())\n        },\n    )?\n}\n```\n\nrun\n\n```bash\nRUST_LOG=info cargo run --example async-echo\n```\n\nYou can test it using `telnet`.\n\n### Afterword\n\nHowever, to run the example metioned at the beginning, we should implement a non-blocking FS-IO based on `mio`  and `std::future`. Here is the final implementation: [src/fs_future.rs](https://github.com/Hexilee/async-io-demo/blob/master/src/fs_future.rs).\n\nNow, let's run:\n\n```bash\nRUST_LOG=info cargo run --example file-server\n```\n\nTest it using `telnet`:\n\n```bash\n[~] telnet 127.0.0.1 7878                                                                  \nTrying 127.0.0.1...\nConnected to localhost.\nEscape character is '^]'.\nPlease enter filename: examples/test.txt\nHello, World!\nConnection closed by foreign host.\n```\n\nYou can look up source code by yourself if you are interested in it.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FHexilee%2Fasync-io-demo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FHexilee%2Fasync-io-demo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FHexilee%2Fasync-io-demo/lists"}