In tokio, the object we need to use to manage an event loop is Core. Here's how we start an event loop using tokio (in the main module):
use tokio_core::reactor::Core; fn main() { let mut core = Core::new().expect("Cannot create tokio Core"); if let Err(error) = core.run(server()) { println!("Error running the server: {}", error); } }
We first create a new Core object, and then call the run() method to start the event loop. The latter method will return when the provided future ends. Here, we call server() to get the future, so let's write this function:
use std::io; use futures::prelude::async; #[async] fn server() -> io::Result<()> { Ok(()) }
As you can see, we use the #[async] attribute. Since attributes are currently instable in Rust, we had to specify that we are using the proc_macro feature. We also import the async attribute from the futures_await crate (which was imported under the name futures). So don't forget the #![feature] attribute and the extern crate statements at the top.
This attribute allows us to write a normal function, returning a Result, and will convert this function to actually return a Future. This function does nothing and returns Ok(()), so when you run the program, it will end immediately.
There's another syntax we could have used that is provided by the futures-await crate:
use futures::prelude::async_block; fn main() { let mut core = Core::new().expect("Cannot create tokio Core"); let server = async_block! { Ok(()) }; let result: Result<_, io::Error> = core.run(server); if let Err(error) = result { println!("Error running the server: {}", error); } }
We won't use this syntax in our FTP server, but it is worth knowing about. By using an async_block, we are not required to create a new function.