ccs 0.1.0

A simple implementation of the Calculus of Communicating Systems by Robin Milner
use std::fmt::{self, Display};

use rand::thread_rng;
use rand::seq::IteratorRandom;
use rand::seq::SliceRandom;

pub struct RandomLts(Vec<(String, Vec<(String, String)>)>);

fn state_name(n: usize) -> String {
    format!("S{}", n)
}

fn action_name(n: usize) -> String {
    format!("a{}", n)
}

impl RandomLts {
    pub fn generate(nstates: usize, nactions: usize, ntransitions: usize) -> Self {
        let mut graph: Vec<_> = (0..nstates)
            .map(state_name)
            .map(|n| (n, Vec::new()))
            .collect();
        let action_labels: Vec<_> = (0..nactions)
            .map(action_name)
            .collect();
        let mut rng = thread_rng();

        for _ in 0..ntransitions {
            let to = graph.choose(&mut rng).unwrap().0.clone();
            let from_transitions = &mut graph.choose_mut(&mut rng).unwrap().1;
            let label = action_labels.iter().choose(&mut rng).unwrap().clone();
            from_transitions.push((label, to));
        }

        RandomLts(graph)
    }
}

impl Display for RandomLts {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        for (state, transitions) in self.0.iter() {
            write!(f, "{} = ", state)?;

            if transitions.is_empty() {
                writeln!(f, "0")?;
                continue;
            }

            for (i, (label, dest)) in transitions.iter().enumerate() {
                if i == 0 {
                    write!(f, "{}.{}", label, dest)?;
                } else {
                    write!(f, " + {}.{}", label, dest)?;
                }
            }
            writeln!(f)?;
        }
        Ok(())
    }
}