Lumiera  0.pre.03
»edit your freedom«
mutation-message.hpp File Reference

Go to the source code of this file.

Description

Generic Message with an embedded diff, to describe changes to model elements.

The ability to create and apply such messages relies on the diff framework. Using diff messages allows to describe and effect changes, without actually knowing much about the target. Sender and receiver just need to share some common assumptions about the abstract structure of the data.

The challenging part with this task is the fact that we need to pass such messages over abstraction barriers and even schedule them into another thread (the UI event thread). Yet diff application actually is a pull operation, which means there must be a callback actually to retrieve the diff content, and this callback will happen from the context of the receiver.

Mutation messages on the UI-Bus

The UI-Bus offers a dedicated API to direct MutationMessages towards UI-Elements. Each tangible element in the UI, be it Widget or Controller, is designated by an unique ID. Sending a Mutation message causes the target to alter and reshape itself, to comply to the diff sequence indicated and transported through the message – since a diff sequence as such is always concrete and relates to a a specific context, we can not represent it directly as a type on interface level. Rather, the receiver of a diff sequence must offer the ability to be reshaped through diff messages, which is expressed through the interface DiffMutable. In the case at question here, stage::model::Tangible offers this interface and thus the ability to construct a concrete lib::diff::TreeMutator, which in turn is bound to the internals of the actual UI-Element. In this framework, a diff is actually represented as a sequence of diff verbs, which can be ``pulled'' one by one from the MutationMessage, and then applied to the target data structure with the help of a DiffApplicator<DiffMutable>, based on the TreeMutator exposed.

Mutation messages sent from the Session into the UI

While components in the UI generate commands to work on the session, the effect of performing those commands is reflected back asynchronously into the GUI through MutationMessages. All visible content in the UI is controlled by such messages. Initially the UI is a blank slate, and will be populated with content to reflect the content and structure of the session. Whenever the session changes, an incremental update is pushed into the UI as a diff.

Hand-over and application of mutations is actually a process in two steps. The necessity to change something is indicated (or ``triggered'') by passing a MutationMessage through the GuiNotification::facade. We should note at this point that Session and UI perform each within a dedicated single thread (contrast this to the player and render engine, which are inherently multithreaded). The UI is loaded as plug-in and opens the GuiNotification::facade when the event loop is started. Thus initiating the mutation process is a simple invocation from the session thread, which enqueues the MutationMessage and schedules the trigger over into the UI event thread. This starts the second stage of diff application: when the UI is about to process this event, the MutationMessage (which was passed through a dispatcher queue) will be forwarded over the UI-Bus to reach the designated target object. On reception, the receiving UI-Element builds and exposes its TreeMutator and the starts to pull the individual DiffStep entries from the MutationMessage. But in fact those entries aren't stored within the message, rather a callback is invoked. When initially creating the message, an opaque generation context was established, which now receives those callbacks and generates the actual sequence of diff verbs, which are immediately passed on to through the DiffApplicator and the TreeMutator to effect the corresponding changes in the target data structure within the UI. Care has to be taken when referring to session data at that point, since the pull happens from within the UI thread; yet in the end this remains an opaque implementation detail within the session.

Creation of mutation messages

The standard case is to build a MutationMessage by passing a heap allocated generator object. This DiffSource object needs to implement the interface lib::IterSource<DiffStep>, with callbacks to generate the initial step and further steps. Incidentally, the MutationMessage takes ownership and manages the DiffSource generator. Beyond this standard case, MutationMessage offers several convenience constructors to produce simple diff messages with a predetermined fixes sequence of DiffStep entries.

See also
MutationMessage_test
AbstractTangible_test
BustTerm_test::pushDiff()
BusTerm::change()

Definition in file mutation-message.hpp.

#include "lib/error.hpp"
#include "lib/iter-source.hpp"
#include "lib/iter-adapter-stl.hpp"
#include "lib/diff/tree-diff.hpp"
#include "lib/diff/gen-node.hpp"
#include "lib/format-util.hpp"
#include "lib/meta/util.hpp"
#include <string>

Classes

struct  DiffSnapshot
 "materialised view" of the diff sequence More...
 
class  MaterialisedDiffBuffer
 Decorator to be layered transparently on top of MutationMessage. More...
 
struct  MutationMessage
 Opaque message to effect a structural change on a target, which is likewise only known in an abstract way, as being specifically structured. More...
 

Typedefs

using _RangeIT = RangeIter< _VecIter >
 
using _VecIter = DiffSnapshot::iterator
 
using _Wrapped = WrappedLumieraIter< _RangeIT >
 
using DiffSource = IterSource< DiffStep >
 
using DiffStep = TreeDiffLanguage::DiffStep
 

Namespaces

 lib
 Implementation namespace for support and library code.