plexor-core 0.1.0-alpha.1

Core library for the rust implementation of the Plexo distributed system architecture, providing the fundamental Plexus, Neuron, Codec, and Axon abstractions.
Documentation

Plexor Core

Plexor Core is the foundational library of the Plexo architecture—a language-agnostic distributed system and message processing framework inspired by biological neural networks.

This crate provides the essential abstractions and the central routing logic ("Plexus") that decouples signal definition from transport implementation.

Features

  • Biological Metaphor: Intuitive concepts like Neurons (signals), Axons (transmitters), and Synapses (receivers).
  • Transport Agnostic: The core logic is independent of the underlying network layer. Transports (ZeroMQ, HTTP, etc.) are pluggable "Ganglia".
  • Type-Safe Routing: Strongly typed signals within the process, with safe erasure for dynamic routing.
  • Asynchronous: Built on tokio and futures for high-performance async message passing.

Motivation

Building distributed systems often involves a significant amount of "drudge work" that pollutes application logic:

  • Transport Boilerplate: Writing the same ZMQ socket loops, HTTP pollers, or WebSocket handlers over and over.
  • Manual Routing: Hardcoding which service handles which message type and manually managing those connections.
  • Implicit Contracts: Relying on fragile naming conventions or complex glue code to bridge different parts of a system.
  • Cross-Cutting Concerns: Re-implementing tracing, correlation IDs, and error propagation for every new network boundary.

Plexor solves this by decoupling your Signals from your Transports:

  1. Define your Signals (Neurons): You focus on the data and the codec once.
  2. Define your Logic (Reactants): Your code reacts to signals arriving at a Synapse, regardless of whether they came from a local thread or a ZMQ socket 1,000 miles away.
  3. Dynamic Wiring: Using the Plexus (the hub) and Ganglia (the bridges), you can "infuse" different transport layers into your system at runtime.

The biological metaphor provides a mental model where the network is a living organism: you don't call "endpoints," you fire "Axons" into a "Plexus," and the system handles the heavy lifting of routing and encoding automatically.

Core Concepts

  • Neuron: The fundamental unit of identity. It defines the schema (data structure), the codec (how it's encoded), and its unique namespace in the network.
  • Plexus: The "brain" of the system. It interconnects multiple Ganglia and manages the complex routing logic required to move signals between them.
  • Axon: Your primary interface for "firing" a signal. It's a high-level, strongly-typed handle used to transmit messages into the Plexus.
  • Synapse & Reactant: The receiving end. A Synapse filters for specific Neurons, and a Reactant is the logic that "triggers" when that signal arrives.
  • Ganglion: A node in the network. It can be a transport bridge (ZMQ, HTTP, etc.) or a processing hub. Ganglia handle the physical transmission of signals.

Usage

In-Process Example

This example demonstrates a simple local message passing setup using the built-in TextCodec.

Note: This example assumes you have tokio in your dependencies.

use plexor_core::neuron::{Neuron, NeuronImpl};
use plexor_core::plexus::Plexus;
use plexor_core::axon::{Axon, AxonImpl};
use plexor_core::reactant::{Reactant, ReactantError};
use plexor_core::payload::Payload;
use plexor_core::erasure::reactant::ReactantErased;
use plexor_core::namespace::NamespaceImpl;
use plexor_core::codec::TextCodec;
use std::sync::Arc;

#[derive(Clone)]
struct MyReactant;

impl Reactant<String, TextCodec> for MyReactant {
    fn react(&self, payload: Arc<Payload<String, TextCodec>>) -> std::pin::Pin<Box<dyn std::future::Future<Output = Result<(), ReactantError>> + Send + 'static>> {
        Box::pin(async move {
            println!("Received: {}", payload.value);
            Ok(())
        })
    }
    fn erase(self: Box<Self>) -> Arc<dyn ReactantErased + Send + Sync + 'static> {
        plexor_core::erasure::reactant::erase_reactant(self)
    }
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 1. Define Identity
    let ns = Arc::new(NamespaceImpl { delimiter: ".", parts: vec!["hello", "world"] });
    let neuron = NeuronImpl::<String, TextCodec>::new_arc(ns);

    // 2. Create the Plexus (The Brain)
    let plexus_arc = Plexus::new_shared(vec![], vec![]).await;
    
    // 3. Register a Reactant (The Receiver)
    {
        let mut p = plexus_arc.lock().await;
        // Adapt ensures the Plexus knows how to route this specific Neuron
        p.adapt(neuron.clone()).await?;
        // Link the Reactant to the Neuron
        p.react(neuron.name(), vec![Box::new(MyReactant).erase()], vec![]).await?;
    }
    
    // 4. Create an Axon (The Transmitter) and Fire!
    let mut axon = AxonImpl::new(neuron, plexus_arc);
    axon.transmit("Hello, Plexor!".to_string()).await?;

    Ok(())
}

Implementation Details

Type Erasure & Unsafe

To achieve a Universal Plexus capable of routing an infinite variety of user-defined types without compile-time knowledge, Plexor utilizes type erasure and unsafe transmutes.

  • Dynamic Type Mapping: Particularly for External Ganglia, incoming byte streams must be dynamically mapped to concrete Rust types at runtime based on string-based identities.
  • Safety: All unsafe operations are strictly guarded by TypeId equality verification at runtime. We only step outside the safe sandbox once we have absolute proof that the memory layout matches the expected type.
  • Rationale: This approach overcomes the limitations of standard Any downcasting in complex generic contexts across trait boundaries, which is a common hurdle in building pluggable distributed frameworks.

Ecosystem

To build a distributed system, combine plexor-core with other crates in the ecosystem:

  • Codecs:
    • plexor-codec-serde-json: JSON serialization.
    • plexor-codec-capnp: Cap'n Proto serialization.
  • Transports (WIP):
    • plexor-zmq: ZeroMQ transport.
    • plexor-http: HTTP/SSE transport.
    • plexor-websocket: WebSocket transport.

License

Mozilla Public License, version 2.0.