From eb6df5425507ecb5f1b82b8c1f40699c848efdf4 Mon Sep 17 00:00:00 2001 From: Ali Salehi Date: Wed, 22 Apr 2026 15:29:14 +0200 Subject: [PATCH] Initialize simulation Cargo workspace and crate scaffolding --- .gitignore | 1 + Cargo.lock | 33 ++++++++++++++++++++++++++++++++ Cargo.toml | 20 +++++++++++++++++++ crates/sim-cli/Cargo.toml | 15 +++++++++++++++ crates/sim-cli/src/lib.rs | 24 +++++++++++++++++++++++ crates/sim-cli/src/main.rs | 25 ++++++++++++++++++++++++ crates/sim-core/.gitignore | 1 + crates/sim-core/Cargo.toml | 7 +++++++ crates/sim-core/src/lib.rs | 37 ++++++++++++++++++++++++++++++++++++ crates/sim-proto/Cargo.toml | 7 +++++++ crates/sim-proto/src/lib.rs | 27 ++++++++++++++++++++++++++ crates/sim-server/Cargo.toml | 9 +++++++++ crates/sim-server/src/lib.rs | 35 ++++++++++++++++++++++++++++++++++ crates/sim-ui/Cargo.toml | 17 +++++++++++++++++ crates/sim-ui/src/lib.rs | 3 +++ crates/sim-ui/src/main.rs | 3 +++ 16 files changed, 264 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 crates/sim-cli/Cargo.toml create mode 100644 crates/sim-cli/src/lib.rs create mode 100644 crates/sim-cli/src/main.rs create mode 100644 crates/sim-core/.gitignore create mode 100644 crates/sim-core/Cargo.toml create mode 100644 crates/sim-core/src/lib.rs create mode 100644 crates/sim-proto/Cargo.toml create mode 100644 crates/sim-proto/src/lib.rs create mode 100644 crates/sim-server/Cargo.toml create mode 100644 crates/sim-server/src/lib.rs create mode 100644 crates/sim-ui/Cargo.toml create mode 100644 crates/sim-ui/src/lib.rs create mode 100644 crates/sim-ui/src/main.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..2db6e9b --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,33 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "sim-cli" +version = "0.1.0" +dependencies = [ + "sim-core", + "sim-proto", + "sim-server", + "sim-ui", +] + +[[package]] +name = "sim-core" +version = "0.1.0" + +[[package]] +name = "sim-proto" +version = "0.1.0" + +[[package]] +name = "sim-server" +version = "0.1.0" +dependencies = [ + "sim-core", + "sim-proto", +] + +[[package]] +name = "sim-ui" +version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..1e9dd47 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,20 @@ +[workspace] +members = [ + "crates/sim-core", + "crates/sim-proto", + "crates/sim-server", + "crates/sim-cli", + "crates/sim-ui", +] +resolver = "2" + +[workspace.package] +edition = "2021" +license = "MIT" +version = "0.1.0" + +[workspace.dependencies] +sim-core = { path = "crates/sim-core" } +sim-proto = { path = "crates/sim-proto" } +sim-server = { path = "crates/sim-server" } +sim-ui = { path = "crates/sim-ui" } diff --git a/crates/sim-cli/Cargo.toml b/crates/sim-cli/Cargo.toml new file mode 100644 index 0000000..2b2b1b4 --- /dev/null +++ b/crates/sim-cli/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "sim-cli" +version.workspace = true +edition.workspace = true +license.workspace = true + +[dependencies] +sim-core.workspace = true +sim-proto.workspace = true +sim-server.workspace = true +sim-ui = { workspace = true, optional = true } + +[features] +default = [] +ui = ["dep:sim-ui"] diff --git a/crates/sim-cli/src/lib.rs b/crates/sim-cli/src/lib.rs new file mode 100644 index 0000000..2d048b6 --- /dev/null +++ b/crates/sim-cli/src/lib.rs @@ -0,0 +1,24 @@ +use sim_proto::SimulationRequest; +use sim_server::SimulationService; + +pub type CliResult = Result>; + +pub fn realtime_entrypoint(steps: u32) -> CliResult<()> { + let mut service = SimulationService::new(); + for _ in 0..steps { + let _ = service.handle_step(SimulationRequest { + delta_time_seconds: 1.0 / 60.0, + })?; + } + Ok(()) +} + +pub fn fixed_step_entrypoint(steps: u32, dt_seconds: f32) -> CliResult<()> { + let mut service = SimulationService::new(); + for _ in 0..steps { + let _ = service.handle_step(SimulationRequest { + delta_time_seconds: dt_seconds, + })?; + } + Ok(()) +} diff --git a/crates/sim-cli/src/main.rs b/crates/sim-cli/src/main.rs new file mode 100644 index 0000000..255d250 --- /dev/null +++ b/crates/sim-cli/src/main.rs @@ -0,0 +1,25 @@ +use std::env; + +fn main() -> Result<(), Box> { + let mut args = env::args().skip(1); + let mode = args.next().unwrap_or_else(|| "realtime".to_string()); + + match mode.as_str() { + "realtime" => { + let steps = args.next().and_then(|v| v.parse().ok()).unwrap_or(600); + sim_cli::realtime_entrypoint(steps) + } + "fixed-step" => { + let steps = args.next().and_then(|v| v.parse().ok()).unwrap_or(600); + let dt_seconds = args + .next() + .and_then(|v| v.parse().ok()) + .unwrap_or(1.0 / 120.0); + sim_cli::fixed_step_entrypoint(steps, dt_seconds) + } + _ => { + eprintln!("Usage: sim-cli [realtime [steps] | fixed-step [steps] [dt_seconds]]"); + Ok(()) + } + } +} diff --git a/crates/sim-core/.gitignore b/crates/sim-core/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/crates/sim-core/.gitignore @@ -0,0 +1 @@ +/target diff --git a/crates/sim-core/Cargo.toml b/crates/sim-core/Cargo.toml new file mode 100644 index 0000000..2d3940d --- /dev/null +++ b/crates/sim-core/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "sim-core" +version.workspace = true +edition.workspace = true +license.workspace = true + +[dependencies] diff --git a/crates/sim-core/src/lib.rs b/crates/sim-core/src/lib.rs new file mode 100644 index 0000000..3282a1c --- /dev/null +++ b/crates/sim-core/src/lib.rs @@ -0,0 +1,37 @@ +#[derive(Debug, Clone)] +pub struct WorldState { + pub tick: u64, + pub simulation_time_seconds: f32, +} + +#[derive(Debug, Clone)] +pub struct Simulator { + world: WorldState, +} + +impl Default for Simulator { + fn default() -> Self { + Self::new() + } +} + +impl Simulator { + pub fn new() -> Self { + Self { + world: WorldState { + tick: 0, + simulation_time_seconds: 0.0, + }, + } + } + + pub fn step(&mut self, dt_seconds: f32) -> &WorldState { + self.world.tick += 1; + self.world.simulation_time_seconds += dt_seconds.max(0.0); + &self.world + } + + pub fn world(&self) -> &WorldState { + &self.world + } +} diff --git a/crates/sim-proto/Cargo.toml b/crates/sim-proto/Cargo.toml new file mode 100644 index 0000000..be5f7c7 --- /dev/null +++ b/crates/sim-proto/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "sim-proto" +version.workspace = true +edition.workspace = true +license.workspace = true + +[dependencies] diff --git a/crates/sim-proto/src/lib.rs b/crates/sim-proto/src/lib.rs new file mode 100644 index 0000000..5214680 --- /dev/null +++ b/crates/sim-proto/src/lib.rs @@ -0,0 +1,27 @@ +#[derive(Debug, Clone)] +pub struct SimulationRequest { + pub delta_time_seconds: f32, +} + +#[derive(Debug, Clone)] +pub struct SimulationResponse { + pub tick: u64, + pub simulation_time_seconds: f32, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ProtocolError { + InvalidDeltaTime, +} + +impl core::fmt::Display for ProtocolError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + ProtocolError::InvalidDeltaTime => { + f.write_str("invalid request: delta_time_seconds must be finite and non-negative") + } + } + } +} + +impl std::error::Error for ProtocolError {} diff --git a/crates/sim-server/Cargo.toml b/crates/sim-server/Cargo.toml new file mode 100644 index 0000000..9786ec1 --- /dev/null +++ b/crates/sim-server/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "sim-server" +version.workspace = true +edition.workspace = true +license.workspace = true + +[dependencies] +sim-core.workspace = true +sim-proto.workspace = true diff --git a/crates/sim-server/src/lib.rs b/crates/sim-server/src/lib.rs new file mode 100644 index 0000000..81378d7 --- /dev/null +++ b/crates/sim-server/src/lib.rs @@ -0,0 +1,35 @@ +use sim_core::Simulator; +use sim_proto::{ProtocolError, SimulationRequest, SimulationResponse}; + +pub struct SimulationService { + simulator: Simulator, +} + +impl Default for SimulationService { + fn default() -> Self { + Self::new() + } +} + +impl SimulationService { + pub fn new() -> Self { + Self { + simulator: Simulator::new(), + } + } + + pub fn handle_step( + &mut self, + request: SimulationRequest, + ) -> Result { + if !request.delta_time_seconds.is_finite() || request.delta_time_seconds < 0.0 { + return Err(ProtocolError::InvalidDeltaTime); + } + + let world = self.simulator.step(request.delta_time_seconds); + Ok(SimulationResponse { + tick: world.tick, + simulation_time_seconds: world.simulation_time_seconds, + }) + } +} diff --git a/crates/sim-ui/Cargo.toml b/crates/sim-ui/Cargo.toml new file mode 100644 index 0000000..d51c4ea --- /dev/null +++ b/crates/sim-ui/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "sim-ui" +version.workspace = true +edition.workspace = true +license.workspace = true + +[lib] +path = "src/lib.rs" + +[[bin]] +name = "sim-ui" +path = "src/main.rs" +required-features = ["runtime"] + +[features] +default = [] +runtime = [] diff --git a/crates/sim-ui/src/lib.rs b/crates/sim-ui/src/lib.rs new file mode 100644 index 0000000..43a4e56 --- /dev/null +++ b/crates/sim-ui/src/lib.rs @@ -0,0 +1,3 @@ +pub fn launch() { + // Placeholder for a future visual frontend. +} diff --git a/crates/sim-ui/src/main.rs b/crates/sim-ui/src/main.rs new file mode 100644 index 0000000..d3fd472 --- /dev/null +++ b/crates/sim-ui/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + sim_ui::launch(); +}