|
|
|
|
|
by jude-
1685 days ago
|
|
I'm not saying that we should go back to hand-rolling our own epoll loops. I'm saying that we can do better than async/await by making both the state machines and event loop explicit. For example, here's an API I'd prefer to use over async/await: /// A state machine that adds three numbers and uploads them to a web server
struct AddAndUpload {
/// I/O handle to the event loop
io: IOClient,
/// Buffer to store numbers I load
nums: [u64; 3],
/// URL to upload the data to
url: String
}
impl AddAndUpload {
/// Constructor
pub fn new(io: IOClient, url: String) -> AddAndUpload {
AddAndUpload {
io,
nums: [0u64; 3],
url
}
}
/// Entry point to this state machine
pub fn inner_main(&mut self) -> Result<(), IOClient::Error> {
/// go and get the data
let n1_fut : IOClient::Future<u64> = self.io.sql_async("SELECT n1 FROM table1", &[])?;
let n2_fut : IOClient::Future<u64> = self.io.sql_async("SELECT n2 FROM table2", &[])?;
let n3_fut : IOClient::Future<u64> = self.io.sql_async("SELECT n3 FROM table3", &[])?;
// wait for all I/O operations to finish
IOClient::wait_all(&[&n1_fut, &n2_fut, &n3_fut])?;
// extract results
let n1 = n1_fut.into_inner();
let n2 = n2_fut.into_inner();
let n3 = n3_fut.into_inner();
// upload them
let sum = n1 + n2 + n3;
let upload_fut : IOClient::Future<IOClient::HTTPStatus> = self.io.http_post_async(&self.url, &["content-type: application/octet-stream"], &sum.to_be_bytes())?;
let upload_http_status = upload_fut.wait()?.into_inner();
match upload_http_status.as_u16() {
200 => {
Ok(())
}
400..499 => {
Err(IOClient::Error::Custom("client error"))
}
500..599 => {
Err(IOClient::Error::Custom("server error"))
}
x => {
Err(IOClient::Error::Custom("Nonsensical HTTP code"))
}
}
}
}
impl IOClient::StateMachine for AddAndUpload {
type Return = ();
fn main(&mut self) -> Result<(), IOClient::Error> {
self.inner_main()
}
}
/\* somewhere else \*/
fn main() {
let io_server = IOServer::spawn().unwrap();
let io_client = io_server.client().unwrap();
let add_and_upload = AddAndUpload::new(io_client, "http://example.com".to_string());
loop {
io_server.run().unwrap();
match add_and_upload.get_machine_status() {
Ok(IOClient::StateMachine::Finished(result)) => {
eprintln!("add_and_uploaded exited with {:?}", &result);
break;
}
Ok(_) => {},
Err(e) => {
panic!("add_and_upload aborted: {:?}", &e);
}
}
}
io_server.terminate();
}
|
|
your statemachine blocks the thread. if you had a more complicated state machine, maybe nested machines, theyd block each other because they dont know how to cooperate.