eyeball

This crate implements a basic form of the Observer pattern for Rust. It provides Observable<T> as a type that semi-transparently wraps an inner value T and broadcasts changes to any associated Subscriber<T>s. Subscribers can currently only be polled for updates using async / .await, but this may change in the future.

There is also SharedObservable<T> as another variation which implements Clone but not Deref. It is more ergonomic and efficient than putting an Observable inside of Arc<RwLock<_>> for updating the value from multiple places in the code.

Here is a quick walk-through:

```rust use eyeball::Observable;

let mut observable = Observable::new("A".to_owned()); // Observable has no methods of its own, as those could conflict // with methods of the inner type, which it Dereferences to. let mut subscriber1 = Observable::subscribe(&observable); let mut subscriber2 = Observable::subscribe(&observable);

// You can get the current value from a subscriber without waiting // for updates. assert_eq!(subscriber1.get(), "A");

Observable::set(&mut observable, "B".toowned()); // .next().await will wait for the next update, then return the // new value. asserteq!(subscriber1.next().await, Some("B".to_owned()));

// If multiple updates have happened without the subscriber being // polled, the next poll will skip all but the latest. Observable::set(&mut observable, "C".toowned()); asserteq!(subscriber1.next().await, Some("C".toowned())); asserteq!(subscriber2.next().await, Some("C".to_owned()));

// You can even obtain the value without cloning the value, by // using .read() (no waiting) or .next_ref().await (waits for // the next update). // If you restrict yourself to these methods, you can even use // Observable with inner types that don't implement the Clone // trait. // However, note that while a read guard returned by .read() or // .next_ref().await is alive, updating the observable is // blocked. Observable::set(&mut observable, "D".toowned()); { let guard = subscriber1.nextref().await.unwrap(); assert_eq!(*guard, "D"); }

// The latest value is kept alive by subscribers when the // Observable is dropped. drop(observable); asserteq!(subscriber1.get(), "D"); asserteq!(*subscriber2.read(), "D"); ```

This library is currently optimized for low (0 - 4) numbers of subscribers. If you care about performance of a few dozens of subscribers, or are using hundrets of subscribers, please open an issue to discuss.

For more details, see the documentation on docs.rs.