Lumiera  0.pre.03
»edityourfreedom«
command-setup.cpp
Go to the documentation of this file.
1 /*
2  CommandSetup - Implementation of command registration and instance management
3 
4  Copyright (C) Lumiera.org
5  2017, Hermann Vosseler <Ichthyostega@web.de>
6 
7  This program is free software; you can redistribute it and/or
8  modify it under the terms of the GNU General Public License as
9  published by the Free Software Foundation; either version 2 of
10  the License, or (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 
21 * *****************************************************/
22 
23 
38 #include "lib/error.hpp"
39 #include "include/logging.h"
40 #include "include/lifecycle.h"
41 #include "proc/control/command.hpp"
45 #include "lib/symbol.hpp"
46 #include "lib/format-string.hpp"
47 #include "lib/util.hpp"
48 
49 #include <tuple>
50 #include <utility>
51 
52 using std::tuple;
53 using std::get;
54 using std::function;
55 using std::move;
56 using lib::Symbol;
59 using std::string;
60 using util::unConst;
61 using util::_Fmt;
62 
63 
64 namespace proc {
65 namespace control {
66  namespace error = lumiera::error;
67 
68  namespace { // implementation details: storage for pending static command definitions...
69 
70  using CmdDefEntry = std::tuple<Symbol, DefinitionClosure>;
71 
72  std::deque<CmdDefEntry>&
73  pendingCmdDefinitions()
74  {
75  static std::deque<CmdDefEntry> definitionQueue;
76  return definitionQueue;
77  }
78 
79  }//(End) implementation details
80 
81 
82 
83 
84 
85 
87 
95  : cmdID_(cmdID)
96  { }
97 
98 
120  CommandSetup&
122  {
123  if (not definitionBlock)
124  throw error::Invalid ("unbound function/closure provided for CommandSetup"
125  , error::LERR_(BOTTOM_VALUE));
126 
127  pendingCmdDefinitions().emplace_front (cmdID_, move(definitionBlock));
128  return *this;
129  }
130 
131 
132  size_t
134  {
135  return pendingCmdDefinitions().size();
136  }
137 
138  void
140  {
141  while (not pendingCmdDefinitions().empty())
142  {
143  CmdDefEntry& entry = pendingCmdDefinitions().back();
144  Symbol& cmdID{get<Symbol>(entry)};
145  DefinitionClosure& buildDefinition{get<DefinitionClosure> (entry)};
146 
147  TRACE (command, "defining Command(%s)...", cmdID.c());
148  CommandDef def(cmdID);
149  buildDefinition(def);
150  pendingCmdDefinitions().pop_back();
151  }
152  }
153 
154  namespace { // automatically invoke static command definitions
155 
157  }
158 
159 
160 
161 
162 
163  // emit dtors of embedded objects here....
165 
171  : dispatcher_{dispatcher}
173  { }
174 
175 
181  Symbol
182  CommandInstanceManager::newInstance (Symbol prototypeID, string const& invocationID)
183  {
184  Symbol instanceID{prototypeID, invocationID};
185  Command& instance = table_[instanceID];
186  if (instance)
187  throw new error::Logic (_Fmt{"Attempt to create a new Command instance '%s', "
188  "while an instance for this invocationID %s "
189  "is currently open for parametrisation and "
190  "not yet dispatched for execution."}
191  % instanceID % invocationID
192  , LERR_(DUPLICATE_COMMAND)
193  );
194  // create new clone from the prototype
195  table_[instanceID] = move (Command::get(prototypeID).newInstance());
196  ENSURE (instance, "cloning of command prototype failed");
197  return instanceID;
198  }
199 
200 
213  Command
215  {
216  auto entry = table_.find(instanceID);
217  if (entry == table_.end())
218  return Command::get(instanceID);
219  if (not entry->second)
220  throw error::Logic (_Fmt{"Command instance '%s' is not (yet/anymore) active"}
221  % instanceID
222  , error::LERR_(LIFECYCLE));
223  return entry->second;
224  }
225 
226 
232  Command
233  CommandInstanceManager::getCloneOrInstance (Symbol instanceID, bool must_be_bound)
234  {
235  Command instance = Command::maybeGetNewInstance (instanceID);
236  if (not instance)
237  { // second attempt: search of a locally "opened" instance
238  auto entry = table_.find(instanceID);
239  if (entry == table_.end())
240  throw error::Invalid(_Fmt("Command-ID \"%s\" refers neither to a "
241  "globally registered command definition, "
242  "nor to an previously opened command instance")
243  % instanceID
244  , LERR_(INVALID_COMMAND));
245  if (not entry->second.isValid())
246  throw error::Logic (_Fmt{"Command instance '%s' is not (yet/anymore) active"}
247  % instanceID
248  , error::LERR_(LIFECYCLE));
249  if (not must_be_bound or entry->second.canExec())
250  instance = move(entry->second);
251  }
252  if (must_be_bound and not instance.canExec())
253  throw error::State (_Fmt{"attempt to dispatch command instance '%s' "
254  "without binding all arguments properly beforehand"}
255  % instanceID
256  , LERR_(UNBOUND_ARGUMENTS));
257 
258  ENSURE (instance.isValid() and
259  (instance.canExec() or not must_be_bound));
260  return instance;
261  }
262 
263 
265  void
267  {
268  REQUIRE (toDispatch and toDispatch.canExec());
269  dispatcher_.enqueue(move (toDispatch));
270  ENSURE (not toDispatch);
271  }
272 
273 
283  void
285  {
286  handOver (getCloneOrInstance (instanceID, true));
287  }
288 
289 
301  void
303  {
304  Command instance{getCloneOrInstance (instanceID, false)};
305  REQUIRE (instance);
306  instance.bindArg (argSeq);
307  ENSURE (instance.canExec());
308  handOver (move (instance));
309  }
310 
311 
312  bool
314  {
315  return util::contains (table_, instanceID)
316  and unConst(this)->table_[instanceID].isValid();
317  }
318 
319 
320 
321 }} // namespace proc::control
Installing and invoking of application lifecycle event callbacks.
Record< GenNode > Rec
Definition: gen-node.hpp:133
static size_t definition_count()
Definition: command.cpp:296
Command getCloneOrInstance(Symbol, bool)
LumieraError< LERR_(INVALID)> Invalid
Definition: error.hpp:216
std::function< void(CommandDef &)> DefinitionClosure
Front-end for printf-style string template interpolation.
Service to support forming and invocation of command instances for use by the UI. ...
Symbol newInstance(Symbol prototypeID, string const &invocationID)
Create and thus "open" a new anonymous command instance.
This header is for including and configuring NoBug.
A front-end for using printf-style formatting.
Helper class used solely for defining a Command-Object.
Command getInstance(Symbol instanceID)
access the currently "opened" instance with the given instanceID
static void invokeDefinitionClosures()
bool contains(Symbol instanceID) const
Derived specific exceptions within Lumiera&#39;s exception hierarchy.
Definition: error.hpp:196
void dispatch(Symbol instanceID)
hand over the designated command instance to the dispatcher installed on construction.
Token or Atom with distinct identity.
Definition: symbol.hpp:116
void bindAndDispatch(Symbol instanceID, Rec const &argSeq)
fire and forget anonymous command instance.
bool contains(MAP &map, typename MAP::key_type const &key)
shortcut for containment test on a map
Definition: util.hpp:205
#define LERR_(_NAME_)
Definition: error.hpp:58
Marker types to indicate a literal string and a Symbol.
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
std::unordered_map< Symbol, Command > table_
Provision for setup of concrete commands for use by the UI.
Proc-Layer command frontend.
const char * ON_GLOBAL_INIT
to be triggered in main()
static Command get(Symbol cmdID)
Access existing command for use.
Definition: command.cpp:127
LumieraError< LERR_(LOGIC)> Logic
Definition: error.hpp:212
CommandSetup & operator=(DefinitionClosure)
core functionality: provide a command definition block.
define and register a callback for a specific lifecycle event.
Definition: lifecycle.h:76
Lumiera error handling (C++ interface).
TRACE(test, "inserted %d", data)
OBJ * unConst(const OBJ *o)
shortcut to save some typing when having to define const and non-const variants of member functions ...
Definition: util.hpp:319
CommandInstanceManager(CommandDispatch &)
create a CommandInstanceManager and wire it with the given CommandDispatch implementation.
static size_t pendingCnt()
diagnostics / test
Handle object representing a single Command instance to be used by client code.
Definition: command.hpp:125
CommandSetup(Symbol cmdID)
Start a command setup for defining a Proc-Layer command with the given cmdID.
static Command maybeGetNewInstance(Symbol cmdID)
try to access an existing command definition and immediately create a new clone copy by calling newIn...
Definition: command.cpp:147
Interface of a service to perform Commands on the session.
virtual void enqueue(Command &&)=0
Proc-Layer implementation namespace root.
Definition: id-scheme.hpp:63
Actually defining a command and binding it to execution parameters.
Marker and Helper for writing Proc-Layer Command definitions.
ENSURE(r==&pq)