dscale 0.7.1

A fast & deterministic simulation framework for benchmarking and testing distributed systems
Documentation
// DScale: deterministic distributed systems simulator
// Copyright (C) 2026  Konstantin Shprenger

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

mod clock;
pub(crate) mod core;
mod fault;
pub(crate) mod scalable;
pub(crate) mod seq;

use crate::jiffy::Jiffies;

/// Outcome of a simulation run.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CompleteStatus {
    /// Ran all requested steps (for `run_steps`) or the full sub-budget (for `run_sub_budget`).
    Completed { steps: usize },
    /// The total time budget was exhausted.
    TimeBudgetExhausted { steps: usize },
    /// No more events to process — the simulation has quiesced.
    NoMoreEvents { steps: usize },
}

impl CompleteStatus {
    /// Number of steps that were actually executed.
    pub fn steps(&self) -> usize {
        match *self {
            CompleteStatus::Completed { steps }
            | CompleteStatus::TimeBudgetExhausted { steps }
            | CompleteStatus::NoMoreEvents { steps } => steps,
        }
    }
}

/// Execution engine returned by [`crate::SimulationBuilder::build`].
pub trait SimulationRunner {
    /// Runs the simulation until the total time budget is exhausted
    /// or no more events remain.
    fn run_full_budget(&mut self) -> CompleteStatus;

    /// Runs up to `k` steps and returns the outcome.
    ///
    /// The simulation can be resumed by calling this method again.
    fn run_steps(&mut self, k: usize) -> CompleteStatus;

    /// Runs the simulation for at most `sub_budget` additional time.
    ///
    /// Stops early if the total time budget is hit or no more events remain.
    /// The simulation can be resumed by calling any run method again.
    fn run_sub_budget(&mut self, sub_budget: Jiffies) -> CompleteStatus;
}

impl SimulationRunner for Box<dyn SimulationRunner> {
    fn run_full_budget(&mut self) -> CompleteStatus {
        (**self).run_full_budget()
    }
    fn run_steps(&mut self, k: usize) -> CompleteStatus {
        (**self).run_steps(k)
    }
    fn run_sub_budget(&mut self, sub_budget: Jiffies) -> CompleteStatus {
        (**self).run_sub_budget(sub_budget)
    }
}