#![feature(pattern)]
use colored;
use env_logger;
use log;
use apis;
pub const LOG_LEVEL : log::LevelFilter = log::LevelFilter::Info;
static THING_DROPPED : std::sync::atomic::AtomicBool =
std::sync::atomic::AtomicBool::new (false);
#[derive(Debug,Default)]
pub struct Dropthing;
impl Drop for Dropthing {
fn drop (&mut self) {
println!("dropping...");
let already_dropped
= THING_DROPPED.swap (true, std::sync::atomic::Ordering::SeqCst);
assert!(!already_dropped);
}
}
apis::def_program! {
program Interactive where
let result = session.run()
{
MODES [
mode readline_echoup::ReadlineEchoup {
println!("result: {result:?}");
Some (EventId::ToReadlineEchorev)
}
mode readline_echorev::ReadlineEchorev
]
TRANSITIONS [
transition ToReadlineEchorev
<readline_echoup::ReadlineEchoup> => <readline_echorev::ReadlineEchorev> [
Readline (readline_up) => Readline (readline_rev) {
readline_rev.dropthing = readline_up.dropthing.take();
}
]
]
initial_mode: ReadlineEchoup
}
}
pub mod readline_echoup {
use std;
use apis;
use crate::Dropthing;
apis::def_session! {
context ReadlineEchoup {
PROCESSES where
let process = self,
let message_in = message_in
[
process Readline (
dropthing : Option <Dropthing> = Some (Default::default())
) -> (Option <()>) {
kind { apis::process::Kind::Anisochronous }
sourcepoints [Toecho]
endpoints [Fromecho]
handle_message { process.readline_handle_message (message_in) }
update { process.readline_update() }
}
process Echoup () -> (Option <()>) {
kind { apis::process::Kind::asynchronous_default() }
sourcepoints [Fromecho]
endpoints [Toecho]
handle_message { process.echoup_handle_message (message_in) }
update { process.echoup_update() }
}
]
CHANNELS [
channel Toecho <ToechoMsg> (Simplex) {
producers [Readline]
consumers [Echoup]
}
channel Fromecho <FromechoMsg> (Simplex) {
producers [Echoup]
consumers [Readline]
}
]
MESSAGES [
message ToechoMsg {
Astring (String),
Quit
}
message FromechoMsg {
Echo (String)
}
]
main: Readline
}
}
impl Readline {
#[expect(clippy::unused_self)]
fn readline_handle_message (&self, message : GlobalMessage)
-> apis::process::ControlFlow
{
log::trace!("readline handle message...");
match message {
GlobalMessage::FromechoMsg (FromechoMsg::Echo (echo)) => {
log::info!("Readline: received echo \"{echo}\"");
},
_ => unreachable!()
}
log::trace!("...readline handle message");
apis::process::ControlFlow::Continue
}
fn readline_update (&self) -> apis::process::ControlFlow {
use std::io::Write;
use apis::Process;
log::trace!("readline update...");
assert_eq!("main", std::thread::current().name().unwrap());
let mut result = apis::process::ControlFlow::Continue;
print!(" > ");
let _ = std::io::stdout().flush();
let mut s = String::new();
let _ = std::io::stdin().read_line (&mut s);
if !s.trim_end().is_empty() {
let word_ct = s.as_str().split_whitespace().count();
match word_ct {
0 => unreachable!("zero words in server input readline parse"),
_ => {
let command = {
let mut words = s.as_str().split_whitespace();
let mut first = words.next().unwrap().to_string();
if first.starts_with (':') {
use std::str::pattern::Pattern;
debug_assert!(0 < first.len());
let _ = first.remove (0);
if 0 < first.len() && first.is_prefix_of ("quit") {
let _ = self.send (ChannelId::Toecho, ToechoMsg::Quit);
result = apis::process::ControlFlow::Break;
} else {
println!("unrecognized command: \"{}\"", s.trim());
}
true
} else {
false
}
};
if !command {
result = self.send (
ChannelId::Toecho, ToechoMsg::Astring (s.trim().to_string())
).into();
}
}
} }
log::trace!("...readline update");
result
}
}
impl Echoup {
fn echoup_handle_message (&self, message : GlobalMessage)
-> apis::process::ControlFlow
{
use apis::Process;
log::trace!("echoup handle message...");
let GlobalMessage::ToechoMsg (msg) = message else { unreachable!() };
let result = match msg {
ToechoMsg::Astring (string) => {
let echo = string.as_str().to_uppercase();
self.send (ChannelId::Fromecho, FromechoMsg::Echo (echo)).into()
}
ToechoMsg::Quit => apis::process::ControlFlow::Break
};
log::trace!("...echoup handle message");
result
}
#[expect(clippy::unused_self)]
fn echoup_update (&self) -> apis::process::ControlFlow {
log::trace!("echoup update...");
log::trace!("...echoup update");
apis::process::ControlFlow::Continue
}
}
}
pub mod readline_echorev {
use std;
use apis;
use crate::Dropthing;
apis::def_session! {
context ReadlineEchorev {
PROCESSES where
let process = self,
let message_in = message_in
[
process Echorev () -> (Option <()>) {
kind { apis::process::Kind::asynchronous_default() }
sourcepoints [Fromecho]
endpoints [Toecho]
handle_message { process.echorev_handle_message (message_in) }
update { process.echorev_update() }
}
process Readline (
dropthing : Option <Dropthing> = None
) -> (Option <()>) {
kind { apis::process::Kind::Anisochronous }
sourcepoints [Toecho]
endpoints [Fromecho]
handle_message { process.readline_handle_message (message_in) }
update { process.readline_update() }
}
]
CHANNELS [
channel Toecho <ToechoMsg> (Simplex) {
producers [Readline]
consumers [Echorev]
}
channel Fromecho <FromechoMsg> (Simplex) {
producers [Echorev]
consumers [Readline]
}
]
MESSAGES [
message ToechoMsg {
Astring (String),
Quit
}
message FromechoMsg {
Echo (String)
}
]
main: Readline
}
}
impl Readline {
#[expect(clippy::unused_self)]
fn readline_handle_message (&self, message : GlobalMessage)
-> apis::process::ControlFlow
{
log::trace!("readline handle message...");
match message {
GlobalMessage::FromechoMsg (FromechoMsg::Echo (echo)) => {
log::info!("Readline: received echo \"{echo}\"");
},
_ => unreachable!()
}
log::trace!("...readline handle message");
apis::process::ControlFlow::Continue
}
fn readline_update (&self) -> apis::process::ControlFlow {
use std::io::Write;
use apis::Process;
log::trace!("readline update...");
assert_eq!("main", std::thread::current().name().unwrap());
let mut result = apis::process::ControlFlow::Continue;
print!(" > ");
let _ = std::io::stdout().flush();
let mut s = String::new();
let _ = std::io::stdin().read_line (&mut s);
if !s.trim_end().is_empty() {
let word_ct = s.as_str().split_whitespace().count();
match word_ct {
0 => unreachable!("zero words in server input readline parse"),
_ => {
let command = {
let mut words = s.as_str().split_whitespace();
let mut first = words.next().unwrap().to_string();
if first.starts_with (':') {
use std::str::pattern::Pattern;
debug_assert!(0 < first.len());
let _ = first.remove (0);
if 0 < first.len() && first.is_prefix_of ("quit") {
let _ = self.send (ChannelId::Toecho, ToechoMsg::Quit);
result = apis::process::ControlFlow::Break;
} else {
println!("unrecognized command: \"{}\"", s.trim());
}
true
} else {
false
}
};
if !command {
result = self.send (
ChannelId::Toecho, ToechoMsg::Astring (s.trim().to_string())
).into();
}
}
} }
log::trace!("...readline update");
result
}
}
impl Echorev {
fn echorev_handle_message (&self, message : GlobalMessage)
-> apis::process::ControlFlow
{
use apis::Process;
log::trace!("echorev handle message...");
let GlobalMessage::ToechoMsg (msg) = message else { unreachable!() };
let result = match msg {
ToechoMsg::Astring (string) => {
let echo = string.chars().rev().collect();
self.send (ChannelId::Fromecho, FromechoMsg::Echo (echo)).into()
}
ToechoMsg::Quit => apis::process::ControlFlow::Break
};
log::trace!("...echorev handle message");
result
}
#[expect(clippy::unused_self)]
fn echorev_update (&self) -> apis::process::ControlFlow {
log::trace!("echorev update...");
log::trace!("...echorev update");
apis::process::ControlFlow::Continue
}
}
}
fn main() {
use colored::Colorize;
let example_name = std::path::PathBuf::from (std::env::args().next().unwrap())
.file_name().unwrap().to_str().unwrap().to_string();
println!("{}", format!("{example_name} main...").green().bold());
env_logger::Builder::new()
.filter_level (LOG_LEVEL)
.parse_default_env()
.init();
use std::io::Write;
let mut f = std::fs::File::create (format!("{example_name}.dot")).unwrap();
f.write_all (Interactive::dotfile().as_bytes()).unwrap();
drop (f);
Interactive::report_sizes();
println!(":quit to quit");
use apis::Program;
let mut myprogram = Interactive::initial();
myprogram.run();
println!("{}", format!("...{example_name} main").green().bold());
}