Wavelet
A high-performance, graph-based stream processing runtime for Rust.

Overview
Wavelet is designed for applications that need predictable, low-latency stream processing without the overhead of async runtimes or actor systems. Built around a computation graph where nodes represent stream processors and edges define data dependencies, wavelet provides:
- Deterministic execution - Same inputs always produce the same execution order
- Dependency-ordered processing - Guaranteed that parent nodes are always processed before their children
- Event integration - Unified I/O, timer, and yield event handling
- Dependency injection - Build-time configuration for different environments
Quick Start
Add wavelet to your Cargo.toml:
[]
= "0.1"
Create a simple stream processing graph:
use *;
use Duration;
Architecture
Relationships: Define how nodes interact in the computation graph. Trigger relationships cause immediate
downstream execution when a node broadcasts changes, while Observe relationships create dependencies without automatic
propagation, allowing nodes to inspect upstream state on-demand.
Core Concepts
Node: A computational unit that processes data from upstream nodes and optionally propagates results downstream. Nodes can perform transformations, aggregations, filtering, side effects, or any custom business logic.
Relationships: Define how nodes interact in the computation graph. Trigger relationships cause immediate
downstream execution when a node broadcasts changes, while Observe relationships create dependencies without automatic
propagation, allowing nodes to inspect upstream state on-demand.
Cooperative Scheduling: Multi-depth scheduling system that processes nodes in dependency order. Nodes execute atomically and return control to the scheduler, which ensures proper execution sequencing and prevents infinite loops through epoch-based deduplication.
Event System: External event integration that drives graph execution. I/O events (network, file operations), timer events (scheduled execution), and yield events (immediate re-scheduling) all feed into the scheduler to trigger node processing cycles.
Key Components
// Build a computation graph
let processor = new
.triggered_by // Execute when source changes
.observer_of // Read config but don't auto-execute
.with_name
.build;
Features
Wavelet uses Cargo features to enable different functionality:
runtime(default) - Core execution engine including the scheduler, computation graph, event drivers (I/O, timer, yield), and garbage collection. This provides the fundamental stream processing capabilities.factories- Domain-specific language (DSL) primitives and dependency injection system for building complex computation graphs. Factories enable you to construct reusable subgraphs that return leaf nodes, with automatic memoization to prevent duplicate node creation. This is essential for building sophisticated topologies where the same subgraph patterns are reused across multiple downstream dependencies.testing- Comprehensive test utilities and mock implementations designed for unit testing individual nodes and entire computation graphs. Includes test clocks and mock event sources for validating node behavior in isolation.channel- Cross-thread communication infrastructure using lock-free ring buffers (crossbeam's ArrayQueue) integrated with mio notifications (Notifier). This enables external threads and systems to inject data into the computation graph safely and efficiently.full- Convenience feature that enables all available functionality. Equivalent to enabling runtime, factories, testing, and channel features simultaneously.
[]
= { = "0.1.3", = ["full"] }
Dependency Injection with Factories
Wavelet's factory system enables environment-specific implementations while maintaining identical graph topology. Factories provide build-time dependency injection, allowing you to swap implementations based on configuration without changing your core processing logic.
Simple Factory Usage
use *;
// Configure different data sources per environment
let data_source = match environment ;
// Same graph construction code works with any configured factory
let eurusd_feed = data_source.get;
let gbpusd_feed = data_source.get;
// Build downstream processors using the factory-created nodes
let processor = new
.triggered_by // Implementation determined by factory
.triggered_by
.build;
Composable Factory Patterns
For complex topologies, compose simple factories into larger DSL structures:
// DSL-level factories (custom structs)
// Strategy factory composes DSL factories with a KeyedFactory
// Usage: DSL factories compose into higher-level factories
let factory = for_environment;
let eurusd_strategy = factory.get_strategy;
let gbpusd_strategy = factory.get_strategy;
Key Benefits
- Memoization: Identical keys return the same cached node instance, preventing duplicate subgraph creation
- Environment Isolation: Test, staging, and production can use completely different implementations
- Resource Efficiency: Expensive resources (database connections, external APIs) are created once per key
- Type Safety: Factory functions are statically typed, preventing configuration errors
- Composability: Simple factories combine into complex domain-specific languages (DSLs)
This pattern is particularly powerful for financial systems, IoT processing pipelines, and any domain where you need to swap data sources, validation logic, or output destinations based on runtime configuration.
License
MIT License (LICENSE)