pub struct SimulationBuilder { /* private fields */ }Expand description
Fluent builder for constructing a Simulation.
Builds a SimConfig internally and delegates to Simulation::new().
Provides a more ergonomic API for programmatic construction compared to
assembling a config struct manually.
§Constructors
SimulationBuilder::new— empty builder. You must add at least one stop and at least one elevator before.build(), or it errors.ScanDispatchis the default strategy, 60 ticks/s the default rate.SimulationBuilder::demo— pre-populated with two stops (Ground at 0.0, Top at 10.0) and one elevator, for doctests and quick prototyping. Override any piece with the fluent methods.
Implementations§
Source§impl SimulationBuilder
impl SimulationBuilder
Sourcepub fn new() -> Self
pub fn new() -> Self
Create an empty builder — no stops, no elevators, ScanDispatch as
the default strategy, and 60 ticks per second.
You must add at least one stop and at least one elevator (via
stops / stop and
elevators / elevator)
before build, or the build fails with
SimError::InvalidConfig.
If you want a quick, already-valid sim for prototyping or examples,
use demo.
use elevator_core::prelude::*;
use elevator_core::config::ElevatorConfig;
use elevator_core::stop::StopConfig;
// An empty builder errors on build — you must configure it first.
assert!(SimulationBuilder::new().build().is_err());
// Minimum valid configuration: at least one stop and one elevator.
let sim = SimulationBuilder::new()
.stops(vec![
StopConfig { id: StopId(0), name: "Ground".into(), position: 0.0 },
StopConfig { id: StopId(1), name: "Top".into(), position: 10.0 },
])
.elevator(ElevatorConfig {
id: 0,
name: "Main".into(),
max_speed: 2.0,
acceleration: 1.5,
deceleration: 2.0,
weight_capacity: 800.0,
starting_stop: StopId(0),
door_open_ticks: 10,
door_transition_ticks: 5,
restricted_stops: Vec::new(),
service_mode: None,
inspection_speed_factor: 0.25,
})
.build()
.unwrap();
assert_eq!(sim.current_tick(), 0);Sourcepub fn demo() -> Self
pub fn demo() -> Self
Pre-populated builder for zero-config examples, doctests, and quick prototyping where the building layout isn’t the point.
Provides two stops (Ground at 0.0, Top at 10.0) and one elevator
with SCAN dispatch. Use this when you want a working Simulation
in one call and don’t care about the specific stops.
use elevator_core::prelude::*;
let sim = SimulationBuilder::demo().build().unwrap();
assert_eq!(sim.current_tick(), 0);If you need a specific stop layout or elevator physics, use
new and configure every field explicitly — it reads
more clearly than threading overrides on top of demo’s defaults.
.stop() is a push onto the current stops list,
so calling it after demo() appends to the two defaults rather
than replacing them.
Sourcepub fn from_config(config: SimConfig) -> Self
pub fn from_config(config: SimConfig) -> Self
Create a builder from an existing SimConfig.
Uses ScanDispatch as the default strategy. Call .dispatch()
to override.
Sourcepub fn stops(self, stops: Vec<StopConfig>) -> Self
pub fn stops(self, stops: Vec<StopConfig>) -> Self
Replace all stops with the given list.
Clears any previously added stops.
Sourcepub fn stop(self, id: StopId, name: impl Into<String>, position: f64) -> Self
pub fn stop(self, id: StopId, name: impl Into<String>, position: f64) -> Self
Add a single stop to the building.
Sourcepub fn elevators(self, elevators: Vec<ElevatorConfig>) -> Self
pub fn elevators(self, elevators: Vec<ElevatorConfig>) -> Self
Replace all elevators with the given list.
Clears any previously added elevators.
Sourcepub fn elevator(self, config: ElevatorConfig) -> Self
pub fn elevator(self, config: ElevatorConfig) -> Self
Add a single elevator configuration.
Sourcepub fn line(self, config: LineConfig) -> Self
pub fn line(self, config: LineConfig) -> Self
Add a single line configuration.
Switches from legacy flat-elevator mode to explicit topology.
Sourcepub fn lines(self, lines: Vec<LineConfig>) -> Self
pub fn lines(self, lines: Vec<LineConfig>) -> Self
Replace all lines with the given list.
Switches from legacy flat-elevator mode to explicit topology.
Sourcepub fn group(self, config: GroupConfig) -> Self
pub fn group(self, config: GroupConfig) -> Self
Add a single group configuration.
Sourcepub fn groups(self, groups: Vec<GroupConfig>) -> Self
pub fn groups(self, groups: Vec<GroupConfig>) -> Self
Replace all groups with the given list.
Sourcepub const fn ticks_per_second(self, tps: f64) -> Self
pub const fn ticks_per_second(self, tps: f64) -> Self
Set the simulation tick rate (ticks per second).
Sourcepub fn building_name(self, name: impl Into<String>) -> Self
pub fn building_name(self, name: impl Into<String>) -> Self
Set the building name.
Sourcepub fn dispatch(self, strategy: impl DispatchStrategy + 'static) -> Self
pub fn dispatch(self, strategy: impl DispatchStrategy + 'static) -> Self
Set the default dispatch strategy for the default group.
Sourcepub fn dispatch_for_group(
self,
group: GroupId,
strategy: impl DispatchStrategy + 'static,
) -> Self
pub fn dispatch_for_group( self, group: GroupId, strategy: impl DispatchStrategy + 'static, ) -> Self
Set a dispatch strategy for a specific group.
Sourcepub fn before(
self,
phase: Phase,
hook: impl Fn(&mut World) + Send + Sync + 'static,
) -> Self
pub fn before( self, phase: Phase, hook: impl Fn(&mut World) + Send + Sync + 'static, ) -> Self
Register a hook to run before a simulation phase.
Sourcepub fn after(
self,
phase: Phase,
hook: impl Fn(&mut World) + Send + Sync + 'static,
) -> Self
pub fn after( self, phase: Phase, hook: impl Fn(&mut World) + Send + Sync + 'static, ) -> Self
Register a hook to run after a simulation phase.
Sourcepub fn before_group(
self,
phase: Phase,
group: GroupId,
hook: impl Fn(&mut World) + Send + Sync + 'static,
) -> Self
pub fn before_group( self, phase: Phase, group: GroupId, hook: impl Fn(&mut World) + Send + Sync + 'static, ) -> Self
Register a hook to run before a phase for a specific group.
Sourcepub fn after_group(
self,
phase: Phase,
group: GroupId,
hook: impl Fn(&mut World) + Send + Sync + 'static,
) -> Self
pub fn after_group( self, phase: Phase, group: GroupId, hook: impl Fn(&mut World) + Send + Sync + 'static, ) -> Self
Register a hook to run after a phase for a specific group.
Sourcepub fn reposition(
self,
strategy: impl RepositionStrategy + 'static,
id: BuiltinReposition,
) -> Self
pub fn reposition( self, strategy: impl RepositionStrategy + 'static, id: BuiltinReposition, ) -> Self
Set a reposition strategy for the default group.
Enables the reposition phase, which runs after dispatch to move idle elevators for better coverage.
Sourcepub fn reposition_for_group(
self,
group: GroupId,
strategy: impl RepositionStrategy + 'static,
id: BuiltinReposition,
) -> Self
pub fn reposition_for_group( self, group: GroupId, strategy: impl RepositionStrategy + 'static, id: BuiltinReposition, ) -> Self
Set a reposition strategy for a specific group.
Sourcepub fn with_ext<T: 'static + Send + Sync + Serialize + DeserializeOwned>(
self,
name: &str,
) -> Self
pub fn with_ext<T: 'static + Send + Sync + Serialize + DeserializeOwned>( self, name: &str, ) -> Self
Pre-register an extension type for snapshot deserialization.
Extensions registered here will be available immediately after build()
without needing to call register_ext manually.
Sourcepub fn validate(&self) -> Result<(), SimError>
pub fn validate(&self) -> Result<(), SimError>
Validate the configuration without building the simulation.
Runs the same validation as build() but does not
allocate entities or construct the simulation. Useful for CLI tools,
config editors, and dry-run checks.
§Errors
Returns SimError::InvalidConfig if the configuration is invalid.
Sourcepub fn build(self) -> Result<Simulation, SimError>
pub fn build(self) -> Result<Simulation, SimError>
Build the simulation, validating the configuration.
Returns Err(SimError) if the configuration is invalid.
§Errors
Returns SimError::InvalidConfig if the assembled configuration is invalid.
§Examples
use elevator_core::prelude::*;
use elevator_core::stop::StopConfig;
let mut sim = SimulationBuilder::demo()
.stops(vec![
StopConfig { id: StopId(0), name: "Lobby".into(), position: 0.0 },
StopConfig { id: StopId(1), name: "Roof".into(), position: 20.0 },
])
.build()
.unwrap();
sim.spawn_rider_by_stop_id(StopId(0), StopId(1), 75.0).unwrap();
for _ in 0..1000 {
sim.step();
}
assert!(sim.metrics().total_delivered() > 0);