#![allow(clippy::type_complexity)]
use dialectic::prelude::*;
use std::{error::Error, future::Future, pin::Pin};
use tokio::io::{AsyncWriteExt, BufReader, Stdin, Stdout};
mod common;
use common::{demo, prompt};
#[tokio::main]
async fn main() {
demo::<Server, _, _, _, _, _, _>(&server, &client, usize::MAX).await;
}
type Client = Session! {
loop {
choose {
0 => break,
1 => {
send String;
call { continue };
recv String;
}
}
}
};
#[Transmitter(Tx for ref String)]
#[Receiver(Rx for String)]
async fn client<Tx, Rx>(
mut input: BufReader<Stdin>,
mut output: Stdout,
chan: Chan<Client, Tx, Rx>,
) -> Result<(), Box<dyn Error>>
where
Tx::Error: Error + Send,
Rx::Error: Error + Send,
{
client_rec(0, &mut input, &mut output, chan).await
}
async fn client_prompt(
input: &mut BufReader<Stdin>,
output: &mut Stdout,
size: usize,
) -> Result<String, std::io::Error> {
prompt(
&format!(
"[size: {}] Type a string to push, or [ENTER] to pop/quit: ",
size
),
input,
output,
|s| Ok::<_, ()>(s.to_string()),
)
.await
}
#[Transmitter(Tx for ref String)]
#[Receiver(Rx for String)]
fn client_rec<'a, Tx, Rx>(
size: usize,
input: &'a mut BufReader<Stdin>,
output: &'a mut Stdout,
mut chan: Chan<Client, Tx, Rx>,
) -> Pin<Box<dyn Future<Output = Result<(), Box<dyn Error>>> + Send + 'a>>
where
Tx::Error: Error + Send,
Rx::Error: Error + Send,
{
Box::pin(async move {
loop {
chan = {
let string = client_prompt(input, output, size).await?;
if string.is_empty() {
break chan.choose::<0>().await?.close();
} else {
let chan = chan.choose::<1>().await?.send_ref(&string).await?;
let chan = chan
.call(|chan| client_rec(size + 1, input, output, chan))
.await?
.1
.unwrap();
let (string, chan) = chan.recv().await?;
output.write_all(string.as_bytes()).await?;
output.write_all(b"\n").await?;
chan
}
}
}
Ok(())
})
}
type Server = <Client as Session>::Dual;
#[Transmitter(Tx for ref String)]
#[Receiver(Rx for String)]
fn server<Tx, Rx>(
mut chan: Chan<Server, Tx, Rx>,
) -> Pin<Box<dyn Future<Output = Result<(), Box<dyn Error>>> + Send>>
where
Tx::Error: Error + Send,
Rx::Error: Error + Send,
{
Box::pin(async move {
loop {
chan = offer!(in chan {
0 => break chan.close(),
1 => {
let (string, chan) = chan.recv().await?; let chan = chan.call(server).await?.1.unwrap(); chan.send_ref(&string.to_uppercase()).await? },
})?;
}
Ok(())
})
}