Skip to content

3.1 RustBackend

Raul Cardenas Montoya edited this page Sep 19, 2026 · 1 revision

RustBackend

Relevant source files

The following files were used as context for generating this wiki page:

The RustBackend is a native, pure-Rust implementation of the IpcBackend trait. Unlike the ZmqIpcBackend, it has no external dependencies and requires no external compute engine (e.g., Julia) to function. It serves as the default software fallback and a high-performance smoke-test stub for the corpus-ipc ecosystem.

Overview and Purpose

The RustBackend is designed for three primary use cases:

  1. Smoke Testing: Validating the signal pipeline without the overhead of ZMQ or a running external environment.
  2. Push-Pull Encoding: Providing a reference implementation of a signal-to-spike encoding algorithm where positive and negative magnitudes are isolated into separate channels.
  3. Stateless Fallback: Serving as a "pass-through" model when complex neural dynamics are not required.

Key Characteristics

Feature Implementation Detail
Statefulness Stateless; does not track internal membrane potentials or synaptic weights.
Complexity $O(N)$ where $N$ is the number of input channels.
Dependencies None (Standard Library only).
Lifecycle Requires explicit initialization via initialize() before processing.

Sources: src/rust_backend.rs:3-17


The Push-Pull Encoding Algorithm

The core logic of the RustBackend resides in its process_batch implementation. It transforms a continuous input vector into a push-pull encoded output vector of double the length.

Encoding Logic

For every input channel i in the inputs slice, the backend generates two output channels in the resulting Vec<f32>:

Data Flow Diagram: Signal Encoding

The following diagram illustrates how the RustBackend::process_batch function maps input data to the encoded output vector.

graph TD
    subgraph "Natural Language Space"
        Input["Input Signals (f32)"]
        Logic{"Encoding Logic"}
        Output["Encoded Output (f32)"]
    end

    subgraph "Code Entity Space"
        inputs["inputs: &[f32]"]
        process["RustBackend::process_batch"]
        output_vec["output: Vec<f32>"]
        
        pos["Positive Channel (i*2)"]
        neg["Negative Channel (i*2+1)"]
    end

    Input --> inputs
    inputs --> process
    process --> Logic
    Logic -- "val > 0.0" --> pos
    Logic -- "val <= 0.0" --> neg
    pos --> output_vec
    neg --> output_vec
    output_vec --> Output
Loading

Sources: src/rust_backend.rs:9-11, src/rust_backend.rs:33-53, src/rust_backend.rs:89-106


Initialization Lifecycle

The RustBackend maintains a simple internal state machine via the initialized boolean flag src/rust_backend.rs:16-16.

  1. Creation: RustBackend::new() src/rust_backend.rs:21-23 or RustBackend::default() src/rust_backend.rs:26-30 sets initialized to false.
  2. Activation: initialize(Option<&str>) src/rust_backend.rs:55-58 must be called to set initialized to true. The model_path argument is currently ignored as the backend is stateless.
  3. Validation: Every call to process_batch checks the initialized flag src/rust_backend.rs:34-38. If false, it returns BackendError::InitializationError.
  4. Reset: Calling reset() src/rust_backend.rs:69-75 sets initialized back to false, requiring a new initialize() call before further processing.

Lifecycle Sequence

sequenceDiagram
    participant App as "Application Logic"
    participant RB as "RustBackend [src/rust_backend.rs]"
    
    App->>RB: "new()"
    Note over RB: initialized = false
    
    App->>RB: "process_batch(inputs)"
    RB-->>App: "Err(BackendError::InitializationError)"
    
    App->>RB: "initialize(None)"
    Note over RB: initialized = true
    RB-->>App: "Ok(())"
    
    App->>RB: "process_batch(inputs)"
    Note over RB: Run Push-Pull Algorithm
    RB-->>App: "Ok(output_vec)"

    App->>RB: "reset()"
    Note over RB: initialized = false
    RB-->>App: "Ok(())"
Loading

Sources: src/rust_backend.rs:21-23, src/rust_backend.rs:33-38, src/rust_backend.rs:55-58, src/rust_backend.rs:69-75


Stateless Design and Stub Methods

Because the RustBackend is designed as a functional transform rather than a simulation, several IpcBackend trait methods are implemented as stubs:

  • save_state(&self, _model_path: &str): Returns Ok(()) immediately src/rust_backend.rs:60-62. Since there are no weights or membrane potentials, there is nothing to persist.
  • get_spike_states(&self): Returns an empty Vec<bool> src/rust_backend.rs:64-67. It does not track discrete spike events over time.
  • reset(&mut self): Clears the initialized flag for consistency with other backends but performs no data clearing as the backend is stateless src/rust_backend.rs:69-75.

Sources: src/rust_backend.rs:60-75


Unit Test Suite

The RustBackend includes a comprehensive test suite in src/rust_backend.rs that validates the encoding logic and lifecycle constraints.

Test Function Purpose
process_before_init_returns_error Ensures the backend rejects signal processing if initialize() hasn't been called src/rust_backend.rs:83-86.
positive_input_goes_to_even_channel Verifies that a value like 0.8 appears at index i*2 and index i*2+1 is 0.0 src/rust_backend.rs:89-96.
negative_input_goes_to_odd_channel Verifies that a value like -0.5 appears as 0.5 (absolute value) at index i*2+1 and index i*2 is 0.0 src/rust_backend.rs:99-106.
output_has_double_the_elements Confirms the output vector length is exactly $2 \times$ the input length src/rust_backend.rs:109-116.
spike_states_is_empty Confirms the stateless nature by checking for an empty spike vector src/rust_backend.rs:119-122.
reset_clears_initialized_and_next_process_fails Verifies that reset() correctly forces a re-initialization requirement src/rust_backend.rs:125-132.

Sources: src/rust_backend.rs:79-133

Clone this wiki locally