use super::{
ADDRESSABLE_STRANDS, Counterexample, ExplorationBound, ExplorationBoundRefusal,
ExplorationMode, ExplorationReading, ExplorationSite, ExplorationStanding, InterleavedSequence,
Interleaving, InterleavingSpace, Strand, StrandRefusal, StrandSet, StrandSetRefusal,
};
use crate::descriptor::NamespacedName;
use crate::generate::{CaseWidth, CaseWidthRefusal};
use crate::report::TrialFinding;
use std::collections::BTreeSet;
impl<Command> Strand<Command> {
pub fn declared(name: NamespacedName, commands: Vec<Command>) -> Result<Self, StrandRefusal> {
if commands.is_empty() {
return Err(StrandRefusal::EmptyStrand(name));
}
Ok(Self { name, commands })
}
#[must_use]
pub const fn name(&self) -> NamespacedName {
self.name
}
#[must_use]
pub fn commands(&self) -> &[Command] {
&self.commands
}
}
impl<Command> StrandSet<Command> {
pub fn declared(strands: Vec<Strand<Command>>) -> Result<Self, StrandSetRefusal> {
unique_names(&strands)?;
if strands.len() > ADDRESSABLE_STRANDS {
return Err(StrandSetRefusal::MoreStrandsThanAddressable {
strands: strands.len(),
});
}
let (steps, width) = steps_and_width(&strands)?;
if strands.len() < 2 {
return Err(StrandSetRefusal::FewerThanTwoStrands {
strands: strands.len(),
});
}
Ok(Self {
strands,
steps,
width,
})
}
#[must_use]
pub fn strands(&self) -> &[Strand<Command>] {
&self.strands
}
#[must_use]
pub const fn steps(&self) -> usize {
self.steps
}
#[must_use]
pub(crate) const fn width(&self) -> CaseWidth {
self.width
}
}
fn unique_names<Command>(strands: &[Strand<Command>]) -> Result<(), StrandSetRefusal> {
let mut seen = BTreeSet::new();
for strand in strands {
if !seen.insert(strand.name()) {
return Err(StrandSetRefusal::DuplicateStrand(strand.name()));
}
}
Ok(())
}
fn steps_and_width<Command>(
strands: &[Strand<Command>],
) -> Result<(usize, CaseWidth), StrandSetRefusal> {
let mut steps = 0usize;
for strand in strands {
steps = steps
.checked_add(strand.commands().len())
.ok_or(StrandSetRefusal::StepsUnaddressable)?;
}
match CaseWidth::declared(steps) {
Ok(width) => Ok((steps, width)),
Err(CaseWidthRefusal::ZeroBytes) => Err(StrandSetRefusal::FewerThanTwoStrands {
strands: strands.len(),
}),
}
}
impl Interleaving {
#[must_use]
pub const fn declared(choices: Vec<u8>) -> Self {
Self { choices }
}
#[must_use]
pub fn choices(&self) -> &[u8] {
&self.choices
}
}
impl<Command> InterleavedSequence<Command> {
#[must_use]
pub(crate) const fn realized(interleaving: Interleaving, commands: Vec<Command>) -> Self {
Self {
interleaving,
commands,
}
}
#[must_use]
pub const fn interleaving(&self) -> &Interleaving {
&self.interleaving
}
#[must_use]
pub fn commands(&self) -> &[Command] {
&self.commands
}
}
impl ExplorationBound {
pub const fn declared(
interleavings: u32,
samples: u32,
) -> Result<Self, ExplorationBoundRefusal> {
if interleavings == 0u32 {
return Err(ExplorationBoundRefusal::ZeroInterleavings);
}
if samples == 0u32 {
return Err(ExplorationBoundRefusal::ZeroSamples);
}
Ok(Self {
interleavings,
samples,
})
}
#[must_use]
pub const fn interleavings(self) -> u32 {
self.interleavings
}
#[must_use]
pub const fn samples(self) -> u32 {
self.samples
}
}
impl Counterexample {
#[must_use]
pub(crate) const fn found(
site: ExplorationSite,
interleaving: Interleaving,
finding: TrialFinding,
) -> Self {
Self {
site,
interleaving,
finding,
}
}
#[must_use]
pub const fn site(&self) -> ExplorationSite {
self.site
}
#[must_use]
pub const fn interleaving(&self) -> &Interleaving {
&self.interleaving
}
#[must_use]
pub const fn finding(&self) -> &TrialFinding {
&self.finding
}
}
impl ExplorationReading {
#[must_use]
pub(crate) const fn read(
space: InterleavingSpace,
mode: ExplorationMode,
explored: u64,
standing: ExplorationStanding,
) -> Self {
Self {
space,
mode,
explored,
standing,
}
}
#[must_use]
pub const fn space(&self) -> InterleavingSpace {
self.space
}
#[must_use]
pub const fn mode(&self) -> ExplorationMode {
self.mode
}
#[must_use]
pub const fn explored(&self) -> u64 {
self.explored
}
#[must_use]
pub const fn standing(&self) -> &ExplorationStanding {
&self.standing
}
}