observable ~master

Provides event handling facilities based on observable and signal slot approaches


To use this package, run the following command in your project's root directory:

Manual usage
Put the following dependency into your project's dependences section:

Observable and signal/slot implementation

This library provides event handling mechanisms on two abstraction levels. Signals/slots are a direct way for events to be propagated to any number of event receivers. The propagation happens synchronously and has very low overhead, computationally and memory consumption wise.

Observables on the other hand allow each observer to process events asynchronously using a separate event queue. The advantage of this approach is that each observer can process events in order, but independent of the timing of the source. Additionally, observables can be composed, manipulated and augmented using a range-like API.

Both, signals and observables, support storing extra data to avoid the need for creating heap closures when listening for events.

Build status

Signal/slot example

Signal can be used to create direct call connections between source and destination. All observer callbacks of a signal will be called synchronously, whenever the signal gets emitted.

class Slider {
    private {
        double m_value = 0.0;
        Signal!double m_valueChangeSignal;
    }

    @property ref SignalSocket!double valueChangeSignal()
    {
        return m_valueChangeSignal.socket;
    }

    @property void value(double new_value)
    {
        m_value = new_value;
        m_valueChangeSignal.emit(new_value);
    }
}

class Label {
    @property void caption(string caption);
}

class MyDialog {
    private {
        Label m_label;
        Slider m_slider;
        SignalConnection m_valueConnection;
    }

    this()
    {
        m_label = new Label;

        m_slider = new Slider;
        m_slider.valueChangeSignal.connect(m_valueConnection,
            (value) => m_label.caption = value.to!string);
    }
}

Observable example

Observable adds an internal event queue to each observer, so that observers are independent of each other and do not interfere with the observable's execution.

class Slider {
    private {
        double m_value = 0.0;
        ObservableSource!double m_valueChanges;
    }

    @property ref Observable!double valueChanges()
    {
        return m_valueChanges.observable;
    }

    @property void value(double new_value)
    {
        m_value = new_value;
        m_valueChanges.put(new_value);
    }
}

class Label {
    @property void caption(string caption);
}

class MyDialog {
    private {
        Label m_label;
        Slider m_slider;
        SignalConnection m_valueConnection;
    }

    this()
    {
        m_label = new Label;

        m_slider = new Slider;

        runTask({
            foreach (value; m_slider.valueChanges.subscribe)
                m_label.caption = value.to!string;
        });
    }
}

Reactive value example

Reactive values simplify the connection of properties by exposing an observable interface to handle updates. Assigning a reactive value to another will automatically update the latter whenever the assigned value changes. Reactive values are also observable, with subscribe working just like for Observable.

class Slider {
    @property ref Value!double value();
}

class Label {
    @property ref Value!string caption();
}

class MyDialog {
    private {
        Label m_label;
        Slider m_slider;
        SignalConnection m_valueConnection;
    }

    this()
    {
        m_slider = new Slider;

        m_label = new Label;
        m_label.caption = m_slider.value.mapValue!(n => n.to!string);
    }
}
Authors:
  • Sönke Ludwig
Dependencies:
vibe-core, vibe-container
Versions:
1.5.0 2024-Feb-14
1.4.0 2024-Feb-13
1.3.4 2024-Feb-09
1.3.3 2023-Oct-20
1.3.2 2023-Mar-07
Show all 15 versions
Download Stats:
  • 0 downloads today

  • 0 downloads this week

  • 3 downloads this month

  • 281 downloads total

Score:
1.4
Short URL:
observable.dub.pm