com.wire.signals

Type members

Classlikes

Companion
class
class AggregatingSignal[E, V](loader: () => Future[V], sourceStream: EventStream[E], updater: (V, E) => V)(ec: ExecutionContext) extends Signal[V] with EventSubscriber[E]

A signal which initializes its value by executing the loader future and then updates the value by composition of the previous value and an event published in the associated source stream. You may think of it as a more performance-efficient version of RefreshingSignal, useful when the loader requires heavy computations but an update between one value and another is simple in comparison. For example:

A signal which initializes its value by executing the loader future and then updates the value by composition of the previous value and an event published in the associated source stream. You may think of it as a more performance-efficient version of RefreshingSignal, useful when the loader requires heavy computations but an update between one value and another is simple in comparison. For example:

val loader: Future[ Vector[DBEntry] ] = fetchDBTableData()
val sourceStream: EventStream[DBEntry] = newDBTableEntryStream()
val updater: (Vector[DBEntry], DBEntry) => Vector[DBEntry] = { (table, newEntry) => table :+ newEntry }
val signal = new AggregatingSignal(loader, sourceStream, updater)

Here, the loader fetches the whole DB table, but if we know that the only change to that table is that new entries can be added to it, we can avoid calling the loader every time the event comes. Instead, we can create the updater function which will combine the current value of the signal (i.e. the in-memory cache of the DB table, created by calling the loader only once, when the signal was initialized), with the new entry.

Type Params
E

The type of the update events.

V

The type of the value held in the signal and the result of the loader execution.

Value Params
ec

The execution context in which the loader is executed.

loader

A future used for computing the initial value of the signal. It's passed by name, so if it is created in the place of argument, it will be executed for the first time only when the first subscriber function is registered in the signal, or immediately if disableAutowiring is used. If a new event comes while the loader not yet finished, the event will be memorized and used to produce the first updated value right afterwards.

sourceStream

An event stream publishing events which will be used to update the value of the signal.

updater

A function combining the current value of the signal with a new event to produce the updated value.

See also
Companion
object
abstract class BaseSubscription(context: WeakReference[EventContext]) extends Subscription

Provides the default implementation of the Subscription trait. Exposes two new abstract methods: onSubscribe and onUnsubscribe. A typical way to implement them is to have a reference to the source of events which implements the EventSource trait and call subscribe(this) on that source (where this is the subscription).

Provides the default implementation of the Subscription trait. Exposes two new abstract methods: onSubscribe and onUnsubscribe. A typical way to implement them is to have a reference to the source of events which implements the EventSource trait and call subscribe(this) on that source (where this is the subscription).

For examples:

Value Params
context

A weak reference to the event context within which the subscription lives.

See also
class Cancellable[+T](promise: Promise[T])(ec: ExecutionContext) extends CancellableFuture[T]

A subclass of CancellableFuture which represents a subset of cancellable futures which are actually cancellable. I know it means the name of the parent class is misleading, since not all cancellable futures are cancellable, but, well, naming is a hard problem in computer science. The reasoning here goes like this: An actually cancellable CancellableFuture is a wrapper over a Promise, not a Future. We create a promise and try to fulfill it with the code given to us in one of the constructor methods. If we succeed, the cancellable future will behave just as a regular one. But thanks to that we hold a promise, we are able to cancel the ongoing execution of that piece of code by calling tryFailure on the promise.

A subclass of CancellableFuture which represents a subset of cancellable futures which are actually cancellable. I know it means the name of the parent class is misleading, since not all cancellable futures are cancellable, but, well, naming is a hard problem in computer science. The reasoning here goes like this: An actually cancellable CancellableFuture is a wrapper over a Promise, not a Future. We create a promise and try to fulfill it with the code given to us in one of the constructor methods. If we succeed, the cancellable future will behave just as a regular one. But thanks to that we hold a promise, we are able to cancel the ongoing execution of that piece of code by calling tryFailure on the promise.

However, in some situations cancelling will not be possible. One is of course that the future may already be completed - with success or with failure (including that it might have been already cancelled). This is why the cancel method returns a boolean - we can't be always 100% sure that calling it will actually cancel the future.

But there is also another possibility. Because of how ubiquitous futures are in the Scala standard library, it makes sense to be able to wrap them in cancellable futures so that they can be used in the same code with the actually cancellable futures. After all, if we're on the happy path, the two behave the same. The only difference appears only when we try to cancel such a "cancellable" future - we don't have access to the parent promise of that future, so we can't cancel it. Calling cancel on such a future will always return false, a callback registered with onCancel will be ignored, etc.

