use futures_channel::{
mpsc,
oneshot,
};
use futures_util::{
future::FutureExt,
pin_mut,
sink::SinkExt,
};
use std::{
io::{
self,
BufRead,
Write,
},
thread::sleep,
time::Duration,
};
use sync_async_runner;
async fn hello_dialog(mut d: DialogSender) {
d.text("Hello there!").await;
d.text("I'm going to ask you a question.").await;
d.text("What's your favorite color?").await;
let choice = d.choices(vec!["Red", "Green", "Blue"]).await;
match choice {
0 => d.text("Just like a rose! How pretty!").await,
1 => d.text("Green is not a creative color...").await,
2 => d.text("That reminds me, I am thirsty").await,
_ => unreachable!(),
};
d.text("Thank you for talking with me.").await;
}
struct DialogSender(mpsc::Sender<DialogAction>);
impl DialogSender {
pub async fn text(&mut self, text: &'static str) {
self.0.send(DialogAction::Text(text)).await.unwrap();
}
pub async fn choices(&mut self, choices: Vec<&'static str>) -> usize {
let (sender, receiver) = oneshot::channel();
self.0
.send(DialogAction::Choice {
choices,
response: sender,
})
.await
.unwrap();
receiver.await.unwrap()
}
}
#[derive(Debug)]
enum DialogAction {
Text(&'static str),
Choice {
choices: Vec<&'static str>,
response: oneshot::Sender<usize>,
},
}
fn main() {
let stdin = io::stdin();
let stdout = io::stdout();
let (dialog_sender, mut dialog_receiver) = mpsc::channel(5);
let dialog_sender = DialogSender(dialog_sender);
let dialog_coroutine = sync_async_runner::runner(hello_dialog(dialog_sender).fuse());
pin_mut!(dialog_coroutine);
loop {
let _ = dialog_coroutine.as_mut().poll();
let command = dialog_receiver.try_next().ok().flatten();
match command {
Some(DialogAction::Text(t)) => {
println!("{}", t);
sleep(Duration::from_millis(1000));
}
Some(DialogAction::Choice { choices, response }) => {
for (i, choice) in choices.iter().enumerate() {
println!("{}. {}", i, choice);
}
loop {
print!("Choose by number: ");
stdout.lock().flush().unwrap();
let mut input = String::new();
stdin.lock().read_line(&mut input).unwrap();
if let Ok(v) = input.trim().parse() {
response.send(v).unwrap();
break;
}
}
}
None => {
break;
}
}
}
}