use crate::error::Error;
use crate::net::{Arc, Net, Place, Transition};
use crate::sim::{Marking, Tokens};
use crate::NodeId;
use std::fs::OpenOptions;
use std::io::Write;
use std::marker::PhantomData;
use std::path::Path;
pub trait NetFormatter {
type Place: Place;
type Transition: Transition;
type Arc: Arc;
type Net: Net<Place = Self::Place, Transition = Self::Transition, Arc = Self::Arc>;
fn fmt_net<W: Write>(&self, w: &mut W, net: &Self::Net) -> Result<(), Error>;
}
pub trait MarkedNetFormatter {
type Place: Place;
type Transition: Transition;
type Arc: Arc;
type Net: Net<Place = Self::Place, Transition = Self::Transition, Arc = Self::Arc>;
type Tokens: Tokens;
type Marking: Marking<Tokens = Self::Tokens>;
fn fmt_marked_net<W: Write>(
&self,
w: &mut W,
net: &Self::Net,
marking: &Self::Marking,
enabled: Option<&[NodeId]>,
) -> Result<(), Error>;
}
#[derive(Debug)]
pub struct NetMatrixFormatter<P, T, A, N>
where
P: Place,
T: Transition,
A: Arc,
N: Net<Place = P, Transition = T, Arc = A>,
{
nothing: PhantomData<N>,
}
pub fn net_to_file<F: NetFormatter, P: AsRef<Path>>(
net: &F::Net,
path: P,
append: bool,
formatter: &mut F,
) -> Result<(), Error> {
let mut file = OpenOptions::new()
.write(true)
.create(true)
.append(append)
.open(path)?;
formatter.fmt_net(&mut file, net)
}
pub fn net_to_string<F: NetFormatter>(net: &F::Net, formatter: &mut F) -> Result<String, Error> {
let mut buffer = Vec::new();
formatter.fmt_net(&mut buffer, net)?;
let string = String::from_utf8(buffer)?;
Ok(string)
}
pub fn print_net<F: NetFormatter>(net: &F::Net, formatter: &mut F) -> Result<(), Error> {
let stdout = std::io::stdout();
let mut handle = stdout.lock();
formatter.fmt_net(&mut handle, net)
}
pub fn marked_net_to_file<F: MarkedNetFormatter, P: AsRef<Path>>(
net: &F::Net,
marking: &F::Marking,
enabled: Option<&[NodeId]>,
path: P,
append: bool,
formatter: &mut F,
) -> Result<(), Error> {
let mut file = OpenOptions::new()
.write(true)
.create(true)
.append(append)
.open(path)?;
formatter.fmt_marked_net(&mut file, net, marking, enabled)
}
pub fn marked_net_to_string<F: MarkedNetFormatter>(
net: &F::Net,
marking: &F::Marking,
enabled: Option<&[NodeId]>,
formatter: &mut F,
) -> Result<String, Error> {
let mut buffer = Vec::new();
formatter.fmt_marked_net(&mut buffer, net, marking, enabled)?;
let string = String::from_utf8(buffer)?;
Ok(string)
}
pub fn print_marked_net<F: MarkedNetFormatter>(
net: &F::Net,
marking: &F::Marking,
enabled: Option<&[NodeId]>,
formatter: &mut F,
) -> Result<(), Error> {
let stdout = std::io::stdout();
let mut handle = stdout.lock();
formatter.fmt_marked_net(&mut handle, net, marking, enabled)
}
const FORMAT_FIELD_WIDTH: usize = 6;
const MATRIX_ARROW: &str = "-^";
impl<P, T, A, N> Default for NetMatrixFormatter<P, T, A, N>
where
P: Place,
T: Transition,
A: Arc,
N: Net<Place = P, Transition = T, Arc = A>,
{
fn default() -> Self {
Self {
nothing: Default::default(),
}
}
}
impl<P, T, A, N> NetFormatter for NetMatrixFormatter<P, T, A, N>
where
P: Place,
T: Transition,
A: Arc,
N: Net<Place = P, Transition = T, Arc = A>,
{
type Place = P;
type Transition = T;
type Arc = A;
type Net = N;
fn fmt_net<W: Write>(&self, w: &mut W, net: &Self::Net) -> Result<(), Error> {
let mut places: Vec<NodeId> = net.places().iter().map(|place| place.id()).collect();
places.sort();
let mut transitions: Vec<NodeId> = net
.transitions()
.iter()
.map(|transition| transition.id())
.collect();
transitions.sort();
writeln!(
w,
"| {:>FORMAT_FIELD_WIDTH$} | {} |",
"",
places
.iter()
.map(|id| format!("{:>FORMAT_FIELD_WIDTH$}", id.as_place_string()))
.chain(
transitions
.iter()
.map(|id| format!("{:>FORMAT_FIELD_WIDTH$}", id.as_transition_string()))
)
.collect::<Vec<String>>()
.join(" | ")
)?;
let fields = places.len() + transitions.len();
let width = FORMAT_FIELD_WIDTH + 2; writeln!(
w,
"|{}|",
(0..=fields)
.map(|_| format!("{:-<width$}", ""))
.collect::<Vec<String>>()
.join("+")
)?;
let arcs: Vec<(NodeId, NodeId)> = net
.arcs()
.iter()
.map(|arc| (arc.source(), arc.target()))
.collect();
for place in &places {
writeln!(
w,
"| {:>FORMAT_FIELD_WIDTH$} | {} |",
place.as_place_string(),
places
.iter()
.map(|_| format!("{:>FORMAT_FIELD_WIDTH$}", ""))
.chain(transitions.iter().map(|id| format!(
"{:>FORMAT_FIELD_WIDTH$}",
if arcs.contains(&(*place, *id)) {
MATRIX_ARROW
} else {
""
}
)))
.collect::<Vec<String>>()
.join(" | ")
)?;
}
for transition in &transitions {
writeln!(
w,
"| {:>FORMAT_FIELD_WIDTH$} | {} |",
transition.as_transition_string(),
places
.iter()
.map(|id| format!(
"{:>FORMAT_FIELD_WIDTH$}",
if arcs.contains(&(*id, *transition)) {
MATRIX_ARROW
} else {
""
}
))
.chain(
transitions
.iter()
.map(|_| format!("{:>FORMAT_FIELD_WIDTH$}", ""))
)
.collect::<Vec<String>>()
.join(" | ")
)?;
}
Ok(())
}
}