observable-property 0.1.0

A thread-safe observable property implementation for Rust
Documentation
# Observable Property


A thread-safe observable property implementation for Rust that allows you to observe changes to values across multiple threads.

## Features


* **Thread-safe**: Uses `Arc<RwLock<>>` for safe concurrent access

* **Observer pattern**: Subscribe to property changes with callbacks

* **Filtered observers**: Only notify when specific conditions are met

* **Async notifications**: Non-blocking observer notifications with background threads

* **Panic isolation**: Observer panics don't crash the system

* **Type-safe**: Generic implementation works with any `Clone + Send + Sync + 'static` type

* **Zero dependencies**: Uses only Rust standard library

## Quick Start


Add this to your `Cargo.toml`:

```toml
[dependencies]
observable-property = "0.1.0"
```

## Usage


### Basic Example


```rust
use observable_property::ObservableProperty;
use std::sync::Arc;

// Create an observable property
let property = ObservableProperty::new(42);

// Subscribe to changes
let observer_id = property.subscribe(Arc::new(|old_value, new_value| {
    println!("Value changed from {} to {}", old_value, new_value);
})).unwrap();

// Change the value (triggers observer)
property.set(100).unwrap(); // Prints: Value changed from 42 to 100

// Unsubscribe when done
property.unsubscribe(observer_id).unwrap();
```

### Multi-threading Example


```rust
use observable_property::ObservableProperty;
use std::sync::Arc;
use std::thread;

let property = Arc::new(ObservableProperty::new(0));
let property_clone = property.clone();

// Subscribe from one thread
property.subscribe(Arc::new(|old, new| {
    println!("Value changed: {} -> {}", old, new);
})).unwrap();

// Modify from another thread
thread::spawn(move || {
    property_clone.set(42).unwrap();
}).join().unwrap();
```

### Filtered Observers


```rust
use observable_property::ObservableProperty;
use std::sync::Arc;

let counter = ObservableProperty::new(0);

// Only notify when value increases
let observer_id = counter.subscribe_filtered(
    Arc::new(|old, new| println!("Increased: {} -> {}", old, new)),
    |old, new| new > old
).unwrap();

counter.set(5).unwrap();  // Triggers observer: "Increased: 0 -> 5"
counter.set(3).unwrap();  // Does NOT trigger observer
counter.set(10).unwrap(); // Triggers observer: "Increased: 3 -> 10"
```

### Async Notifications


For observers that might perform time-consuming operations, use async notifications to avoid blocking:

```rust
use observable_property::ObservableProperty;
use std::sync::Arc;
use std::time::Duration;

let property = ObservableProperty::new(0);

property.subscribe(Arc::new(|old, new| {
    // This slow observer won't block the caller
    std::thread::sleep(Duration::from_millis(100));
    println!("Slow observer: {} -> {}", old, new);
})).unwrap();

// This returns immediately even though observer is slow
property.set_async(42).unwrap();
```

### Complex Types


Observable properties work with any type that implements the required traits:

```rust
use observable_property::ObservableProperty;
use std::sync::Arc;

#[derive(Clone, Debug)]

struct Person {
    name: String,
    age: u32,
}

let person_property = ObservableProperty::new(Person {
    name: "Alice".to_string(),
    age: 30,
});

person_property.subscribe(Arc::new(|old_person, new_person| {
    println!("Person changed: {:?} -> {:?}", old_person, new_person);
})).unwrap();

person_property.set(Person {
    name: "Alice".to_string(),
    age: 31,
}).unwrap();
```

## Error Handling


All operations return `Result` types with descriptive errors:

```rust
use observable_property::{ObservableProperty, PropertyError};

let property = ObservableProperty::new(42);

match property.get() {
    Ok(value) => println!("Current value: {}", value),
    Err(PropertyError::PoisonedLock) => println!("Lock was poisoned!"),
    Err(e) => println!("Other error: {}", e),
}
```

## Performance Considerations


* **Read operations** are very fast and can be performed concurrently from multiple threads

* **Write operations** are serialized but optimize for quick lock release

* **Synchronous notifications** block the setter until all observers complete

* **Asynchronous notifications** return immediately and run observers in background threads

* **Observer panics** are isolated and won't affect other observers or crash the system

## Examples


Run the included examples to see more usage patterns:

```bash
# Basic usage example

cargo run --example basic

# Multithreaded usage with performance comparisons

cargo run --example multithreaded
```

## Safety


This crate is designed with safety as a primary concern:

* Thread-safe access patterns prevent data races

* Observer panics are caught and isolated

* Lock poisoning is properly handled and reported

* No unsafe code is used

## License


Licensed under either of

* Apache License, Version 2.0, ([LICENSE-APACHE]https://www.google.com/search?q=LICENSE-APACHE or <http://www.apache.org/licenses/LICENSE-2.0>)

* MIT license ([LICENSE-MIT]https://www.google.com/search?q=LICENSE-MIT or <http://opensource.org/licenses/MIT>)

at your option.

### Contribution


Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.