RemoteProcedure.h
1 /*
2  Copyright (C) 2009-2026 by Marc Duerner
3 
4  This library is free software; you can redistribute it and/or
5  modify it under the terms of the GNU Lesser General Public
6  License as published by the Free Software Foundation; either
7  version 2.1 of the License, or (at your option) any later version.
8 
9  As a special exception, you may use this file as part of a free
10  software library without restriction. Specifically, if other files
11  instantiate templates or use macros or inline functions from this
12  file, or you compile this file and link it with other files to
13  produce an executable, this file does not by itself cause the
14  resulting executable to be covered by the GNU General Public
15  License. This exception does not however invalidate any other
16  reasons why the executable file might be covered by the GNU Library
17  General Public License.
18 
19  This library is distributed in the hope that it will be useful,
20  but WITHOUT ANY WARRANTY; without even the implied warranty of
21  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22  Lesser General Public License for more details.
23 
24  You should have received a copy of the GNU Lesser General Public
25  License along with this library; if not, write to the:
26  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
27  Boston, MA 02110-1301 USA
28 */
29 
30 #ifndef PT_REMOTING_REMOTEPROCEDURE_H
31 #define PT_REMOTING_REMOTEPROCEDURE_H
32 
33 #include <Pt/Remoting/Api.h>
34 #include <Pt/Remoting/Client.h>
35 #include <Pt/SerializationContext.h>
36 #include <Pt/Composer.h>
37 #include <Pt/Decomposer.h>
38 #include <Pt/NonCopyable.h>
39 #include <Pt/Signal.h>
40 #include <Pt/String.h>
41 #include <cstddef>
42 #include <string>
43 
44 namespace Pt {
45 
46 namespace Remoting {
47 
50 class PT_REMOTING_API RemoteCall : private Pt::NonCopyable
51 {
52  public:
53  RemoteCall(Client& client, const String& name);
54 
55  RemoteCall(Client& client, const std::string& name);
56 
57  RemoteCall(Client& client, const char* name);
58 
59  virtual ~RemoteCall();
60 
63  Client& client()
64  { return *_client; }
65 
68  const String& name() const
69  { return _name; }
70 
73  bool isFailed() const
74  { return _client->isFailed(); }
75 
78  void cancel();
79 
82  void setReady();
83 
86  void endCall();
87 
88  protected:
91  virtual void onReady() = 0;
92 
95  virtual void onReset() = 0;
96 
99  virtual void onClear() = 0;
100 
101  private:
102  Client* _client;
103  String _name;
104 };
105 
106 
109 template <typename R>
110 class Result : private Pt::NonCopyable
111 {
112  public:
115  explicit Result(RemoteCall* call = 0)
116  : _call(call)
117  , _result(0)
118  {
119  _result = new (_mem) R;
120  }
121 
122  ~Result()
123  {
124  _result->~R();
125  }
126 
127  void init(RemoteCall* call)
128  { _call = call; }
129 
134  bool isFailed() const
135  {
136  return _call->isFailed();
137  }
138 
141  R& value()
142  { return *_result; }
143 
151  const R& get() const
152  {
153  _call->endCall();
154  return *_result;
155  }
156 
157  void clear()
158  {
159  _result->~R();
160  _result = new (_mem) R;
161  }
162 
163  private:
164  RemoteCall* _call;
165  char _mem[ sizeof(R) ];
166  R* _result;
167 };
168 
169 
172 template <typename R>
173 class RemoteProcedureBase : public RemoteCall
174 {
175  public:
176  RemoteProcedureBase(Client& client, const std::string& name)
177  : RemoteCall(client, name)
178  , _result(0)
179  , _r(0)
180  {
181  _result.init(this);
182  }
183 
184  ~RemoteProcedureBase()
185  {
186  if(_r)
187  _r->~BasicComposer<R>();
188  }
189 
192  Result<R>& result()
193  {
194  return _result;
195  }
196 
199  const Result<R>& result() const
200  {
201  return _result;
202  }
203 
206  Signal< const Result<R>& >& finished()
207  { return _finished; }
208 
209  protected:
210  void onReady()
211  { _finished.send(_result); }
212 
213  BasicComposer<R>& beginResult()
214  {
215  if(_r)
216  {
217  _r->~BasicComposer<R>();
218  _r = 0;
219  }
220 
221  _r = new (_mem) BasicComposer<R>( &client().context() );
222  _r->begin( result().value() );
223  return *_r;
224  }
225 
226  virtual void onReset()
227  {
228  if(_r)
229  {
230  _r->~BasicComposer<R>();
231  _r = 0;
232  }
233  }
234 
235  virtual void onClear()
236  {
237  this->onReset();
238  _result.clear();
239  }
240 
241  private:
242  Signal< const Result<R>& > _finished;
243  Result<R> _result;
244  char _mem[ sizeof(BasicComposer<R>) ];
245  BasicComposer<R>* _r;
246 };
247 
248 
249 template <typename A>
250 class RemoteArgument : private Pt::NonCopyable
251 {
252  public:
253  RemoteArgument(SerializationContext* )
254  : _decomposer(0)
255  { }
256 
257  ~RemoteArgument()
258  {
259  if(_decomposer)
260  _decomposer->~BasicDecomposer<A>();
261  }
262 
263  void begin(const A& a, const char* name, SerializationContext& ctx)
264  {
265  if(_decomposer)
266  {
267  _decomposer->~BasicDecomposer<A>();
268  _decomposer = 0;
269  }
270 
271  _decomposer = new (_mem) BasicDecomposer<A>(&ctx);
272  _decomposer->begin(a, name);
273  }
274 
275  void clear(SerializationContext* )
276  {
277  if(_decomposer)
278  {
279  _decomposer->~BasicDecomposer<A>();
280  _decomposer = 0;
281  }
282  }
283 
284  // TODO: return decomposer pointer from begin
285  BasicDecomposer<A>* decomposer()
286  { return reinterpret_cast<BasicDecomposer<A>*>(_mem); }
287 
288  private:
289  char _mem[ sizeof(BasicDecomposer<A>) ];
290  BasicDecomposer<A>* _decomposer;
291 };
292 
293 
294 template <typename... Ts>
295 class RemoteArguments;
296 
297 
298 template <>
299 class RemoteArguments<>
300 {
301  public:
302  explicit RemoteArguments(SerializationContext* /*ctx*/)
303  { }
304 
305  void begin(SerializationContext& /*ctx*/)
306  { }
307 
308  void fill(std::size_t i, Decomposer** args)
309  {
310  args[i] = 0;
311  }
312 
313  void clear(SerializationContext* /*ctx*/)
314  { }
315 };
316 
317 
318 template <typename T, typename... Ts>
319 class RemoteArguments<T, Ts...>
320 {
321  public:
322  explicit RemoteArguments(SerializationContext* ctx)
323  : _head(ctx)
324  , _tail(ctx)
325  { }
326 
327  void begin(SerializationContext& ctx, const T& a, const Ts&... as)
328  {
329  _head.begin(a, "", ctx);
330  _tail.begin(ctx, as...);
331  }
332 
333  void fill(std::size_t i, Decomposer** args)
334  {
335  args[i] = _head.decomposer();
336  _tail.fill(i + 1, args);
337  }
338 
339  void clear(SerializationContext* ctx)
340  {
341  _head.clear(ctx);
342  _tail.clear(ctx);
343  }
344 
345  private:
346  RemoteArgument<T> _head;
347  RemoteArguments<Ts...> _tail;
348 };
349 
350 
372 template <typename R, typename... As>
373 class RemoteProcedure : public RemoteProcedureBase<R>
374 {
375  public:
378  RemoteProcedure(Client& client, const std::string& name)
379  : RemoteProcedureBase<R>(client, name)
380  , _argv( &client.context() )
381  {
382  _argv.fill(0, _args);
383  }
384 
388  { }
389 
392  void begin(const As&... args)
393  {
394  try
395  {
396  _argv.begin(this->client().context(), args...);
397  BasicComposer<R>& r = this->beginResult();
398 
399  this->client().beginCall(r, *this, _args, sizeof...(As));
400  }
401  catch(...)
402  {
403  this->onClear();
404  throw;
405  }
406  }
407 
410  const R& call(const As&... args)
411  {
412  try
413  {
414  _argv.begin(this->client().context(), args...);
415  BasicComposer<R>& r = this->beginResult();
416 
417  this->client().call(r, *this, _args, sizeof...(As));
418  this->onReset();
419  }
420  catch(...)
421  {
422  this->onClear();
423  throw;
424  }
425 
426  return this->result().value();
427  }
428 
431  const R& operator()(const As&... args)
432  {
433  return this->call(args...);
434  }
435 
436  protected:
437  void onReset()
438  {
439  RemoteProcedureBase<R>::onReset();
440  _argv.clear( &this->client().context() );
441  }
442 
443  private:
444  RemoteArguments<As...> _argv;
445  Decomposer* _args[sizeof...(As) + 1];
446 };
447 
448 } // namespace Remoting
449 
450 } // namespace Pt
451 
452 #endif // PT_REMOTING_REMOTEPROCEDURE_H
Core module.
Definition: Allocator.h:33
Manages the decomposition of types during serialization.
Definition: Decomposer.h:44
const R & call(const As &... args)
Blocking remote call.
Definition: RemoteProcedure.h:410
RemoteProcedure(Client &client, const std::string &name)
Construct with procedure name and client.
Definition: RemoteProcedure.h:378
const R & get() const
Ends a remote procedure call.
Definition: RemoteProcedure.h:151
bool isFailed() const
Indicates if the procedure has failed.
Definition: RemoteProcedure.h:134
R & value()
The return value.
Definition: RemoteProcedure.h:141
Performs a remote procedure call.
Definition: RemoteProcedure.h:374
Result(RemoteCall *call=0)
Constructor.
Definition: RemoteProcedure.h:115
const R & operator()(const As &... args)
Blocking remote call.
Definition: RemoteProcedure.h:431
virtual ~RemoteProcedure()
Destructor.
Definition: RemoteProcedure.h:387
void begin(const As &... args)
Begins an asynchronous remote call.
Definition: RemoteProcedure.h:392
A client for remote procedure calls.
Definition: Client.h:48
Protects derived classes from being copied.
Definition: NonCopyable.h:54
Result of a remote procedure call.
Definition: RemoteProcedure.h:111