[][src]Crate froop

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.


use froop::{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 {


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.


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.

Froop has no queues

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

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

Thread safe

Every part of the froop 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, froop 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

Froop 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.
  • Froop stream instances themselves are Sync and Send.
  • Impose a minimum of constraints the event value T.

Subscription lifetimes

See Subscription



The collector instance collects values from a stream. Created by Stream::collect().


Imitators are used to create cyclic streams. Created by Stream::imitator().


A sink is a producer of events. Created by Stream::sink().


A stream of events, values in time.


A subscription is a receipt for adding a listener to a stream. Can be used to stop listening.