Show the crate…

1 unstable release

0.1.1 Mar 16, 2021

#22 in #fp

MIT license

59KB
942 lines

xi

Xi is a functional reactive stream library for rust.

  • Small (~20 operations)
  • Synchronous
  • No dependencies
  • Is FRP (ha!)

Modelled on André Staltz' javascript library xstream which nicely distills the ideas of reactive extensions (Rx) down to the essential minimum.

This library is not FRP (Functional Reactive Programming) in the way it was defined by Conal Elliot, but as a paradigm that is both functional and reactive. Why I cannot say FRP but I just did.

Example

use xi::{Sink, Stream};

// A sink is an originator of events that form a stream.
let sink: Sink<u32> = Stream::sink();

// Map the even numbers to their square.
let stream: Stream<u32> = sink.stream()
    .filter(|i| i % 2 == 0)
    .map(|i| i * i);

// Print the result
stream.subscribe(|i| if let Some(i) = i {
    println!("{}", i)
});

// Send numbers into the sink.
for i in 0..10 {
    sink.update(i);
}
sink.end();

Idea

Functional Reactive Programming is a good foundation for functional programming (FP). The step-by-step approach of composing interlocked operations, is a relatively easy way to make an FP structure to a piece of software.

Synchronous

Libraries that deals with streams as values-over-time (or events) often conflate the idea of moving data from point A to B, with the operators that transform the data. The result is that the library must deal with queues of data, queue lengths and backpressure.

xi has no queues

Every Sink::update() of data into the tree of operations executes synchronously. xi has no operators that dispatches "later", i.e. no delay() or other time shifting operations.

That also means xi also has no internal threads, futures or otherwise.

Thread safe

Every part of the xi tree is thread safe. You can move a Sink into another thread, or subscribe and propagate on a UI main thread. The thread that calls Sink::update() is the thread executing the entire tree.

That safety comes at a cost, xi is not a zero cost abstraction library. Every part of the tree is protected by a mutex lock. This is fine for most applications since a lock without contention is not much overhead in the execution. But if you plan on having lots of threads simultaneously updating many values into the tree, you might experience a performance hit due to lock contention.

Be out of your way

xi tries to impose a minimum of cognitive load when using it.

  • Every operator is an FnMut(&T) to make it the most usable possible.
  • Not require Sync and/or Send on operator functions.
  • xi stream instances themselves are Sync and Send.
  • Impose a minimum of constraints the event value T.

No runtime deps