The last case is an inverse of the second one: Sometimes we have an actually cancellable future but we want to make sure that it won't be cancelled in a given piece of code. Imagine a situation when we wait for a result of complex computations which are modelled as a cancellable future. The computations may be cancelled by one class that manages the computations, but we also give a reference to that cancellable future to a few other classes in the program, so that when the computations finish, those classes will be immediately informed, get the result, and use it. But they shouldn't be able to cancel the original computations - even if the given class becomes disinterested in the result, it should not be able to stop the computations for all others. In such case, we can use the method toUncancellable - it will give us an Uncancellable wrapped over the promise.future of our original Cancellable future.

Type Params
T

The result type of the cancellable future

Value Params
ec

The execution context in which the future will be executed. By default it's the default context set in the Threading class

promise

The promise a new cancellable future wraps around

CancellableFuture is an object that for all practical uses works like a future but enables the user to cancel the operation. A cancelled future fails with CancellableFuture.CancelException so the subscriber can differentiate between thisand other failure reasons.

CancellableFuture is an object that for all practical uses works like a future but enables the user to cancel the operation. A cancelled future fails with CancellableFuture.CancelException so the subscriber can differentiate between thisand other failure reasons.

See also
Companion
class
abstract class CancellableFuture[+T](ec: ExecutionContext) extends Awaitable[T]

CancellableFuture is an object that for all practical uses works like a future but enables the user to cancel the operation. A cancelled future fails with CancellableFuture.CancelException so the subscriber can differentiate between this and other failure reasons. It is impossible to cancel a future if it is already completed or if it is uncancellable.

CancellableFuture is an object that for all practical uses works like a future but enables the user to cancel the operation. A cancelled future fails with CancellableFuture.CancelException so the subscriber can differentiate between this and other failure reasons. It is impossible to cancel a future if it is already completed or if it is uncancellable.

See also

Uncancellable for details on uncancellable futures

Companion
object
object ConstSignal
Companion
class
final class ConstSignal[V] extends Signal[V] with NoAutowiring[V]

A signal holding an immutable value. Using const signals in flatMap chains should have better performance compared to source signals with the same value. Since the value never changes, the subscriber function will be called only in the moment of subscription, but never after that, so there's no need to keep the subscription.

A signal holding an immutable value. Using const signals in flatMap chains should have better performance compared to source signals with the same value. Since the value never changes, the subscriber function will be called only in the moment of subscription, but never after that, so there's no need to keep the subscription.

Companion
object
trait DispatchQueue extends ExecutionContext

A thin wrapper over Scala's ExecutionContext allowing us to differentiate between the default execution context which tries to run asynchronously as many tasks as possible, and limited execution contexts, allowed to run only up to a given number of tasks at once.

A thin wrapper over Scala's ExecutionContext allowing us to differentiate between the default execution context which tries to run asynchronously as many tasks as possible, and limited execution contexts, allowed to run only up to a given number of tasks at once.

See also

ExecutionContext

Companion
object
Companion
class
object EventContext
Companion
class

When you subscribe to an EventSource in return you receive a Subscription. You can use that subscription to unsubscribe from the event source or to temporarily pause receiving events. But managing a big number of subscriptions to different event sources can be tricky. EventContext comes to the rescue.

When you subscribe to an EventSource in return you receive a Subscription. You can use that subscription to unsubscribe from the event source or to temporarily pause receiving events. But managing a big number of subscriptions to different event sources can be tricky. EventContext comes to the rescue.

By default, every subscription is registered in a "dummy" EventContext.Global which lives for the lifetime of the whole program and does nothing. But if instead you will create a new EventContext and use it explicitly when subscribing or you will set it as an implicit parameter, taking over EventContext.Global, the subscription will be registered within this new one. It will allow you to manage all registered subscriptions at once and all registered subscriptions will be destroyed when the event context lifetime ends.

Usage of methods in the trait are explained as they are implemented in the default implementation. All operations on an EventContext are synchronized.

See also
Companion
object
abstract class EventSource[E, S]
object EventStream
Companion
class
class EventStream[E] extends EventSource[E, EventSubscriber[E]]

An event stream of type E dispatches events (of type E) to all functions of type (E) => Unit which were registered in the event stream as its subscribers. It doesn't have an internal state. It provides a handful of methods which enable the user to create new event streams by means of composing the old ones, filtering them, etc., in a way similar to how the user can operate on standard collections, as well as to interact with Scala futures, cancellable futures, and signals. Please note that by default an event stream is not able to receive events from the outside - that functionality belongs to SourceStream.

