use super::{
CampaignSelection, FaultInjectionRefusal, InjectedCommand, InjectedSequence, ScheduledFault,
};
pub fn inject<Command, Behavior: Clone, Postcondition: Clone>(
selection: &CampaignSelection<'_, Behavior, Postcondition>,
commands: Vec<Command>,
) -> Result<InjectedSequence<Command, Behavior, Postcondition>, FaultInjectionRefusal> {
let schedule = selection.schedule();
let places = places_within(schedule.faults(), commands.len())?;
let injected = commands
.into_iter()
.enumerate()
.map(|(index, command)| {
let faults = places
.iter()
.zip(schedule.faults())
.filter(|(place, _)| **place == index)
.map(|(_, scheduled)| scheduled.adapter().clone())
.collect();
InjectedCommand::injected(command, faults)
})
.collect();
Ok(InjectedSequence::injected(schedule.name(), injected))
}
fn places_within<Behavior, Postcondition>(
faults: &[ScheduledFault<Behavior, Postcondition>],
commands: usize,
) -> Result<Vec<usize>, FaultInjectionRefusal> {
if u32::try_from(commands.saturating_sub(1)).is_err() {
return Err(FaultInjectionRefusal::SequenceTooLong { commands });
}
faults
.iter()
.map(|scheduled| {
usize::try_from(scheduled.position().ordinal())
.ok()
.filter(|place| *place < commands)
.ok_or(FaultInjectionRefusal::PositionOutsideSequence {
position: scheduled.position(),
commands,
})
})
.collect()
}