use petgraph::Graph;
use std::collections::hash_map::RandomState;
use std::collections::HashMap;
use std::error::Error;
use std::fs::{create_dir_all, remove_file, File};
use std::io::Write;
use std::process::Command;
use std::str;
#[doc(hidden)]
mod aux_checker;
use aux_checker::*;
type HashGraph = HashMap<String, Graph<String, String>>;
#[macro_export]
#[cfg_attr(doc_cfg, doc(cfg(feature = "checking")))]
macro_rules! checker_concat {
(
$name_file: expr,
$(
$sessiontype: ty
),+ $(,)?
) => {
{
let mut sessions = Vec::new();
$(
sessions.push(String::from(std::any::type_name::<$sessiontype>()));
)+
let state_branching_sessions = std::collections::hash_map::RandomState::new();
let branching_sessions: std::collections::HashMap<String, String> =
std::collections::HashMap::with_hasher(state_branching_sessions);
let state_group_branches = std::collections::hash_map::RandomState::new();
let group_branches: std::collections::HashMap<String, i32> =
std::collections::HashMap::with_hasher(state_group_branches);
let state_branches = std::collections::hash_map::RandomState::new();
let branches_receivers: std::collections::HashMap<String, std::collections::HashMap<String, String>> =
std::collections::HashMap::with_hasher(state_branches);
mpstthree::checking::checker(
$name_file,
sessions,
branches_receivers,
branching_sessions,
group_branches
)
}
};
(
$name_file: expr,
$(
$sessiontype: ty
),+ $(,)?
=>
$(
[
$branch_stack: ty,
$(
$choice: ty,
$branch: ident
),+ $(,)?
]
),+ $(,)?
) => {
{
let mut sessions = Vec::new();
$(
sessions.push(String::from(std::any::type_name::<$sessiontype>()));
)+
let state_branching_sessions = std::collections::hash_map::RandomState::new();
let mut branching_sessions: std::collections::HashMap<String, String> =
std::collections::HashMap::with_hasher(state_branching_sessions);
let state_group_branches = std::collections::hash_map::RandomState::new();
let mut group_branches: std::collections::HashMap<String, i32> =
std::collections::HashMap::with_hasher(state_group_branches);
let mut index = 0;
$(
let temp_branch_stack = String::from(std::any::type_name::<$branch_stack>());
$(
branching_sessions.insert(
format!(
"{}::{}",
stringify!($choice).to_string(),
stringify!($branch).to_string(),
),
temp_branch_stack.clone()
);
group_branches.insert(
format!(
"{}::{}",
stringify!($choice).to_string(),
stringify!($branch).to_string(),
),
index
);
)+
index += 1;
)+
mpst_seq_proc::checking!(
$(
$(
{
$choice,
$branch,
}
)+
)+
);
mpstthree::checking::checker(
$name_file,
sessions,
branches_receivers,
branching_sessions,
group_branches
)
}
};
}
#[macro_export]
#[cfg_attr(doc_cfg, doc(cfg(feature = "checking")))]
macro_rules! checker_concat_impl {
(
$(
[
$(
$choice: ty,
$branch: ident
),+ $(,)?
]
),+ $(,)?
) => {
mpst_seq_proc::checking_impl!(
$(
$(
{
$choice,
$branch,
}
)+
)+
);
};
}
pub(crate) fn kmc_cli(name_file: &str, kmc_number: i32) -> Result<(bool, String), Box<dyn Error>> {
remove_file(format!(
"../mpst_rust_github/outputs/{name_file}_{kmc_number}_kmc.txt"
))
.unwrap_or(());
remove_file(format!(
"../mpst_rust_github/outputs/{name_file}-sync-0norm-system.dot"
))
.unwrap_or(());
remove_file(format!(
"../mpst_rust_github/outputs/{name_file}-sync-0norm-system.png"
))
.unwrap_or(());
remove_file(format!(
"../mpst_rust_github/outputs/{name_file}-ts-{kmc_number}.fsm"
))
.unwrap_or(());
let kmc = Command::new("KMC")
.arg(format!("cfsm/{name_file}.txt"))
.arg(format!("{kmc_number:?}"))
.arg("--fsm")
.output()?;
let stdout = String::from(str::from_utf8(&kmc.stdout)?);
if stdout.contains("False") {
Ok((false, stdout))
} else {
let mut kmc_file = File::create(format!("outputs/{name_file}_{kmc_number}_kmc.txt"))?;
writeln!(kmc_file, "{stdout}")?;
Ok((true, stdout))
}
}
#[doc(hidden)]
pub fn checker(
name_file: &str,
sessions: Vec<String>,
branches_receivers: HashMap<String, HashMap<String, String>>,
branching_sessions: HashMap<String, String>,
group_branches: HashMap<String, i32>,
) -> Result<(HashGraph, Option<i32>), Box<dyn Error>> {
let (clean_sessions, roles) = clean_sessions(sessions.to_vec())?;
let state_branches = RandomState::new();
let mut update_branches_receivers: HashMap<String, HashMap<String, Vec<String>>> =
HashMap::with_hasher(state_branches);
for (choice, branches) in branches_receivers {
let state_branch = RandomState::new();
let mut temp_branch: HashMap<String, Vec<String>> = HashMap::with_hasher(state_branch);
for (branch, session) in branches {
temp_branch.insert(branch, clean_session(&session)?);
}
update_branches_receivers.insert(choice, temp_branch);
}
let state_branching_sessions = RandomState::new();
let mut update_branching_sessions: HashMap<String, Vec<String>> =
HashMap::with_hasher(state_branching_sessions);
for (branch, session) in branching_sessions {
let current_clean_session = clean_session(&session)?;
update_branching_sessions.insert(
branch.to_string(),
current_clean_session[..(current_clean_session.len() - 1)].to_vec(),
);
}
let state_result = RandomState::new();
let mut result: HashGraph = HashMap::with_hasher(state_result);
if !name_file.is_empty() {
create_dir_all("cfsm")?;
let mut cfsm_file = File::create(format!("cfsm/{name_file}.txt"))?;
let mut cfsm_sort = vec![vec!["".to_string()]; roles.len()];
for (role, full_session) in clean_sessions {
let (graph, cfsm) = get_graph_session(
&role,
full_session,
&roles,
update_branches_receivers.clone(),
update_branching_sessions.clone(),
group_branches.clone(),
)?;
result.insert(role.to_string(), graph);
let index_role = roles.iter().position(|r| r == &role).unwrap();
cfsm_sort[index_role] = cfsm;
}
for elt_cfsm in cfsm_sort.iter() {
for elt in elt_cfsm.iter() {
writeln!(cfsm_file, "{elt}")?;
}
writeln!(cfsm_file)?;
}
let mut kmc_number = 1;
let mut kmc_result = kmc_cli(name_file, kmc_number)?;
while !kmc_result.0 && kmc_number < 50 {
kmc_number += 1;
kmc_result = kmc_cli(name_file, kmc_number)?;
}
if kmc_number == 50 {
println!(
"The protocol does not seem correct. Here is the last output: {:?}",
kmc_result.1
);
Ok((result, None))
} else {
Ok((result, Some(kmc_number)))
}
} else {
for (role, full_session) in clean_sessions {
let (graph, _) = get_graph_session(
&role,
full_session,
&roles,
update_branches_receivers.clone(),
update_branching_sessions.clone(),
group_branches.clone(),
)?;
result.insert(role.to_string(), graph);
}
Ok((result, None))
}
}