An event stream of type E dispatches events (of type E) to all functions of type (E) => Unit which were registered in the event stream as its subscribers. It doesn't have an internal state. It provides a handful of methods which enable the user to create new event streams by means of composing the old ones, filtering them, etc., in a way similar to how the user can operate on standard collections, as well as to interact with Scala futures, cancellable futures, and signals. Please note that by default an event stream is not able to receive events from the outside - that functionality belongs to SourceStream.

An event stream may also help in sending events from one execution context to another. For example, a source stream may receive an event in one execution context, but the function which consumes it is registered with another execution context specified. In that case the function won't be called immediately, but in a future executed in that execution context.

See also

ExecutionContext

Companion
object
class EventStreamWithAuxSignal[A, B](source: EventStream[A], aux: Signal[B]) extends EventStream[(A, Option[B])]

An event stream coupled with an auxiliary signal. You can use it if you want to repeat some computations based on the current value of the signal every time when an event is published in the source stream.

An event stream coupled with an auxiliary signal. You can use it if you want to repeat some computations based on the current value of the signal every time when an event is published in the source stream.

val aux = Signal[Int]()
val source = EventStream[Unit]()

val newStream = EventStreamWithAuxSignal(source, aux)
newStream.foreach { case (_, Option(n)) => /* ... */ }

