From 3fef76e1d7d6b5152ad256585bd98c98f92f8dce Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 29 Jan 2016 00:59:34 +0100 Subject: [PATCH] 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. --- src/lib/meta/trait.hpp | 2 + src/proc/control/command-argument-holder.hpp | 56 +++++++++++++------- src/proc/control/command-closure.hpp | 30 ++++++++--- src/proc/control/command-def.hpp | 1 - src/proc/control/command-impl.hpp | 8 ++- src/proc/control/command.cpp | 12 +++++ src/proc/control/command.hpp | 4 +- tests/gui/bus-term-test.cpp | 9 ++-- 8 files changed, 90 insertions(+), 32 deletions(-) diff --git a/src/lib/meta/trait.hpp b/src/lib/meta/trait.hpp index a12055522..3ee151a81 100644 --- a/src/lib/meta/trait.hpp +++ b/src/lib/meta/trait.hpp @@ -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) diff --git a/src/proc/control/command-argument-holder.hpp b/src/proc/control/command-argument-holder.hpp index 120ad9c78..221e787a1 100644 --- a/src/proc/control/command-argument-holder.hpp +++ b/src/proc/control/command-argument-holder.hpp @@ -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 ArgHolder; - typedef MementoTie MemHolder; + using ArgHolder = Closure; + using MemHolder = MementoTie; - typedef InPlaceBuffer > ArgumentBuff; - typedef InPlaceBuffer > MementoBuff; + using ArgumentBuff = InPlaceBuffer>; + using MementoBuff = InPlaceBuffer>; - typedef typename ArgHolder::ArgTuple ArgTuple; + using ArgTuple = typename ArgHolder::ArgTuple; + using Args = typename Types::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()); - else - arguments_->bindArguments(args); - } + virtual void + bindArguments (Arguments& args) override + { + if (!arguments_->isValid()) + storeTuple (args.get()); + 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 (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); } diff --git a/src/proc/control/command-closure.hpp b/src/proc/control/command-closure.hpp index 48f6c41dd..21aa47cdd 100644 --- a/src/proc/control/command-closure.hpp +++ b/src/proc/control/command-closure.hpp @@ -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(); } + /** 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 (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 apply_this_arguments(params_); apply_this_arguments (unboundFunctor.getFun()); @@ -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 (&other); return (toCompare) diff --git a/src/proc/control/command-def.hpp b/src/proc/control/command-def.hpp index 1c4e0e19c..13b4dcc8e 100644 --- a/src/proc/control/command-def.hpp +++ b/src/proc/control/command-def.hpp @@ -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" diff --git a/src/proc/control/command-impl.hpp b/src/proc/control/command-impl.hpp index 43eaae805..672a8400b 100644 --- a/src/proc/control/command-impl.hpp +++ b/src/proc/control/command-impl.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_); } diff --git a/src/proc/control/command.cpp b/src/proc/control/command.cpp index f3605c40e..bcea3f989 100644 --- a/src/proc/control/command.cpp +++ b/src/proc/control/command.cpp @@ -249,6 +249,18 @@ namespace control { } + /** @internal forward a `Record`, 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 diff --git a/src/proc/control/command.hpp b/src/proc/control/command.hpp index 639ccb52f..97f5fa855 100644 --- a/src/proc/control/command.hpp +++ b/src/proc/control/command.hpp @@ -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; } diff --git a/tests/gui/bus-term-test.cpp b/tests/gui/bus-term-test.cpp index 1d55d63ca..d73bbca18 100644 --- a/tests/gui/bus-term-test.cpp +++ b/tests/gui/bus-term-test.cpp @@ -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───╼━━━━━━━━━╾────────────────"<