oxide_core
oxide_core is the Rust-side engine for Oxide. It provides the primitives for:
- Defining reducers (
Reducer) - Owning state in an engine (
ReducerEngine) - Streaming revisioned snapshots (
StateSnapshot<T>) - Optional persistence helpers (feature-gated)
This crate is intentionally usage-agnostic. For end-to-end Rust ↔ Flutter wiring, see the repository examples and the root README.
Add It To Your Crate
In your Cargo.toml:
[]
= "0.2.0"
When working inside this repository, use a combined version + path dependency (Cargo prefers path locally, while published crates resolve by version):
= { = "0.2.0", = "../rust/oxide_core" }
Core Concepts
Reducer
Reducers are stateful controllers that mutate state in response to actions and side-effects:
use ;
;
ReducerEngine
ReducerEngine<R> is the async-safe facade for dispatching actions and observing snapshots:
use ReducerEngine;
# use ;
# use InitContext;
#
#
#
#
#
#
# ;
#
let runtime = new.unwrap;
runtime.block_on;
Async Runtime Behavior
ReducerEngine starts an internal async loop to process side-effects. Engine creation is safe even when there is no ambient Tokio runtime (for example, when entered from a synchronous FFI boundary):
- If a Tokio runtime is currently available, Oxide spawns tasks onto it.
- On native targets, if no runtime is available and
internal-runtimeis enabled (default), Oxide falls back to an internal global Tokio runtime for background work. - On web WASM (
wasm32-unknown-unknown), Oxide useswasm-bindgen-futuresto spawn background work without requiring a Tokio runtime.
In a normal Rust binary, the simplest approach is to run inside a Tokio runtime:
use ReducerEngine;
async
Invariant: No Partial Mutation On Error
Dispatch uses clone-first semantics:
- The current state is cloned.
- The reducer runs against the clone.
- If the reducer returns
StateChange::None, the clone is discarded and no snapshot is emitted. - If the reducer returns an error, the live state is not updated and no snapshot is emitted.
This makes it safe to write reducers as normal &mut State code while preserving strong error semantics.
Sliced Updates (Optional)
Sliced updates allow snapshots to carry lightweight metadata describing which top-level parts of state changed, so binding layers (like Flutter) can avoid rebuilding when irrelevant fields update.
- Opt-in: slicing is only meaningful when the state type implements
SlicedState(typically generated byoxide_generator_rsvia#[state(sliced = true)]). - Reducer signaling:
- Return
StateChange::Inferto ask the engine to callReducer::infer_slices(before, after). - Return
StateChange::Slices(&[...])to explicitly declare which slices changed. - Return
StateChange::Fullfor a full update.
- Return
- Snapshot semantics:
snapshot.stateis always the full state.snapshot.slices.is_empty()is treated as a full update.
If you are not using sliced updates, you can ignore snapshot.slices (it will remain empty).
Feature Flags
frb-spawn(default): enables FRB’sspawnhelper for cross-platform task spawningstate-persistence: enables bincode encode/decode helpers inoxide_core::persistencepersistence-json: adds JSON encode/decode helpers (requiresstate-persistence)full: enables all persistence featuresinternal-runtime(default): enables a global Tokio runtime fallback on native targets
Web / WASM Support
oxide_core supports compiling for WebAssembly. The supported targets differ in what persistence backend is available:
wasm32-unknown-unknown(web): background tasks are spawned withwasm-bindgen-futures. Whenstate-persistenceis enabled, persisted snapshots are stored inlocalStorageusing a stable key derived fromPersistenceConfig.key.wasm32-wasip1(WASI): compilation is supported. Whenstate-persistenceis enabled, snapshots are persisted to the filesystem.
Build Commands
From rust/:
WASM Tests
oxide_core includes WASM-focused regression tests:
wasm_web_compat(web): validatesReducerEnginedispatch in browser WASM and (when enabled) persistence restore usinglocalStorage.wasm_wasi_compat(WASI): compile-level compatibility check forwasm32-wasip1.
To compile the web test crate:
Troubleshooting
#[tokio::test]does not work onwasm32-unknown-unknown. Usewasm-bindgen-testfor web WASM tests and keep Tokio-based tests for native targets.- Web persistence uses
localStorageand therefore requires a browser environment. If you run WASM tests under Node.js,window/localStoragemay not be available. - Persistence is debounced: writes are throttled to at most once per
PersistenceConfig.min_interval, always persisting the latest snapshot payload observed during the interval.
Commands
From rust/:
To run benches (if enabled for your environment):
License
Dual-licensed under MIT OR Apache-2.0. See LICENSE.