use anyhow::anyhow;
use clap::Parser;
use scan_core::{Oracle, Scan, Time, Tracer, TransitionSystem, TransitionSystemGenerator};
const ALL_PROPS_ERR: &str =
"the --all flag is incompatible with individually-specified properties.\n
Examples:
'scan PATH/TO/MODEL trace' executes the model once and writes the trace to disk
'scan PATH/TO/MODEL verify PROPERTY_1 PROPERTY_2' executes the model once and writes the trace to disk, classifying it according to verification outcome of the properties PROPERTY_1 and PROPERTY_2 together over the model
'scan PATH/TO/MODEL verify --all' executes the model once and writes the trace to disk, and classifying it according to verification outcome of all specified properties together over the model";
#[derive(Debug, Clone, Parser)]
#[deny(missing_docs)]
pub(crate) struct TraceArgs {
pub(crate) properties: Vec<String>,
#[arg(short, long)]
pub(crate) all: bool,
#[arg(long, default_value_t = 1)]
pub(crate) traces: usize,
#[arg(short, long, default_value_t = 10000)]
pub(crate) duration: Time,
#[arg(long)]
pub(crate) single_thread: bool,
}
impl TraceArgs {
pub(crate) fn validate(&self) -> anyhow::Result<()> {
if !self.properties.is_empty() && self.all {
Err(anyhow!(ALL_PROPS_ERR))
} else {
Ok(())
}
}
pub(crate) fn trace<'a, D, Od, Tr>(&self, scan: &'a Scan<D, Od>, tracer: Tr)
where
D: TransitionSystemGenerator + Sync + 'a,
Od: Oracle + Sync + 'a,
Tr: Clone
+ Sync
+ Tracer<<<D as TransitionSystemGenerator>::Ts<'a> as TransitionSystem>::Event>,
{
if self.single_thread {
scan.traces::<Tr>(self.traces, tracer, self.duration);
} else {
scan.par_traces::<Tr>(self.traces, tracer, self.duration);
}
}
}