- Aldebaran documentation |
- C++ Libraries |
- index

libqi-api 2.8.7.4

- Main Page
- Related Pages
- Namespaces
- Classes
- Files
- Examples

- File List
- File Members

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 <qi/type/detail/futureadapter.hpp>
11
12 namespace qi
13 {
14 namespace detail
15 {
16
17 static const char* InvalidValueError = "value is invalid";
18 static const char* InvalidFutureError = "function returned an invalid future";
19
20 template<typename T> void setPromise(qi::Promise<T>& promise, const AnyValue& v)
21 {
22 if (!v.isValid())
23 {
24 promise.setError(InvalidValueError);
25 return;
26 }
27
28 try
29 {
30 qiLogDebug("qi.adapter") << "converting value";
31 T val = v.to<T>();
32 qiLogDebug("qi.adapter") << "setting promise";
33 promise.setValue(val);
34 qiLogDebug("qi.adapter") << "done";
35 }
36 catch(const std::exception& e)
37 {
38 qiLogError("qi.adapter") << "future to promise forwarding error: " << e.what();
39 promise.setError(e.what());
40 }
41 }
42
43 template<> inline void setPromise(qi::Promise<void>& promise, const AnyValue&)
44 {
45 promise.setValue(0);
46 }
47
48 template<> inline void setPromise(qi::Promise<AnyValue>& promise, const AnyValue& val)
49 {
50 promise.setValue(val);
51 }
52
53 template<> inline void setPromise(qi::Promise<AnyReference>& promise, const AnyValue& val)
54 {
55 promise.setValue(val.clone());
56 }
57
58 template <typename T>
59 void futureAdapterGeneric(AnyReference val, qi::Promise<T> promise,
60 boost::shared_ptr<GenericObject> ao)
61 {
62 if (!val.isValid())
63 {
64 promise.setError(InvalidValueError);
65 return;
66 }
67
68 QI_ASSERT(ao);
69 qiLogDebug("qi.adapter") << "futureAdapter trigger";
70 TypeOfTemplate<Future>* ft1 = QI_TEMPLATE_TYPE_GET(val.type(), Future);
71 TypeOfTemplate<FutureSync>* ft2 = QI_TEMPLATE_TYPE_GET(val.type(), FutureSync);
72 qiLogDebug("qi.adapter") << "isFuture " << val.type()->infoString() << ' ' << !!ft1 << ' ' << !!ft2;
73 bool isvoid = false;
74 if (ft1)
75 isvoid = ft1->templateArgument()->kind() == TypeKind_Void;
76 else if (ft2)
77 isvoid = ft2->templateArgument()->kind() == TypeKind_Void;
78 GenericObject& gfut = *ao;
79 if (gfut.call<bool>("hasError", 0))
80 {
81 qiLogDebug("qi.adapter") << "futureAdapter: future in error";
82 std::string s = gfut.call<std::string>("error", 0);
83 qiLogDebug("qi.adapter") << "futureAdapter: got error: " << s;
84 promise.setError(s);
85 return;
86 }
87 if (gfut.call<bool>("isCanceled"))
88 {
89 qiLogDebug("qi.adapter") << "futureAdapter: future canceled";
90 promise.setCanceled();
91 return;
92 }
93 qiLogDebug("qi.adapter") << "futureAdapter: future has value";
94 AnyValue v = gfut.call<AnyValue>("value", 0);
95 // For a Future<void>, value() gave us a void*
96 if (isvoid)
97 v = AnyValue(qi::typeOf<void>());
98 qiLogDebug("qi.adapter") << (v.isValid() ? v.type()->infoString() : "<invalid AnyValue>");
99 setPromise(promise, v);
100 qiLogDebug("qi.adapter") << "Promise set";
101 }
102
103 // return a generic object pointing to the future referenced by val or null if val is not a future
104 // remember that you need a shared_ptr pointing on the genericobject so that it can work (shared_from_this)
105 inline boost::shared_ptr<GenericObject> getGenericFuture(AnyReference val, TypeKind* kind = 0)
106 {
107 if (!val.isValid())
108 {
109 qiLogDebug("qi.adapter") << "getGenericFuture: Invalid value.";
110 return boost::shared_ptr<GenericObject>();
111 }
112
113 TypeOfTemplate<Future>* ft1 = QI_TEMPLATE_TYPE_GET(val.type(), Future);
114 TypeOfTemplate<FutureSync>* ft2 = QI_TEMPLATE_TYPE_GET(val.type(), FutureSync);
115 ObjectTypeInterface* onext = NULL;
116 qiLogDebug("qi.adapter") << "isFuture " << val.type()->infoString() << ' ' << !!ft1 << ' ' << !!ft2;
117 if (ft1)
118 {
119 if (kind)
120 *kind = ft1->templateArgument()->kind();
121 onext = ft1;
122 }
123 else if (ft2)
124 {
125 if (kind)
126 *kind = ft2->templateArgument()->kind();
127 onext = ft2;
128 }
129 if (!onext)
130 return boost::shared_ptr<GenericObject>();
131 return boost::make_shared<GenericObject>(onext, val.rawValue());
132 }
133
134 // futureAdapter helper that detects and handles value of kind future
135 // return true if value was a future and was handled
136 // Takes ownership of the value if it returns true.
137 template <typename T>
138 inline bool handleFuture(AnyReference val, Promise<T> promise)
139 {
140 boost::shared_ptr<GenericObject> ao = getGenericFuture(val);
141 if (!ao)
142 return false;
143
144 // At this point, we are sure that the value holds a Future, so we take its ownership.
145 UniqueAnyReference uval{ val };
146 if (!ao->call<bool>("isValid"))
147 {
148 promise.setError(InvalidFutureError);
149 return true;
150 }
151
152 // The callback takes ownership of the value. After that, the old reference will be in a invalid
153 // state.
154 // TODO: Remove use of a shared_ptr once we can initialize captures of the lambda (C++14).
155 auto spVal = std::make_shared<UniqueAnyReference>(std::move(uval));
156 boost::function<void()> cb = [=]() mutable {
157 if (!spVal || !(*spVal)->isValid() || !ao)
158 throw std::logic_error{"Future is either invalid or has already been adapted."};
159
160 // Transfer the value to a local UniqueAnyReference.
161 // Also reset the shared ptr to break the cycle.
162 auto localRef = ka::exchange(spVal, nullptr);
163 futureAdapterGeneric<T>(**localRef, promise, ka::exchange(ao, nullptr));
164 };
165 spVal.reset();
166
167 // Careful, gfut will die at the end of this block, but it is
168 // stored in call data. So call must finish before we exit this block,
169 // and thus must be synchronous.
170 try
171 {
172 ao->call<void>("_connect", cb);
173 promise.setOnCancel(
174 qi::bindSilent(
175 static_cast<void(GenericObject::*)(const std::string&)>(
176 &GenericObject::call<void>),
177 boost::weak_ptr<GenericObject>(ao),
178 "cancel"));
179 }
180 catch (std::exception& e)
181 {
182 qiLogError("qi.object") << "future connect error " << e.what();
183 promise.setError("internal error: cannot connect returned future");
184 }
185 return true;
186 }
187
188 template <typename T>
189 inline T extractFuture(const qi::Future<qi::AnyReference>& metaFut)
190 {
191 auto val = UniqueAnyReference{ metaFut.value() };
192 if (!val->isValid())
193 throw std::runtime_error(InvalidValueError);
194
195
196 AnyValue hold;
197 if (boost::shared_ptr<GenericObject> ao = getGenericFuture(*val))
198 {
199 if (!ao->call<bool>("isValid"))
200 throw std::runtime_error(InvalidFutureError);
201
202 hold = ao->call<qi::AnyValue>("value", (int)FutureTimeout_Infinite);
203 *val = hold.asReference();
204 }
205
206 static TypeInterface* targetType;
207 QI_ONCE(targetType = typeOf<T>());
208 try
209 {
210 auto conv = val->convert(targetType);
211 if (!conv->type())
212 throw std::runtime_error(std::string("Unable to convert call result to target type: from ") +
213 val->signature(true).toPrettySignature() + " to " +
214 targetType->signature().toPrettySignature());
215 return std::move(*conv->ptr<T>(false));
216 }
217 catch(const std::exception& e)
218 {
219 throw std::runtime_error(std::string("Return argument conversion error: ") + e.what());
220 }
221 }
222
223 template <>
224 inline void extractFuture<void>(const qi::Future<qi::AnyReference>& metaFut)
225 {
226 auto val = UniqueAnyReference{ metaFut.value() };
227 if (!val->isValid())
228 throw std::runtime_error(InvalidValueError);
229
230 if (boost::shared_ptr<GenericObject> ao = getGenericFuture(*val))
231 {
232 if (!ao->call<bool>("isValid"))
233 throw std::runtime_error(InvalidFutureError);
234
235 ao->call<qi::AnyValue>("value", (int)FutureTimeout_Infinite);
236 }
237 }
238
241 template <typename T>
242 inline void setAdaptedResult(Promise<T>& promise, UniqueAnyReference ref)
243 {
244 if (!ref->isValid())
245 {
246 promise.setError(InvalidValueError);
247 return;
248 }
249
250 static TypeInterface* targetType;
251 QI_ONCE(targetType = typeOf<T>());
252 try
253 {
254 auto conv = ref->convert(targetType);
255 if (!conv->type())
256 promise.setError(std::string("Unable to convert call result to target type: from ")
257 + ref->signature(true).toPrettySignature() + " to " + targetType->signature().toPrettySignature() );
258 else
259 {
260 promise.setValue(*conv->ptr<T>(false));
261 }
262 }
263 catch(const std::exception& e)
264 {
265 promise.setError(std::string("Return argument conversion error: ") + e.what());
266 }
267 }
268
271 template <>
272 inline void setAdaptedResult<void>(Promise<void>& promise, UniqueAnyReference ref)
273 {
274 if (!ref->isValid())
275 {
276 promise.setError(InvalidValueError);
277 return;
278 }
279
280 promise.setValue(nullptr);
281 }
282
285 template <>
286 inline void setAdaptedResult<AnyReference>(Promise<AnyReference>& promise, UniqueAnyReference ref)
287 {
288 if (!ref->isValid())
289 {
290 promise.setError(InvalidValueError);
291 return;
292 }
293
294 try
295 {
296 promise.setValue(ref->clone());
297 }
298 catch(const std::exception& e)
299 {
300 promise.setError(std::string("Return argument conversion error: ") + e.what());
301 }
302 }
303
304 template <typename T>
305 inline void futureAdapter(const qi::Future<qi::AnyReference>& metaFut, qi::Promise<T> promise)
306 {
307 //error handling
308 if (metaFut.hasError()) {
309 promise.setError(metaFut.error());
310 return;
311 }
312 if (metaFut.isCanceled()) {
313 promise.setCanceled();
314 return;
315 }
316
317 auto val = metaFut.value();
318 if (handleFuture(val, promise)) // Takes ownership of the value if it returns true.
319 return;
320 setAdaptedResult(promise, UniqueAnyReference{ val });
321 }
322
323 template <typename T>
324 inline void futureAdapterVal(const qi::Future<qi::AnyValue>& metaFut, qi::Promise<T> promise)
325 {
326 //error handling
327 if (metaFut.hasError()) {
328 promise.setError(metaFut.error());
329 return;
330 }
331 if (metaFut.isCanceled()) {
332 promise.setCanceled();
333 return;
334 }
335 const AnyValue& val = metaFut.value();
336 if (!val.isValid())
337 {
338 promise.setError(InvalidValueError);
339 return;
340 }
341
342 try
343 {
344 promise.setValue(val.to<T>());
345 }
346 catch (const std::exception& e)
347 {
348 promise.setError(std::string("Return argument conversion error: ") + e.what());
349 }
350 }
351
352 template <>
353 inline void futureAdapterVal(const qi::Future<qi::AnyValue>& metaFut, qi::Promise<AnyValue> promise)
354 {
355 if (metaFut.hasError())
356 promise.setError(metaFut.error());
357 else if (metaFut.isCanceled())
358 promise.setCanceled();
359 else
360 promise.setValue(metaFut.value());
361 }
362
363 template <>
364 inline void futureAdapterVal(const qi::Future<qi::AnyValue>& metaFut, qi::Promise<void> promise)
365 {
366 if (metaFut.hasError())
367 promise.setError(metaFut.error());
368 else if (metaFut.isCanceled())
369 promise.setCanceled();
370 else
371 promise.setValue(0);
372 }
373
374 }
375 }
376
377 #endif
qi::Signature::toPrettySignature
std::string toPrettySignature() const
qi::bindSilent
std::enable_if< std::is_function< RF >::value, boost::function< RF > >::type bindSilent(AF &&fun, Arg0 &&arg0, Args &&...args)
Definition: trackable.hxx:300
qi::AnyValue
Definition: anyvalue.hpp:19
qi::detail::futureAdapter
void futureAdapter(const Future< FT > &f, Promise< PT > p, CONV converter)
Definition: future.hxx:475
qi::Future
Definition: executioncontext.hpp:20
qi::detail::setPromise
void setPromise(qi::Promise< T > &promise, const AnyValue &v)
Definition: futureadapter.hxx:20
qi::detail::AnyReferenceBase::convert
UniqueAnyReference convert(TypeInterface *targetType) const
qiLogDebug
#define qiLogDebug(...)
Definition: log.hpp:76
qi::AnyReference
Definition: anyreference.hpp:360
qi::Promise::setError
void setError(const std::string &msg)
Definition: future_fwd.hpp:862
qi::detail::setAdaptedResult< void >
void setAdaptedResult< void >(Promise< void > &promise, UniqueAnyReference ref)
Definition: futureadapter.hxx:272
QI_ASSERT
#define QI_ASSERT(expr__)
Definition: assert.hpp:27
qi::detail::futureAdapterGeneric
void futureAdapterGeneric(AnyReference val, qi::Promise< T > promise, boost::shared_ptr< GenericObject > ao)
Definition: futureadapter.hxx:59
qi::detail::extractFuture
T extractFuture(const qi::Future< qi::AnyReference > &metaFut)
Definition: futureadapter.hxx:189
qi::Future::isCanceled
bool isCanceled() const
Definition: future_fwd.hpp:339
qi::TypeKind_Void
Definition: fwd.hpp:57
qi::TypeInterface::signature
qi::Signature signature(void *storage=nullptr, bool resolveDynamic=false)
qi::detail::setAdaptedResult< AnyReference >
void setAdaptedResult< AnyReference >(Promise< AnyReference > &promise, UniqueAnyReference ref)
Definition: futureadapter.hxx:286
qi::detail::UniqueAnyReference
Definition: anyreference.hpp:444
futureadapter.hpp
qi::detail::setAdaptedResult
void setAdaptedResult(Promise< T > &promise, UniqueAnyReference ref)
Definition: futureadapter.hxx:242
qi::TypeInterface
Definition: typeinterface.hpp:129
qi::GenericObject::call
R call(const std::string &methodName, Args &&...args)
Definition: genericobject.hpp:195
qiLogError
#define qiLogError(...)
Log in error mode.
Definition: log.hpp:120
qi::detail::AnyReferenceBase::to
T to() const
Convert to anything or throw trying.
Definition: anyreference.hxx:138
qi::detail::AnyReferenceBase::signature
qi::Signature signature(bool resolveDynamic=false) const
Definition: anyreference.hxx:26
qi::GenericObject
Definition: genericobject.hpp:41
qi::detail::AnyReferenceBase::type
TypeInterface * type() const
Definition: anyreference.hpp:348
qi::detail::AnyReferenceBase::rawValue
void * rawValue() const
Definition: anyreference.hpp:351
qi::detail::futureAdapterVal
void futureAdapterVal(const qi::Future< qi::AnyValue > &metaFut, qi::Promise< T > promise)
Definition: futureadapter.hxx:324
qi::ObjectTypeInterface
Definition: typeobject.hpp:48
QI_TEMPLATE_TYPE_GET
#define QI_TEMPLATE_TYPE_GET(typeInst, templateName)
Definition: typeinterface.hpp:394
QI_ONCE
#define QI_ONCE(code)
Execute code once, parallel calls are blocked until code finishes.
Definition: atomic.hpp:420
qi::detail::getGenericFuture
boost::shared_ptr< GenericObject > getGenericFuture(AnyReference val, TypeKind *kind=0)
Definition: futureadapter.hxx:105
qi::AnyValue::asReference
AnyReference asReference() const
Definition: anyvalue.hpp:87
qi::TypeInterface::infoString
const char * infoString()
Definition: typeinterface.hpp:178
qi::detail::AnyReferenceBase::isValid
bool isValid() const
Definition: anyreference.hxx:156
qi::detail::hold
void hold(T data)
Definition: futureadapter.hpp:18
qi::Promise::setCanceled
void setCanceled()
Definition: future_fwd.hpp:869
qi::Promise::setOnCancel
void setOnCancel(boost::function< void(qi::Promise< T > &)> cancelCallback)
Definition: future_fwd.hpp:897
qi::detail::AnyReferenceBase::clone
AnyReference clone() const
Definition: anyreference.hxx:18
qi::FutureSync
Definition: future_fwd.hpp:70
qi::Future::error
const std::string & error(int msecs=FutureTimeout_Infinite) const
Definition: future_fwd.hpp:367
qi::Future::value
const ValueType & value(int msecs=FutureTimeout_Infinite) const
Return the value associated to a Future.
Definition: future_fwd.hpp:249
qi::TypeKind
TypeKind
Definition: fwd.hpp:54
qi::Promise::setValue
void setValue(const ValueType &value)
Definition: future_fwd.hpp:855
qi::Promise
Definition: future_fwd.hpp:71
qi::detail::handleFuture
bool handleFuture(AnyReference val, Promise< T > promise)
Definition: futureadapter.hxx:138
qi::FutureTimeout_Infinite
Definition: future_fwd.hpp:111
qi::detail::extractFuture< void >
void extractFuture< void >(const qi::Future< qi::AnyReference > &metaFut)
Definition: futureadapter.hxx:224
qi::Future::hasError
bool hasError(int msecs=FutureTimeout_Infinite) const
Definition: future_fwd.hpp:348