use super::{
CampaignSelection, FaultAdapter, FaultCampaign, FaultCampaignRefusal, FaultSchedule,
FaultSelectionRefusal, InjectedCommand, InjectedSequence, ScheduledFault, SequencePosition,
};
use crate::descriptor::NamespacedName;
use std::collections::BTreeSet;
impl<Behavior, Postcondition> FaultAdapter<Behavior, Postcondition> {
#[must_use]
pub const fn declared(behavior: Behavior, postcondition: Postcondition) -> Self {
Self {
behavior,
postcondition,
}
}
#[must_use]
pub const fn behavior(&self) -> &Behavior {
&self.behavior
}
#[must_use]
pub const fn postcondition(&self) -> &Postcondition {
&self.postcondition
}
}
impl SequencePosition {
#[must_use]
pub const fn at(ordinal: u32) -> Self {
Self(ordinal)
}
#[must_use]
pub const fn ordinal(self) -> u32 {
self.0
}
}
impl<Behavior, Postcondition> ScheduledFault<Behavior, Postcondition> {
#[must_use]
pub const fn at(
position: SequencePosition,
adapter: FaultAdapter<Behavior, Postcondition>,
) -> Self {
Self { position, adapter }
}
#[must_use]
pub const fn position(&self) -> SequencePosition {
self.position
}
#[must_use]
pub const fn adapter(&self) -> &FaultAdapter<Behavior, Postcondition> {
&self.adapter
}
}
impl<Behavior, Postcondition> FaultSchedule<Behavior, Postcondition> {
#[must_use]
pub fn declared(
name: NamespacedName,
faults: Vec<ScheduledFault<Behavior, Postcondition>>,
) -> Self {
Self { name, faults }
}
#[must_use]
pub const fn name(&self) -> NamespacedName {
self.name
}
#[must_use]
pub fn faults(&self) -> &[ScheduledFault<Behavior, Postcondition>] {
&self.faults
}
}
impl<Behavior, Postcondition> FaultCampaign<Behavior, Postcondition> {
pub fn declared(
schedules: Vec<FaultSchedule<Behavior, Postcondition>>,
) -> Result<Self, FaultCampaignRefusal> {
if schedules.is_empty() {
return Err(FaultCampaignRefusal::NoSchedule);
}
let mut seen = BTreeSet::new();
for schedule in &schedules {
if !seen.insert(schedule.name()) {
return Err(FaultCampaignRefusal::DuplicateSchedule(schedule.name()));
}
}
if schedules
.iter()
.all(|schedule| schedule.faults().is_empty())
{
return Err(FaultCampaignRefusal::NoFaultDeclared);
}
Ok(Self { schedules })
}
#[must_use]
pub fn schedules(&self) -> &[FaultSchedule<Behavior, Postcondition>] {
&self.schedules
}
pub fn select(
&self,
name: NamespacedName,
) -> Result<CampaignSelection<'_, Behavior, Postcondition>, FaultSelectionRefusal> {
self.schedules
.iter()
.find(|schedule| schedule.name() == name)
.map(|schedule| CampaignSelection { schedule })
.ok_or(FaultSelectionRefusal::ScheduleAbsent(name))
}
}
impl<'campaign, Behavior, Postcondition> CampaignSelection<'campaign, Behavior, Postcondition> {
#[must_use]
pub const fn schedule(&self) -> &'campaign FaultSchedule<Behavior, Postcondition> {
self.schedule
}
}
impl<Command, Behavior, Postcondition> InjectedCommand<Command, Behavior, Postcondition> {
#[must_use]
pub(crate) const fn injected(
command: Command,
faults: Vec<FaultAdapter<Behavior, Postcondition>>,
) -> Self {
Self { command, faults }
}
#[must_use]
pub const fn command(&self) -> &Command {
&self.command
}
#[must_use]
pub fn faults(&self) -> &[FaultAdapter<Behavior, Postcondition>] {
&self.faults
}
}
impl<Command, Behavior, Postcondition> InjectedSequence<Command, Behavior, Postcondition> {
#[must_use]
pub(crate) const fn injected(
schedule: NamespacedName,
commands: Vec<InjectedCommand<Command, Behavior, Postcondition>>,
) -> Self {
Self { schedule, commands }
}
#[must_use]
pub const fn schedule(&self) -> NamespacedName {
self.schedule
}
#[must_use]
pub fn commands(&self) -> &[InjectedCommand<Command, Behavior, Postcondition>] {
&self.commands
}
#[must_use]
pub fn fault_count(&self) -> usize {
self.commands
.iter()
.map(|command| command.faults().len())
.sum()
}
}