reactivity

Crates.ioreactivity
lib.rsreactivity
version0.1.1
created_at2025-05-13 15:08:15.611775+00
updated_at2025-05-16 15:40:28.830045+00
descriptionA lightweight library for reactive programming with signals in Rust.
homepagehttps://github.com/dexermatters/reactivity
repositoryhttps://github.com/dexermatters/reactivity
max_upload_size
id1672063
size46,026
Dexer Matters (DexerMatters)

documentation

README

Reactivity

A lightweight library for reactive programming with signals in Rust.

Crates.io Documentation License: MIT OR Apache-2.0

Overview

Reactivity is a Rust library that provides a flexible reactive programming system. It allows you to create signals that can depend on other signals, with automatic propagation of changes through your dependency graph.

Features

  • Two signal implementations:
    • reactivity::Signal for single-threaded contexts
    • reactivity::sync::Signal for thread-safe, multi-threaded contexts
  • Clean API for creating and managing signals
  • Convenient macro for defining reactive computations
  • Support for side effects when signals change
  • Fine-grained control over reaction propagation

Installation

Add the following to your Cargo.toml:

[dependencies]
reactivity = "0.1.0"

Basic Usage

Single-Threaded Signals

use reactivity::Signal;
use reactivity::signal;

fn main() {
    // Create a basic signal
    let count = signal!(0);
    
    // Create a derived signal that depends on count
    let doubled = signal!([count] count * 2);
    
    // Create another signal with a side effect
    let message = signal!(<old_val, new_val> [count] 
        format!("The count is {}", count); 
        println!("Count changed from {} to {}!", old_val, new_val)
    );
    
    // Update the original signal
    count.send(5);
    
    // The changes have been automatically propagated
    assert_eq!(count.get(), 5);
    assert_eq!(doubled.get(), 10);
    assert_eq!(message.get(), "The count is 5");
}

Thread-Safe Signals

use std::thread;
use reactivity::sync::Signal;
use reactivity::signal;

fn main() {
    // Create a thread-safe signal
    let count = signal!(0);
    
    // Create dependent signals
    let doubled = signal!([count] count * 2);
    
    // Clone for use in another thread
    let count_clone = count.clone();
    
    // Spawn a thread that updates the signal
    let handle = thread::spawn(move || {
        for i in 1..=5 {
            count_clone.send(i);
            thread::sleep(std::time::Duration::from_millis(100));
        }
    });
    
    // Wait for thread to complete
    handle.join().unwrap();
    
    // Main thread can access the updated value
    assert_eq!(doubled.get(), 10);
}

API Overview

Signal Types

  • Signal<T>: For single-threaded contexts (uses Rc and RefCell internally)
  • sync::Signal<T>: Thread-safe implementation (uses Arc and RwLock internally)
// Single-threaded signal
use reactivity::Signal;
let x = Signal::new(42);

// Thread-safe signal
use reactivity::sync::Signal;
let y = Signal::new(42);

// Create dependent signals
let a = Signal::new(1);
let b = signal!([a] a * 2);

// Register dependency (b will update when a changes)
a.add_receiver(b);

signal! Macro

The signal! macro provides a convenient way to create signals. The macro automatically uses the appropriate Signal type based on the context:

// Basic signal with initial value
let x = signal!(5);

// Signal that depends on other signals
let y = signal!([x] x + 10);

// Signal with side effect
let z = signal!(<old_val, new_val> [x, y] {
    let sum = x + y;
    sum * 2
}; println!("z changed from {} to {}", old_val, new_val));

Advanced Usage

Custom Effect Functions

You can specify custom effects that run when signals change:

let x = signal!(1);
let y = signal!(<old_y, new_y> [x] x * 3; {
    println!("y changed from {} to {}", old_y, new_y);
    // Perform side effects here
});

Choosing Between Signal Types

  • Use reactivity::Signal for single-threaded applications where all signals are accessed from the same thread
  • Use reactivity::sync::Signal when signals need to be shared across multiple threads

License

This project is dual-licensed under either of:

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this project by you shall be dual licensed as above, without any additional terms or conditions.

Commit count: 14

cargo fmt