epoxy/
lib.rs

1//! # Epoxy
2//! ### The Reactive Glue for Frontend Rust Apps
3//! 
4//! This library provides 2 basic reactive programming primitives. `Stream` represents a stateless
5//! pipe of data that can be subscribed to and handled asynchronously. `ReactiveValue` represents
6//! a piece of data whose value can change over time (similar to an Atomic, but backed by streams
7//! so that dependents be alerted when its value changes). These two primitives loosely correspond
8//! to 'Stream' and 'BehaviorSubject' respectively in the Rx family of libraries.
9//! 
10//! One unique feature of this library is that stream subscriptions only last as long as the
11//! subscription object stays in scope, preventing a many of the memory leaks and zombie callback
12//! problems common in reactive code.
13//! 
14//! ```
15//! let stream_host: epoxy::Sink<i32> = epoxy::Sink::new();
16//! let stream = stream_host.get_stream();
17//! {
18//!     let _sub = stream.subscribe(|val| println!("Emitted {}", val));
19//!     stream_host.emit(1); // 'Emitted 1' is printed
20//!     assert_eq!(stream.count_subscribers(), 1);
21//! }
22//! stream_host.emit(2); // Nothing is printed
23//! assert_eq!(stream.count_subscribers(), 0);
24//! ```
25//! 
26//! Streams can be manipulated using a library of built-in functions based on Rust's set of
27//! iterator operations. Currently these operations include:
28//! 
29//! | Operation          | Property of returned stream                                            |
30//! |--------------------|------------------------------------------------------------------------|
31//! | map(fn)            | Runs all values from the input stream through a mapper function        |
32//! | map_rc(fn)         | Same as map() but the mapper function takes and returns an Arc          |
33//! | flat_map(fn)       | Similar to map() but iterates through the result of the mapper function|
34//! | filter(fn)         | Returns only input values that pass the given filter function          |
35//! | inspect(method)    | Passes through the original stream, calls a method for each item       |
36//! | scan(fn, default)  | Similar to reduce(), but returns the value after each iteration        |
37//! | count_values()     | Returns the number of times the stream has emitted                     |
38//! | buffer(size)       | Collects emitted values into vectors of length `size`                  |
39//! 
40//! ReactiveValues have their own set of operators, although it is also possible to get a reference
41//! to the underlying stream of a ReactiveValue with `.as_stream()` and use any of the above
42//! operations as well.
43//! 
44//! | Operation             | Property of returned reactive value                                 |
45//! |-----------------------|---------------------------------------------------------------------|
46//! | map(fn)               | Runs all values from the input stream through a mapper function     |
47//! | sanitize(fn, default) | Does not change the value if the input does not pass a test fn      |
48//! | fallback(fn, fallback)| Changes the value to `fallback` if the input does not pass a test fn|
49//! 
50//! However, this library also ships with a `computed!` macro that makes dealing with ReactiveValue
51//! just as easy as dealing with any other Rust variable.
52//! 
53//! ```
54//! # #[macro_use] extern crate epoxy;
55//! use epoxy::ReactiveValue;
56//! 
57//! let points = epoxy::ReactiveValue::new(4);
58//! let multiplier = epoxy::ReactiveValue::new(1);
59//! let score = computed!(points * multiplier);
60//! 
61//! assert_eq!(*score.get(), 4);
62//! 
63//! multiplier.set(2);
64//! assert_eq!(*score.get(), 8);
65//! ```
66//! 
67//! ## Comparisons to other FRP Libraries
68//! 
69//! ### Carboxyl / Frappe
70//! 
71//! Carboxyl and Frappe are the two most common FRP libraries in Rust right now (I have combined
72//! them here because they are structured very similarly). This library was inspired by ReactiveX
73//! rather than the FRP paper that Carboxyl and Frappe used, so some of the terminology here is
74//! different. There are also a number of significant API differences:
75//! 
76//! * Epoxy Subscription <-> Carboxyl Observers
77//!   * Subscriptions in Epoxy are unsubscribed when they go out of scope
78//!   * Carboxyl Observers are unsubscribed when the observer function returns False-y
79//! * Epoxy ReactiveValue <-> Carboxyl Signal
80//!   * Carboxyl Signals cannot be subscribed to (observed), which is a problem for UI frameworks
81//!   * Epoxy ReactiveValues are push, rather than pull, making them less efficient in some cases
82//! * Epoxy computed! <-> Carboxyl lift!
83//!   * The Epoxy computed! macro extracts variables from the function def, making it more readable
84//!   * Carboxyl's lift! macro has explicitly defined inputs, making it less error-prone
85//! 
86//! As you can see, there are tradeoffs to both of these frameworks. Epoxy was designed to optimize
87//! for frontend use cases, making it easier to integrate with things like DOM libraries.
88//! 
89//! ### ReactiveX
90//! 
91//! These streams are intended to be substantially simpler than those in the ReactiveX family of
92//! libraries. The most significant difference is that this library has no concept of a 'cold'
93//! stream, meaning no streams will ever emit a value immediately upon subscription. Streams
94//! in this library also never close, as they are intended to model long-term asynchronous data
95//! flows (of course it is possible to make a stream 'closeable' by making a stream of Option
96//! enums and unsubscribing on `None`, that just isn't built in to the library). Finally, where
97//! Rx subscriptions live until explicitly unsubscribed, Rust Reactive subscriptions only live
98//! as long as they are in scope.
99//! 
100//! ## Status
101//! 
102//! This crate is under active development and is probably not ready for production use yet.
103extern crate proc_macro_hack;
104extern crate epoxy_macros;
105extern crate epoxy_streams;
106
107use proc_macro_hack::proc_macro_hack;
108
109pub use epoxy_streams::ReactiveValue;
110pub use epoxy_streams::ReadonlyReactiveValue;
111pub use epoxy_streams::Stream;
112pub use epoxy_streams::Sink;
113pub use epoxy_streams::Subscription;
114pub use epoxy_streams::WriteableReactiveValue;
115
116/// Add one to an expression.
117#[proc_macro_hack]
118pub use epoxy_macros::computed;