use std::fmt::{self, Display, Formatter};
use std::fs::File;
use std::io::Write;
use std::path::Path;
use std::{env, error::Error};
fn main() -> Result<(), Box<dyn Error>> {
let out_dir = env::var("OUT_DIR").unwrap();
let dest_path = Path::new(&out_dir).join("valid_sessions.rs");
let mut f = File::create(&dest_path).unwrap();
let deep = Session::enumerate(6, 1, 1);
let medium = Session::enumerate(3, 2, 3);
let wide = Session::enumerate(2, 4, 127);
let sessions = deep.chain(medium.chain(wide));
writeln!(f, "#[deny(unused_imports)]")?; writeln!(
f,
"use crate::types::{{Send, Recv, Choose, Offer, Call, Split, Loop, Continue, Done}};"
)?;
writeln!(f, "use crate::Session;")?;
writeln!(f, "use static_assertions::assert_impl_all;")?;
writeln!(f)?;
writeln!(f, "#[test]")?;
writeln!(f, "fn all_sessions_valid() {{")?;
for s in sessions {
writeln!(f, " assert_impl_all!({}: Session);", s)?;
}
writeln!(f, "}}")?;
Ok(())
}
#[derive(Clone, Debug)]
pub enum Session {
Done,
Recv(Box<Session>),
Send(Box<Session>),
Choose(Vec<Session>),
Offer(Vec<Session>),
Loop(Box<Session>),
Continue(u8),
Split(Box<Session>, Box<Session>, Box<Session>),
Call(Box<Session>, Box<Session>),
}
impl Session {
pub fn enumerate(max_depth: u8, min_width: u8, max_width: u8) -> SessionIter {
let session = if max_depth == 0 {
None
} else {
Some(Session::Done)
};
SessionIter {
max_depth,
min_width,
max_width,
session,
}
}
}
impl Display for Session {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
use Session::*;
match self {
Done => write!(f, "Done")?,
Recv(s) => write!(f, "Recv<(), {}>", s)?,
Send(s) => write!(f, "Send<(), {}>", s)?,
Loop(s) => write!(f, "Loop<{}>", s)?,
Split(s, p, q) => write!(f, "Split<{}, {}, {}>", s, p, q)?,
Call(s, p) => write!(f, "Call<{}, {}>", s, p)?,
Choose(cs) => {
let count = cs.len();
write!(f, "Choose<(")?;
for (i, c) in cs.iter().enumerate() {
write!(f, "{}", c)?;
if i + 1 < count {
write!(f, ", ")?;
}
}
if count == 1 {
write!(f, ",")?;
}
write!(f, ")>")?;
}
Offer(cs) => {
let count = cs.len();
write!(f, "Offer<(")?;
for (i, c) in cs.iter().enumerate() {
write!(f, "{}", c)?;
if i + 1 < count {
write!(f, ", ")?;
}
}
if count == 1 {
write!(f, ",")?;
}
write!(f, ")>")?;
}
Continue(n) => {
write!(f, "Continue<{}>", n)?;
}
}
Ok(())
}
}
#[derive(Clone, Debug)]
pub struct SessionIter {
max_depth: u8,
min_width: u8,
max_width: u8,
session: Option<Session>,
}
impl Iterator for SessionIter {
type Item = Session;
fn next(&mut self) -> Option<Session> {
match self.session {
None => None,
Some(ref mut session) => {
let result = session.clone();
if !session.step(self.max_depth, self.min_width, self.max_width, 0, 0) {
self.session = None;
}
Some(result)
}
}
}
}
impl Session {
fn step(
&mut self,
max_depth: u8, min_width: u8, max_width: u8, loops: u8, productive: u8, ) -> bool {
use Session::*;
if max_depth == 0 {
return false;
}
match self {
Done => {
if max_depth <= 1 {
if loops > 0 && productive < loops {
*self = Continue(productive);
} else {
return false;
}
} else {
*self = Recv(Box::new(Done));
}
}
Recv(s) => {
if !s.step(max_depth - 1, min_width, max_width, loops, 0) {
*self = Send(Box::new(Done));
}
}
Send(s) => {
if !s.step(max_depth - 1, min_width, max_width, loops, 0) {
*self = Loop(Box::new(Done));
}
}
Loop(s) => {
if !s.step(
max_depth - 1,
min_width,
max_width,
loops + 1,
productive + 1,
) {
if min_width <= 3 && 3 <= max_width {
*self = Split(Box::new(Done), Box::new(Done), Box::new(Done));
} else if min_width <= 2 && 2 <= min_width {
*self = Call(Box::new(Done), Box::new(Done));
} else {
let mut initial = Vec::with_capacity(max_width.into());
for _ in 0..min_width {
initial.push(Done);
}
*self = Choose(initial);
}
}
}
Split(s, p, q) => {
if !s.step(max_depth - 1, min_width, max_width, loops, 0)
&& !p.step(max_depth - 1, min_width, max_width, loops, 0)
&& !q.step(max_depth - 1, min_width, max_width, loops, 0)
{
*self = Call(Box::new(Done), Box::new(Done));
}
}
Call(s, p) => {
if !s.step(max_depth - 1, min_width, max_width, loops, 0)
&& !p.step(max_depth - 1, min_width, max_width, loops, 0)
{
let mut initial = Vec::with_capacity(max_width.into());
for _ in 0..min_width {
initial.push(Done);
}
*self = Choose(initial);
}
}
Choose(cs) => {
for c in cs.iter_mut() {
if c.step(max_depth - 1, min_width, max_width, loops, 0) {
return true;
} else {
*c = Done;
}
}
if cs.len() < max_width.into() {
cs.push(Done);
} else {
let mut initial = Vec::with_capacity(max_width.into());
for _ in 0..min_width {
initial.push(Done);
}
*self = Offer(initial);
}
}
Offer(cs) => {
for c in cs.iter_mut() {
if c.step(max_depth - 1, min_width, max_width, loops, 0) {
return true;
} else {
*c = Done;
}
}
if cs.len() < max_width.into() {
cs.push(Done);
} else if loops > 0 && productive < loops {
*self = Continue(productive);
} else {
return false;
}
}
Continue(n) => {
if *n + 1 < loops {
*n += 1;
} else {
return false;
}
}
};
true
}
}