libqi-api  2.4.3.28
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
futureadapter.hxx
Go to the documentation of this file.
1 #pragma once
2 /*
3 ** Copyright (C) 2013 Aldebaran Robotics
4 ** See COPYING for the license
5 */
6 
7 #ifndef QI_TYPE_DETAIL_FUTURE_ADAPTER_HXX_
8 #define QI_TYPE_DETAIL_FUTURE_ADAPTER_HXX_
9 
10 #include <boost/scope_exit.hpp>
11 
13 
14 namespace qi
15 {
16 namespace detail
17 {
18 
19 template<typename T> void setPromise(qi::Promise<T>& promise, AnyValue& v)
20 {
21  try
22  {
23  qiLogDebug("qi.adapter") << "converting value";
24  T val = v.to<T>();
25  qiLogDebug("qi.adapter") << "setting promise";
26  promise.setValue(val);
27  qiLogDebug("qi.adapter") << "done";
28  }
29  catch(const std::exception& e)
30  {
31  qiLogError("qi.adapter") << "future to promise forwarding error: " << e.what();
32  promise.setError(e.what());
33  }
34 }
35 
36 template<> inline void setPromise(qi::Promise<void>& promise, AnyValue&)
37 {
38  promise.setValue(0);
39 }
40 
41 template<> inline void setPromise(qi::Promise<AnyValue>& promise, AnyValue& val)
42 {
43  promise.setValue(val);
44 }
45 
46 template <typename T>
48  boost::shared_ptr<GenericObject>& ao)
49 {
50  assert(ao);
51  qiLogDebug("qi.adapter") << "futureAdapter trigger";
52  TypeOfTemplate<Future>* ft1 = QI_TEMPLATE_TYPE_GET(val.type(), Future);
53  TypeOfTemplate<FutureSync>* ft2 = QI_TEMPLATE_TYPE_GET(val.type(), FutureSync);
54  qiLogDebug("qi.adapter") << "isFuture " << val.type()->infoString() << ' ' << !!ft1 << ' ' << !!ft2;
55  bool isvoid = false;
56  if (ft1)
57  isvoid = ft1->templateArgument()->kind() == TypeKind_Void;
58  else if (ft2)
59  isvoid = ft2->templateArgument()->kind() == TypeKind_Void;
60  GenericObject& gfut = *ao;
61  // reset the shared_ptr to break the cycle
62  BOOST_SCOPE_EXIT_TPL(&ao, &val) {
63  ao.reset();
64  val.destroy();
65  } BOOST_SCOPE_EXIT_END
66  if (gfut.call<bool>("hasError", 0))
67  {
68  qiLogDebug("qi.adapter") << "futureAdapter: future in error";
69  std::string s = gfut.call<std::string>("error", 0);
70  qiLogDebug("qi.adapter") << "futureAdapter: got error: " << s;
71  promise.setError(s);
72  return;
73  }
74  if (gfut.call<bool>("isCanceled"))
75  {
76  qiLogDebug("qi.adapter") << "futureAdapter: future canceled";
77  promise.setCanceled();
78  return;
79  }
80  qiLogDebug("qi.adapter") << "futureAdapter: future has value";
81  AnyValue v = gfut.call<AnyValue>("value", 0);
82  // For a Future<void>, value() gave us a void*
83  if (isvoid)
84  v = AnyValue(qi::typeOf<void>());
85  qiLogDebug("qi.adapter") << v.type()->infoString();
86  setPromise(promise, v);
87  qiLogDebug("qi.adapter") << "Promise set";
88 }
89 
90 // return a generic object pointing to the future referenced by val or null if val is not a future
91 // remember that you need a shared_ptr pointing on the genericobject so that it can work (shared_from_this)
92 inline boost::shared_ptr<GenericObject> getGenericFuture(AnyReference val, TypeKind* kind = 0)
93 {
94  TypeOfTemplate<Future>* ft1 = QI_TEMPLATE_TYPE_GET(val.type(), Future);
95  TypeOfTemplate<FutureSync>* ft2 = QI_TEMPLATE_TYPE_GET(val.type(), FutureSync);
96  ObjectTypeInterface* onext = NULL;
97  qiLogDebug("qi.adapter") << "isFuture " << val.type()->infoString() << ' ' << !!ft1 << ' ' << !!ft2;
98  if (ft1)
99  {
100  if (kind)
101  *kind = ft1->templateArgument()->kind();
102  onext = ft1;
103  }
104  else if (ft2)
105  {
106  if (kind)
107  *kind = ft2->templateArgument()->kind();
108  onext = ft2;
109  }
110  if (!onext)
111  return boost::shared_ptr<GenericObject>();
112  return boost::make_shared<GenericObject>(onext, val.rawValue());
113 }
114 
115 // futureAdapter helper that detects and handles value of kind future
116 // return true if value was a future and was handled
117 template <typename T>
118 inline bool handleFuture(AnyReference val, Promise<T> promise)
119 {
120  boost::shared_ptr<GenericObject> ao = getGenericFuture(val);
121  if (!ao)
122  return false;
123 
124  boost::function<void()> cb =
125  boost::bind(futureAdapterGeneric<T>, val, promise, ao);
126  // Careful, gfut will die at the end of this block, but it is
127  // stored in call data. So call must finish before we exit this block,
128  // and thus must be synchronous.
129  try
130  {
131  ao->call<void>("_connect", cb);
132  promise.setOnCancel(
133  qi::bindWithFallback<void(const qi::Promise<T>&)>(
134  boost::function<void()>(),
135  static_cast<void(GenericObject::*)(const std::string&)>(
136  &GenericObject::call<void>),
137  boost::weak_ptr<GenericObject>(ao),
138  "cancel"));
139  }
140  catch (std::exception& e)
141  {
142  qiLogError("qi.object") << "future connect error " << e.what();
143  }
144  return true;
145 }
146 
148 {
152  {
153  val.destroy();
154  }
155 };
156 
157 template <typename T>
159 {
160  AnyReference val = metaFut.value();
161  AutoRefDestroy destroy(val);
162 
163  boost::shared_ptr<GenericObject> ao = getGenericFuture(val);
164  AnyValue hold;
165  if (ao)
166  {
167  hold = ao->call<qi::AnyValue>("value", (int)FutureTimeout_Infinite);
168  val = hold.asReference();
169  }
170 
171  static TypeInterface* targetType;
172  QI_ONCE(targetType = typeOf<T>());
173  try
174  {
175  std::pair<AnyReference, bool> conv = val.convert(targetType);
176  if (!conv.first.type())
177  throw std::runtime_error(std::string("Unable to convert call result to target type: from ")
178  + val.signature(true).toPrettySignature() + " to " + targetType->signature().toPrettySignature());
179  else
180  {
181  if (conv.second)
182  {
183  AutoRefDestroy destroy(conv.first);
184  return *conv.first.ptr<T>(false);
185  }
186  else
187  return *conv.first.ptr<T>(false);
188  }
189  }
190  catch(const std::exception& e)
191  {
192  throw std::runtime_error(std::string("Return argument conversion error: ") + e.what());
193  }
194 }
195 
196 template <>
198 {
199  AnyReference val = metaFut.value();
200  val.destroy();
201 }
202 
203 template <typename T>
205 {
206  qiLogDebug("qi.object") << "futureAdapter " << qi::typeOf<T>()->infoString()<< ' ' << metaFut.hasError();
207  //error handling
208  if (metaFut.hasError()) {
209  promise.setError(metaFut.error());
210  return;
211  }
212  if (metaFut.isCanceled()) {
213  promise.setCanceled();
214  return;
215  }
216 
217  AnyReference val = metaFut.value();
218  if (handleFuture(val, promise))
219  return;
220 
221  static TypeInterface* targetType;
222  QI_ONCE(targetType = typeOf<T>());
223  try
224  {
225  std::pair<AnyReference, bool> conv = val.convert(targetType);
226  if (!conv.first.type())
227  promise.setError(std::string("Unable to convert call result to target type: from ")
228  + val.signature(true).toPrettySignature() + " to " + targetType->signature().toPrettySignature() );
229  else
230  {
231  promise.setValue(*conv.first.ptr<T>(false));
232  }
233  if (conv.second)
234  conv.first.destroy();
235  }
236  catch(const std::exception& e)
237  {
238  promise.setError(std::string("Return argument conversion error: ") + e.what());
239  }
240  val.destroy();
241 }
242 
243 template <>
245 {
246  qiLogDebug("qi.object") << "futureAdapter void " << metaFut.hasError();
247  //error handling
248  if (metaFut.hasError()) {
249  promise.setError(metaFut.error());
250  return;
251  }
252  if (metaFut.isCanceled()) {
253  promise.setCanceled();
254  return;
255  }
256  AnyReference val = metaFut.value();
257  if (handleFuture(val, promise))
258  return;
259 
260  promise.setValue(0);
261  val.destroy();
262 }
263 
264 template <typename T>
266 {
267  //error handling
268  if (metaFut.hasError()) {
269  promise.setError(metaFut.error());
270  return;
271  }
272  if (metaFut.isCanceled()) {
273  promise.setCanceled();
274  return;
275  }
276  const AnyValue& val = metaFut.value();
277  try
278  {
279  promise.setValue(val.to<T>());
280  }
281  catch (const std::exception& e)
282  {
283  promise.setError(std::string("Return argument conversion error: ") + e.what());
284  }
285 }
286 
287 template<>
289 {
290  if (metaFut.hasError())
291  promise.setError(metaFut.error());
292  else if (metaFut.isCanceled())
293  promise.setCanceled();
294  else
295  promise.setValue(metaFut.value());
296 }
297 
298 }
299 }
300 
301 #endif
std::pair< AnyReference, bool > convert(TypeInterface *targetType) const
void futureAdapter< void >(qi::Future< qi::AnyReference > metaFut, qi::Promise< void > promise)
std::string toPrettySignature() const
AutoRefDestroy(AnyReference ref)
void destroy()
Stop and flush the logging system.
void extractFuture< void >(qi::Future< qi::AnyReference > metaFut)
boost::function< RF > bind(const AF &fun,...)
#define qiLogDebug(...)
Definition: log.hpp:69
void setError(const std::string &msg)
Definition: future_fwd.hpp:689
bool isCanceled() const
Definition: future_fwd.hpp:255
void futureAdapterGeneric(AnyReference val, qi::Promise< T > promise, boost::shared_ptr< GenericObject > &ao)
void setPromise(qi::Promise< T > &promise, AnyValue &v)
void futureAdapter(Future< FT > f, Promise< PT > p, CONV converter)
Definition: future.hxx:557
void destroy()
Deletes storage.
#define qiLogError(...)
Log in error mode.
Definition: log.hpp:113
T to() const
Convert to anything or throw trying.
qi::Signature signature(bool resolveDynamic=false) const
TypeInterface * type() const
void setOnCancel(boost::function< void(qi::Promise< T >)> cancelCallback)
Definition: future_fwd.hpp:724
#define QI_TEMPLATE_TYPE_GET(typeInst, templateName)
#define QI_ONCE(code)
Execute code once, parallel calls are blocked until code finishes.
Definition: atomic.hpp:298
boost::shared_ptr< GenericObject > getGenericFuture(AnyReference val, TypeKind *kind=0)
AnyReference asReference() const
Definition: anyvalue.hpp:80
const char * infoString()
void futureAdapterVal(qi::Future< qi::AnyValue > metaFut, qi::Promise< T > promise)
R call(const std::string &eventName, qi::AutoAnyReference p1=qi::AutoAnyReference(), qi::AutoAnyReference p2=qi::AutoAnyReference(), qi::AutoAnyReference p3=qi::AutoAnyReference(), qi::AutoAnyReference p4=qi::AutoAnyReference(), qi::AutoAnyReference p5=qi::AutoAnyReference(), qi::AutoAnyReference p6=qi::AutoAnyReference(), qi::AutoAnyReference p7=qi::AutoAnyReference(), qi::AutoAnyReference p8=qi::AutoAnyReference())
T extractFuture(qi::Future< qi::AnyReference > metaFut)
void hold(T data)
void setCanceled()
Definition: future_fwd.hpp:696
const std::string & error(int msecs=FutureTimeout_Infinite) const
Definition: future_fwd.hpp:283
const ValueType & value(int msecs=FutureTimeout_Infinite) const
Return the value associated to a Future.
Definition: future_fwd.hpp:200
TypeKind
Definition: fwd.hpp:53
void setValue(const ValueType &value)
Definition: future_fwd.hpp:682
bool handleFuture(AnyReference val, Promise< T > promise)
qi::Signature signature(void *storage=0, bool resolveDynamic=false)
bool hasError(int msecs=FutureTimeout_Infinite) const
Definition: future_fwd.hpp:264