command-binding(#990): add new GenNode based argument binding
based on the new generic tuple builder, we're now able to add a new binding function into the command implementation machinery, alongside the existing one. As it stands, the latter will be used rather by unit tests, while the new access path is what will be actually taken within the application, when receiving argument binding messages dispatched via the UI-Bus.
This commit is contained in:
parent
5abc44b813
commit
3fef76e1d7
8 changed files with 90 additions and 32 deletions
|
|
@ -367,8 +367,10 @@ namespace meta {
|
|||
TRAIT_IS_NARROWING (int64_t, int32_t)
|
||||
TRAIT_IS_NARROWING (int64_t, int16_t)
|
||||
TRAIT_IS_NARROWING (int64_t, int8_t)
|
||||
TRAIT_IS_NARROWING (int64_t, char)
|
||||
TRAIT_IS_NARROWING (int32_t, int16_t)
|
||||
TRAIT_IS_NARROWING (int32_t, int8_t)
|
||||
TRAIT_IS_NARROWING (int32_t, char)
|
||||
TRAIT_IS_NARROWING (int16_t, int8_t)
|
||||
TRAIT_IS_NARROWING (int16_t, short)
|
||||
TRAIT_IS_NARROWING (int16_t, char)
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ namespace control {
|
|||
{ }
|
||||
|
||||
private:
|
||||
virtual bool isValid () const { return false; }
|
||||
virtual bool isValid () const override { return false; }
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -111,13 +111,14 @@ namespace control {
|
|||
ArgumentHolder& operator= (ArgumentHolder const&);
|
||||
|
||||
|
||||
typedef Closure<SIG> ArgHolder;
|
||||
typedef MementoTie<SIG,MEM> MemHolder;
|
||||
using ArgHolder = Closure<SIG>;
|
||||
using MemHolder = MementoTie<SIG,MEM>;
|
||||
|
||||
typedef InPlaceBuffer<ArgHolder, sizeof(ArgHolder), MissingArguments<SIG> > ArgumentBuff;
|
||||
typedef InPlaceBuffer<MemHolder, sizeof(MemHolder), UntiedMemento<SIG,MEM> > MementoBuff;
|
||||
using ArgumentBuff = InPlaceBuffer<ArgHolder, sizeof(ArgHolder), MissingArguments<SIG>>;
|
||||
using MementoBuff = InPlaceBuffer<MemHolder, sizeof(MemHolder), UntiedMemento<SIG,MEM>>;
|
||||
|
||||
typedef typename ArgHolder::ArgTuple ArgTuple;
|
||||
using ArgTuple = typename ArgHolder::ArgTuple;
|
||||
using Args = typename Types<ArgTuple>::Seq;
|
||||
|
||||
|
||||
/* ====== in-place storage buffers ====== */
|
||||
|
|
@ -130,12 +131,14 @@ namespace control {
|
|||
/* ==== proxied CmdClosure interface ==== */
|
||||
|
||||
public:
|
||||
virtual bool isValid () const
|
||||
virtual bool
|
||||
isValid () const override
|
||||
{
|
||||
return arguments_->isValid();
|
||||
}
|
||||
|
||||
virtual bool isCaptured() const
|
||||
virtual bool
|
||||
isCaptured() const override
|
||||
{
|
||||
return memento_->isValid();
|
||||
}
|
||||
|
|
@ -143,16 +146,32 @@ namespace control {
|
|||
|
||||
|
||||
/** assign a new parameter tuple to this */
|
||||
virtual void bindArguments (Arguments& args)
|
||||
{
|
||||
if (!arguments_->isValid())
|
||||
storeTuple (args.get<ArgTuple>());
|
||||
else
|
||||
arguments_->bindArguments(args);
|
||||
}
|
||||
virtual void
|
||||
bindArguments (Arguments& args) override
|
||||
{
|
||||
if (!arguments_->isValid())
|
||||
storeTuple (args.get<ArgTuple>());
|
||||
else
|
||||
arguments_->bindArguments (args);
|
||||
}
|
||||
|
||||
/** assign a new set of parameter values to this.
|
||||
* @note the values are passed packaged into a sequence
|
||||
* of GenNode elements. This is the usual way
|
||||
* arguments are passed from the UI-Bus
|
||||
*/
|
||||
virtual void
|
||||
bindArguments (lib::diff::Rec const& paramData) override
|
||||
{
|
||||
if (!arguments_->isValid())
|
||||
storeTuple (buildTuple<Args> (paramData));
|
||||
else
|
||||
arguments_->bindArguments (paramData);
|
||||
}
|
||||
|
||||
|
||||
virtual void invoke (CmdFunctor const& func)
|
||||
virtual void
|
||||
invoke (CmdFunctor const& func) override
|
||||
{
|
||||
if (!isValid())
|
||||
throw lumiera::error::State ("Lifecycle error: can't bind functor, "
|
||||
|
|
@ -163,7 +182,8 @@ namespace control {
|
|||
}
|
||||
|
||||
|
||||
virtual operator string() const
|
||||
virtual
|
||||
operator string() const override
|
||||
{
|
||||
return "Command-State{ arguments="
|
||||
+ (*arguments_? string(*arguments_) : "unbound")
|
||||
|
|
@ -198,7 +218,7 @@ namespace control {
|
|||
/** assist with creating a clone copy;
|
||||
* this results in invocation of the copy ctor */
|
||||
void
|
||||
accept (CommandImplCloneBuilder& visitor) const
|
||||
accept (CommandImplCloneBuilder& visitor) const override
|
||||
{
|
||||
visitor.buildCloneContext (*this);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@
|
|||
#include "lib/meta/function-closure.hpp"
|
||||
#include "lib/meta/function-erasure.hpp"
|
||||
#include "lib/meta/tuple-helper.hpp"
|
||||
#include "lib/meta/tuple-record-init.hpp"
|
||||
#include "lib/meta/maybe-compare.hpp"
|
||||
#include "lib/format-cout.hpp"
|
||||
#include "lib/util.hpp"
|
||||
|
|
@ -97,6 +98,7 @@ namespace control {
|
|||
using lib::meta::FunErasure;
|
||||
using lib::meta::StoreFunction;
|
||||
using lib::meta::NullType;
|
||||
using lib::meta::buildTuple;
|
||||
|
||||
using lib::meta::equals_safeInvoke;
|
||||
using lib::TypedAllocationManager;
|
||||
|
|
@ -136,6 +138,7 @@ namespace control {
|
|||
virtual bool isCaptured () const =0; ///< does this closure hold captured UNDO state?
|
||||
virtual bool equals (CmdClosure const&) const =0; ///< is equivalent to the given other closure?
|
||||
virtual void bindArguments (Arguments&) =0; ///< store a set of parameter values within this closure
|
||||
virtual void bindArguments (lib::diff::Rec const&) =0; ///< store a set of parameter values, passed as GenNode sequence
|
||||
virtual void invoke (CmdFunctor const&) =0; ///< invoke functor using the stored parameter values
|
||||
virtual void accept (CommandImplCloneBuilder&) const =0; ///< assist with creating clone closure without disclosing concrete type
|
||||
};
|
||||
|
|
@ -146,9 +149,9 @@ namespace control {
|
|||
class AbstractClosure
|
||||
: public CmdClosure
|
||||
{
|
||||
bool isValid() const { return false; }
|
||||
bool isCaptured() const { return false; }
|
||||
void accept (CommandImplCloneBuilder&) const {}
|
||||
bool isValid() const override { return false; }
|
||||
bool isCaptured() const override { return false; }
|
||||
void accept (CommandImplCloneBuilder&) const override {}
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -245,11 +248,22 @@ namespace control {
|
|||
|
||||
/** assign a new parameter tuple to this */
|
||||
void
|
||||
bindArguments (Arguments& args)
|
||||
bindArguments (Arguments& args) override
|
||||
{
|
||||
params_ = args.get<ArgTuple>();
|
||||
}
|
||||
|
||||
/** assign a new set of parameter values to this.
|
||||
* @note the values are passed packaged into a sequence
|
||||
* of GenNode elements. This is the usual way
|
||||
* arguments are passed from the UI-Bus
|
||||
*/
|
||||
void
|
||||
bindArguments (lib::diff::Rec const& paramData) override
|
||||
{
|
||||
params_ = buildTuple<Args> (paramData);
|
||||
}
|
||||
|
||||
|
||||
/** Core operation: use the embedded argument tuple for invoking a functor
|
||||
* @param unboundFunctor an function object, whose function arguments are
|
||||
|
|
@ -260,7 +274,7 @@ namespace control {
|
|||
* Thus this function can't be const.
|
||||
*/
|
||||
void
|
||||
invoke (CmdFunctor const& unboundFunctor)
|
||||
invoke (CmdFunctor const& unboundFunctor) override
|
||||
{
|
||||
TupleApplicator<SIG> apply_this_arguments(params_);
|
||||
apply_this_arguments (unboundFunctor.getFun<SIG>());
|
||||
|
|
@ -268,7 +282,7 @@ namespace control {
|
|||
|
||||
|
||||
|
||||
operator string() const
|
||||
operator string() const override
|
||||
{
|
||||
std::ostringstream buff;
|
||||
params_.dump (buff << "Closure(" );
|
||||
|
|
@ -282,14 +296,14 @@ namespace control {
|
|||
}
|
||||
|
||||
|
||||
bool isValid () const { return true; }
|
||||
bool isValid () const override { return true; }
|
||||
|
||||
/// Supporting equality comparisons...
|
||||
friend bool operator== (Closure const& c1, Closure const& c2) { return compare (c1.params_, c2.params_); }
|
||||
friend bool operator!= (Closure const& c1, Closure const& c2) { return not (c1 == c2); }
|
||||
|
||||
bool
|
||||
equals (CmdClosure const& other) const
|
||||
equals (CmdClosure const& other) const override
|
||||
{
|
||||
const Closure* toCompare = dynamic_cast<const Closure*> (&other);
|
||||
return (toCompare)
|
||||
|
|
|
|||
|
|
@ -61,7 +61,6 @@
|
|||
#include "proc/control/command-registry.hpp"
|
||||
#include "proc/control/command-signature.hpp"
|
||||
#include "proc/control/command-mutation.hpp"
|
||||
#include "proc/control/command-closure.hpp"
|
||||
#include "proc/control/argument-tuple-accept.hpp"
|
||||
#include "lib/bool-checkable.hpp"
|
||||
#include "lib/meta/function.hpp"
|
||||
|
|
|
|||
|
|
@ -162,7 +162,13 @@ namespace control {
|
|||
void
|
||||
setArguments (Arguments& args)
|
||||
{
|
||||
pClo_->bindArguments(args);
|
||||
pClo_->bindArguments (args);
|
||||
}
|
||||
|
||||
void
|
||||
setArguments (lib::diff::Rec const& paramData)
|
||||
{
|
||||
pClo_->bindArguments (paramData);
|
||||
}
|
||||
|
||||
void invokeOperation() { do_(*pClo_); }
|
||||
|
|
|
|||
|
|
@ -249,6 +249,18 @@ namespace control {
|
|||
}
|
||||
|
||||
|
||||
/** @internal forward a `Record<GenNode>`, which was
|
||||
* typically received via UI-Bus, down to the CommandImpl.
|
||||
* @remarks this is how command arguments are actually
|
||||
* passed from UI to the Session core
|
||||
*/
|
||||
void
|
||||
Command::setArguments (lib::diff::Rec const& paramData)
|
||||
{
|
||||
___check_notBottom (this, "Binding arguments of");
|
||||
_Handle::impl().setArguments(paramData);
|
||||
}
|
||||
|
||||
|
||||
/** @return the number of command \em definitions currently registered */
|
||||
size_t
|
||||
|
|
|
|||
|
|
@ -195,6 +195,7 @@ namespace control {
|
|||
|
||||
private:
|
||||
void setArguments (Arguments&);
|
||||
void setArguments (lib::diff::Rec const&);
|
||||
static bool equivalentImpl (Command const&, Command const&);
|
||||
};
|
||||
|
||||
|
|
@ -234,7 +235,8 @@ namespace control {
|
|||
inline Command&
|
||||
Command::bindArg (lib::diff::Rec const& paramData)
|
||||
{
|
||||
UNIMPLEMENTED ("how to accept a GenNode-Rec and unpack it into our argument holder...");
|
||||
this->setArguments (paramData);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -53,6 +53,9 @@ namespace test {
|
|||
using proc::control::LUMIERA_ERROR_INVALID_ARGUMENTS;
|
||||
using proc::control::LUMIERA_ERROR_UNBOUND_ARGUMENTS;
|
||||
|
||||
using lumiera::error::LUMIERA_ERROR_INDEX_BOUNDS; ////////TODO
|
||||
using lumiera::error::LUMIERA_ERROR_WRONG_TYPE; ////////TODO
|
||||
|
||||
namespace { // test fixture...
|
||||
|
||||
}//(End) test fixture
|
||||
|
|
@ -188,15 +191,15 @@ namespace test {
|
|||
|
||||
// we cannot invoke commands prior to binding arguments
|
||||
VERIFY_ERROR (UNBOUND_ARGUMENTS, mock.issueCommand(cmd) );
|
||||
|
||||
// proper argument typing is ensured while dispatching the bind message.
|
||||
VERIFY_ERROR (INDEX_BOUNDS, mock.prepareCommand(cmd, Rec({"lalala"})) ); ////////////TODO : shall we care to get INVALID_ARGUMENTS here??
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////TODO WIP
|
||||
cout << "____Nexus-Log_________________\n"
|
||||
<< util::join(gui::test::Nexus::getLog(), "\n")
|
||||
<< "\n───╼━━━━━━━━━╾────────────────"<<endl;
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////TODO WIP
|
||||
|
||||
// proper argument typing is ensured while dispatching the bind message.
|
||||
VERIFY_ERROR (INVALID_ARGUMENTS, mock.prepareCommand(cmd, Rec({"lalala"})) );
|
||||
|
||||
// command can't be issued, since it's still unbound
|
||||
CHECK (not gui::test::Nexus::canInvoke(cmd));
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue