# DETCORE — Deterministic Logic Core
[](https://github.com/aasyanov/detcore/actions/workflows/ci.yml)
[](https://crates.io/crates/detcore)
[](https://docs.rs/detcore)
[](https://opensource.org/licenses/MIT)
Minimal `no_std` deterministic state machine engine for Rust. Single dependency.
```toml
[dependencies]
detcore = "0.1"
```
## Overview
DETCORE is a generic state machine engine where `Logic::step` is a pure function: same state + same event = same output, always. All arithmetic is integer-only (`i64` fixed-point), time is injected externally, and the command buffer is stack-allocated with a fixed capacity.
Intended for embedded controllers, deterministic simulations, and systems where reproducibility matters. Not certified for safety-critical use (DO-178C, IEC 61508, etc.) — that requires domain-specific qualification beyond what a library can provide.
**Not** a scheduler, async runtime, event bus, or distributed system.
## Architecture
```
Event(seq, ts, payload)
│
▼
Engine::process
├── validate seq > last_seq (monotonic ordering)
├── Logic::step(state, event, commands) (pure transition)
└── check_invariants() (post-condition)
│
▼
Vec<Command<C>, 16> (bounded, stack-allocated)
```
- **Deterministic**: no system clock, no randomness, no heap
- **Fixed-point arithmetic**: `Decimal = i64`, `SCALE = 1_000_000` — avoids float precision issues
- **Monotonic sequencing**: events rejected if `seq` is not strictly increasing
- **Invariant checking**: `State::check_invariants()` runs after every transition
- **Bounded output**: `heapless::Vec<_, 16>` — no allocation, no overflow panic
- **`no_std`**: works on embedded targets, microcontrollers, bare metal
## Quick Start
```rust
use detcore::{Engine, Logic, Event, Command, State, Seq, Timestamp, Vec, SCALE};
#[derive(Clone)]
struct PumpState { pressure: i64, last_seq: Seq }
impl State for PumpState {
fn check_invariants(&self) -> bool { self.pressure >= 0 }
fn last_seq(&self) -> Seq { self.last_seq }
fn set_last_seq(&mut self, seq: Seq) { self.last_seq = seq }
}
#[derive(Clone, Copy)]
enum PumpEvent { PressureUpdate(i64) }
#[derive(Clone, PartialEq, Eq)]
enum PumpCommand { StopPump }
struct PumpLogic;
impl Logic<PumpState, PumpEvent, PumpCommand> for PumpLogic {
fn step(
state: &mut PumpState,
event: Event<PumpEvent>,
commands: &mut Vec<Command<PumpCommand>, 16>,
) {
match event.payload {
PumpEvent::PressureUpdate(p) => {
state.pressure = p;
if p > 100 * SCALE {
let _ = commands.push(Command::Emit(PumpCommand::StopPump));
}
}
}
}
}
let mut engine = Engine::<PumpState, PumpLogic, PumpEvent, PumpCommand>::new(
PumpState { pressure: 0, last_seq: Seq(0) },
);
let cmds = engine.process(Event {
seq: Seq(1),
ts: Timestamp(0),
payload: PumpEvent::PressureUpdate(120 * SCALE),
});
// cmds contains: [Emit(StopPump)]
```
## Public API
### Types
| `Decimal` | `i64` fixed-point type |
| `SCALE` | `1_000_000` — 6 decimal places of precision |
| `Seq(u64)` | Monotonic event sequence number |
| `Timestamp(u64)` | Externally-injected timestamp (not system clock) |
| `Event<E>` | Envelope: `seq` + `ts` + `payload` |
| `Command<C>` | `Emit(C)` or `NoOp` |
### Traits
| `State` | `check_invariants()`, `last_seq()`, `set_last_seq()` | System state with safety properties |
| `Logic<S,E,C>` | `step(state, event, commands)` | Pure deterministic transition function |
### Engine
| `Engine::new(state)` | Create engine with initial state |
| `engine.process(event)` | Process event, return `Vec<Command<C>, 16>` |
## Configuration
### `strict` Feature
Enables `assert!` for sequence validation and invariant checks in release builds. Default behavior uses `debug_assert!` only.
```toml
[dependencies]
detcore = { version = "0.1", features = ["strict"] }
```
| Default (debug) | `debug_assert!` panic | `debug_assert!` panic |
| Default (release) | Silent | Silent |
| `strict` (release) | `assert!` panic | `assert!` panic |
## Test Suite
```
cargo test: 10 passed, 0 failed, 1 doc-test passed
cargo clippy: 0 warnings
```
| Unit tests | 8 | Pressure safety, emergency stop, invariants, seq monotonicity, fixed-point, capacity, transitions, NoOp |
| Property tests | 2 | Arbitrary pressure values preserve invariants, sequence monotonicity across ranges |
| Doc-tests | 1 | Quick start example in lib.rs |
| Benchmarks | 6 | Single event, state clone, command generation, heapless vs std, large state |
## Dependencies
Single runtime dependency: `heapless 0.7`.
Dev-dependencies: `criterion` (benchmarks), `proptest` (property tests).
## File Structure
```
detcore/
├── src/
│ ├── lib.rs # Crate root, re-exports
│ ├── types.rs # Seq, Timestamp, Decimal, SCALE, Event, Command
│ ├── state.rs # State trait
│ ├── logic.rs # Logic trait
│ ├── engine.rs # Engine struct
│ └── tests/
│ ├── fixtures.rs # Shared test types
│ ├── unit.rs # Unit tests
│ └── property.rs # Property-based tests (proptest)
├── examples/
│ └── industrial_control.rs
├── benches/
│ └── engine_benchmark.rs
├── Cargo.toml
├── LICENSE
├── CHANGELOG.md
└── README.md
```
## License
MIT