Here, newStream extends EventStream[Unit, Option[Int]]. The subscriber function registered in newStream`` will be called every time a new unit event is published insourceand it will receive a tuple of the event and the current value ofaux:Some[Int]if something was already published in the signal, orNone` if it is not initialized yet.

Type Params
A

The type of events in the source stream.

B

The type of values in the auxiliary signal.

Value Params
aux

An auxiliary signal of values of the type B. Every time a new event is published in source, this stream will access the signal for its current value. The value (or lack of it) will become the second part of the tuple published in this stream.

source

The source event stream used to trigger events in this event stream. Every event of type A published in source will become the first part of the tuple published in this stream.

Companion
object

A dispatch queue limiting number of concurrently executing tasks. All tasks are executed on parent execution context, but only up to the concurrencyLimit. New tasks, scheduled when the limit is reached, will wait in the queue until one of the current one finishes. Create with one of DispatchQueue.apply methods.

A dispatch queue limiting number of concurrently executing tasks. All tasks are executed on parent execution context, but only up to the concurrencyLimit. New tasks, scheduled when the limit is reached, will wait in the queue until one of the current one finishes. Create with one of DispatchQueue.apply methods.

Companion
object
Companion
class
trait NoAutowiring[V]

By default, a new signal is initialized lazily, i.e. only when the first subscriber function is registered in it. You can decorate it with NoAutowiring to enforce initialization.

By default, a new signal is initialized lazily, i.e. only when the first subscriber function is registered in it. You can decorate it with NoAutowiring to enforce initialization.

See also
abstract class ProxyEventStream[A, E](sources: EventStream[A]*) extends EventStream[E] with EventSubscriber[A]

A superclass for all event streams which compose other event streams into one.

A superclass for all event streams which compose other event streams into one.

Type Params
A

The type of the events emitted by all the source streams.

E

The type of the events emitted by the stream constructed from the sources.

Value Params
sources

A variable arguments list of event streams serving as sources of events for the resulting stream.

abstract class ProxySignal[V](sources: Signal[_]*) extends Signal[V] with SignalSubscriber
Companion
class
class RefreshingSignal[V](loader: () => CancellableFuture[V], refreshStream: EventStream[_])(ec: ExecutionContext) extends Signal[V]

A signal which initializes its value by executing the loader cancellable future and then updates the value the same way every time a new refresh event is published in the associated event stream. The type of the event is not important.

A signal which initializes its value by executing the loader cancellable future and then updates the value the same way every time a new refresh event is published in the associated event stream. The type of the event is not important.

A typical use case for a refreshing signal might be, for example, to inform another component that something changed in the storage while already retrieving the updated data. In this case, the refresh event stream can be anything that indicates the data has changed, and the loader is the query. The refresh event might even be a false positive: then the loader function will be called but the subscriber function of the refreshing signal will not be notified as the result of the loader is the same and so the value of the signal doesn't change.

Type Params
V

The value type of the signal and the result of the loader cancellable future.

Value Params
ec

The execution context in which the loader is executed.

loader

A cancellable future computing the value of the signal. It's passed by name, so if it is created in the place of argument, it will be executed for the first time only when the first subscriber function is registered in the signal, or immediately if disableAutowiring is used. If the execution fails or is cancelled, the value of the signal won't be updated.

refreshStream

An event stream publishing events which will trigger new executions of the loader. If a new event comes before the previous call to loader finishes, the previous call will be cancelled.

See also
Companion
object

A special case of a limited dispatch queue which allows for only one task to be executed at once. Use when you want to enforce the tasks to be executed in the order they were scheduled.

A special case of a limited dispatch queue which allows for only one task to be executed at once. Use when you want to enforce the tasks to be executed in the order they were scheduled.

Companion
object
Companion
class
object Serialized

A utility object for serializing futures.

A utility object for serializing futures.

The need for this functionality comes from the fact that we can't assume an event will be processed before the next one comes, but sometimes it is also crucial to process the next event only after the first one is done. In such case, the user can use one of the methods of Serialized to schedule processing the first event, tag it with a key, and then simply use the same key to schedule processing of the second event. The user doesn't have to know if the first event was already processed or not - if yes, processing of the second will start immediately, if not, the processing (in the form of a future or a CancellableFuture) will be attached to the end of the ongoing processing and triggered only after it's done.

Todo

Serialized is currently used in only one place in wire-signals, FutureEventStream, which in turn is used only for EventStream.mapSync, so we may think or removing this class from the library (move to extensions, maybe?).

object Signal
Companion
class
class Signal[V] extends EventSource[V, SignalSubscriber]

A signal is an event stream with a cache.

A signal is an event stream with a cache.

Whereas an event stream holds no internal state and just passes on events it receives, a signal keeps the last value it received. A new subscriber function registered in an event stream will be called only when a new event is published. A new subscriber function registered in a signal will be called immediately (or as soon as possible on the given execution context) with the current value of the signal (unless it's not initialized yet) and then again when the value changes. A signal is also able to compare a new value published in it with the old one - the new value will be passed on only if it is different. Thus, a signal can help us with optimizing performance on both ends: as a cache for values which otherwise would require expensive computations to produce them every time we need them, and as a way to ensure that subscriber functions are called only when the value actually changes, but not when the result of the intermediate computation is the same as before.

Note that for clarity we talk about events in the event streams, but about values in signals.

An signal of the type V dispatches values to all functions of the type (V) => Unit which were registered in the signal as its subscribers. It provides a handful of methods which enable the user to create new signals by means of composing the old ones, filtering them, etc., in a way similar to how the user can operate on standard collections, as well as to interact with Scala futures, cancellable futures, and event streams. Please note that by default a signal is not able to receive events from the outside - that functionality belongs to SourceSignal.

Type Params
V

The type of the value held in the signal.

Value Params
value

The option of the last value published in the signal or None if the signal was not initialized yet.

See also
Companion
object
object SourceSignal
Companion
class
class SourceSignal[V](val v: Option[V]) extends Signal[V]

The usual entry point for publishing values in signals.

The usual entry point for publishing values in signals.

Create a new signal either using the default constructor or the Signal.apply[V]() method. The source signal exposes methods you can use for changing its value. Then you can combine it with other signals and finally subscribe a function to it which will be called initially, and then on each change of the signal's value.

Type Params
V

the type of the value held by the signal.

Companion
object
class SourceStream[E] extends EventStream[E]

The usual entry point for publishing events.

The usual entry point for publishing events.

Create a new source stream either using the default constructor or the EventStream.apply[V]() method. The source stream exposes methods you can use for publishing new events. Then you can combine it with other event streams and finally subscribe a function to it which will receive the resulting events.

Type Params
E

the type of the event

When you add a new subscriber to your EventStream or Signal, in return you get a Subscription. A subscription can then be used to inform the source about changes in the condition of the connection: should it be enabled or disabled, should the subscriber be subscribed or (temporarily) unsubscribed, or should the subscription be permanently destroyed.

When you add a new subscriber to your EventStream or Signal, in return you get a Subscription. A subscription can then be used to inform the source about changes in the condition of the connection: should it be enabled or disabled, should the subscriber be subscribed or (temporarily) unsubscribed, or should the subscription be permanently destroyed.

It is important to destroy subscriptions when they are no longer needed, e.g. at the end of the life of an object which subscribes to the source of events. Otherwise you may face a hidden memory leak where no longer used data cannot be GC-ed because it is still referenced by the source of events.

See also

EventContext Implement this trait together with writing a new event source if you want to change how your event source reacts to the aforementioned events. For an example of how to do it on a small scale, please

object Threading

Use Threading to set up the default execution context which will be later used as the parent for other dispatch queues and to run cancellable futures, event streams, and signals, if no other execution context is provided.

Use Threading to set up the default execution context which will be later used as the parent for other dispatch queues and to run cancellable futures, event streams, and signals, if no other execution context is provided.

Companion
class
class ThrottledSignal[V](val source: Signal[V], val delay: FiniteDuration) extends ProxySignal[V]

A signal which publishes changes of its parent signal but no more often than once during a given time interval. The initial value of the parent signal will be published immediately. The first change to it will happen at the earliest after the given delay. If the parent signal changes its value more often, the intermediate values will be ignored.

A signal which publishes changes of its parent signal but no more often than once during a given time interval. The initial value of the parent signal will be published immediately. The first change to it will happen at the earliest after the given delay. If the parent signal changes its value more often, the intermediate values will be ignored.

Use it e.g. for optimization of a signal chain when there is no need to react immediately to all changes to the original signal. For example. changes in the UI could be displayed only with the speed that allows for comfortable usage of the app by the user, but not faster.

Type Params
V

The value type of the signal.

Value Params
delay

The time interval used for publishing. No more than one change of the value per delay will be published.

source

The original signal providing the value and changes to it.

Todo

Check if when the original value changes once during the delay interval, but not again after it, will that one change be noticed. I think it should be.

Companion
object
final class Uncancellable[+T](val future: Future[T])(ec: ExecutionContext) extends CancellableFuture[T]

A subclass of CancellableFuture which represents a subset of cancellable futures which are actually uncancellable. I know it means the name of the parent class is misleading, since not all cancellable futures are cancellable, but, well, naming is a hard problem in computer science. The reasoning here goes like this: An actually cancellable CancellableFuture is a wrapper over a Promise, not a Future. We create a promise and try to fulfill it with the code given to us in one of the constructor methods. If we succeed, the cancellable future will behave just as a regular one. But thanks to that we hold a promise, we are able to cancel the ongoing execution of that piece of code by calling tryFailure on the promise.

A subclass of CancellableFuture which represents a subset of cancellable futures which are actually uncancellable. I know it means the name of the parent class is misleading, since not all cancellable futures are cancellable, but, well, naming is a hard problem in computer science. The reasoning here goes like this: An actually cancellable CancellableFuture is a wrapper over a Promise, not a Future. We create a promise and try to fulfill it with the code given to us in one of the constructor methods. If we succeed, the cancellable future will behave just as a regular one. But thanks to that we hold a promise, we are able to cancel the ongoing execution of that piece of code by calling tryFailure on the promise.

However, in some situations cancelling will not be possible. One is of course that the future may already be completed - with success or with failure (including that it might have been already cancelled). This is why the cancel method returns a boolean - we can't be always 100% sure that calling it will actually cancel the future.

But there is also another possibility. Because of how ubiquitous futures are in the Scala standard library, it makes sense to be able to wrap them in cancellable futures so that they can be used in the same code with the actually cancellable futures. After all, if we're on the happy path, the two behave the same. The only difference appears only when we try to cancel such a "cancellable" future - we don't have access to the parent promise of that future, so we can't cancel it. Calling cancel on such a future will always return false, a callback registered with onCancel will be ignored, etc.

The last case is an inverse of the second one: Sometimes we have an actually cancellable future but we want to make sure that it won't be cancelled in a given piece of code. Imagine a situation when we wait for a result of complex computations which are modelled as a cancellable future. The computations may be cancelled by one class that manages the computations, but we also give a reference to that cancellable future to a few other classes in the program, so that when the computations finish, those classes will be immediately informed, get the result, and use it. But they shouldn't be able to cancel the original computations - even if the given class becomes disinterested in the result, it should not be able to stop the computations for all others. In such case, we can use the method toUncancellable - it will give us an Uncancellable wrapped over the promise.future of our original Cancellable future.

Type Params
T

The result type of the cancellable future

Value Params
ec

The execution context in which the future will be executed. By default it's the default context set in the Threading class

future

The future a new uncancellable future wraps around

A dispatch queue that simply passes all its tasks to its execution context.

A dispatch queue that simply passes all its tasks to its execution context.

Companion
object