libqi-api  2.8.7.4
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
genericobject.hpp
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_GENERIC_OBJECT_HPP_
8 #define _QI_TYPE_DETAIL_GENERIC_OBJECT_HPP_
9 
10 #include <map>
11 #include <string>
12 #include <sstream>
13 
14 #include <boost/smart_ptr/enable_shared_from_this.hpp>
15 
16 #include <qi/api.hpp>
19 #include <qi/future.hpp>
20 #include <qi/signal.hpp>
21 #include <qi/type/typeobject.hpp>
22 #include <qi/objectuid.hpp>
23 
24 #ifdef _MSC_VER
25 # pragma warning( push )
26 # pragma warning( disable: 4251 )
27 #endif
28 
29 namespace qi
30 {
31 
32 /* ObjectValue
33  * static version wrapping class C: Type<C>
34  * dynamic version: Type<DynamicObject>
35  *
36  * All the methods are convenience wrappers that bounce to the ObjectTypeInterface,
37  * except Event Loop management
38  * This class has pointer semantic. Do not use directly, use AnyObject,
39  * obtained through Session, DynamicObjectBuilder or ObjectTypeBuilder.
40  */
42  : public Manageable
43  , public boost::enable_shared_from_this<GenericObject>
44 {
45 public:
46  GenericObject(ObjectTypeInterface *type, void *value, const boost::optional<ObjectUid>& maybeUid = boost::none);
47  ~GenericObject();
48  const MetaObject &metaObject();
49 
50  // Help doxygen and the header reader a bit.
51  template <typename R, typename... Args>
52  R call(const std::string& methodName, Args&&... args);
53 
54  template <typename R, typename... Args>
55  qi::Future<R> async(const std::string& methodName, Args&&... args);
56 
72  qi::Future<AnyReference> metaCall(const std::string &nameWithOptionalSignature, const GenericFunctionParameters& params, MetaCallType callType = MetaCallType_Auto, Signature returnSignature = Signature());
73 
81  qi::Future<AnyReference> metaCall(unsigned int method, const GenericFunctionParameters& params, MetaCallType callType = MetaCallType_Auto, Signature returnSignature = Signature());
83 
85  int findMethod(const std::string& name, const GenericFunctionParameters& parameters);
86 
87  void post(const std::string& eventName,
96 
97  void metaPost(unsigned int event, const GenericFunctionParameters& params);
98  void metaPost(const std::string &nameWithOptionalSignature, const GenericFunctionParameters &in);
99 
105  template <typename FUNCTOR_TYPE>
106  qi::FutureSync<SignalLink> connect(const std::string& eventName, FUNCTOR_TYPE callback,
107  MetaCallType threadingModel = MetaCallType_Direct);
108 
109 
110  qi::FutureSync<SignalLink> connect(const std::string &name, const SignalSubscriber& functor);
111 
113  qi::FutureSync<SignalLink> connect(unsigned int signal, const SignalSubscriber& subscriber);
114 
122  qi::FutureSync<SignalLink> connect(unsigned int signal, AnyObject target, unsigned int slot);
123 
125  qi::FutureSync<void> disconnect(SignalLink linkId);
126 
127  template<typename T>
128  qi::FutureSync<T> property(const std::string& name);
129 
130  template<typename T>
131  qi::FutureSync<void> setProperty(const std::string& name, const T& val);
132 
133  //Low Level Properties
134  qi::FutureSync<AnyValue> property(unsigned int id);
135  qi::FutureSync<void> setProperty(unsigned int id, const AnyValue &val);
136 
137 
138  bool isValid() { return type && value;}
140  void* value;
142 
143 private:
145  Future<AnyReference> metaCallNoUnwrap(
146  unsigned int method,
147  const GenericFunctionParameters& params,
148  const MetaCallType callType,
149  const Signature& returnSignature);
150 
152  std::string makeFindMethodErrorMessage(
153  const std::string& nameWithOptionalSignature,
154  const GenericFunctionParameters& args,
155  const int errorNo);
156 };
157 
158 namespace detail
159 {
160 
161 // Storage type used by Object<T>, and Proxy.
162 using ManagedObjectPtr = boost::shared_ptr<GenericObject>;
163 
164 }
165 
166 // C4251
167 template <typename FUNCTION_TYPE>
169  FUNCTION_TYPE callback,
170  MetaCallType model)
171 {
172  return connect(eventName,
173  SignalSubscriber(AnyFunction::from(callback), model));
174 }
175 
176 namespace detail
177 {
178 
179 template <typename T>
180 struct isFuture : boost::false_type {};
181 template <typename T>
182 struct isFuture<qi::Future<T> > : boost::true_type {};
183 template <typename T>
184 struct isFuture<qi::FutureSync<T> > : boost::true_type {};
185 
186 }
187 
188 /* Generate R GenericObject::call(methodname, args...)
189  * for all argument counts
190  * The function packs arguments in a vector<AnyReference>, computes the
191  * signature and bounce those to metaCall.
192  */
193 
194 template <typename R, typename... Args>
195 R GenericObject::call(const std::string& methodName, Args&&... args)
196 {
197  static_assert(!detail::isFuture<R>::value, "return type of call must not be a Future");
198  if (!value || !type)
199  throw std::runtime_error("Invalid GenericObject");
200  std::vector<qi::AnyReference> params = {qi::AnyReference::from(args)...};
201  qi::Future<AnyReference> fmeta = metaCall(methodName, params, MetaCallType_Direct, typeOf<R>()->signature());
202  return detail::extractFuture<R>(fmeta);
203 }
204 
208 template <typename R, typename... Args>
209 qi::Future<R> GenericObject::async(const std::string& methodName, Args&&... args)
210 {
211  std::vector<qi::AnyReference> anyArgs = {qi::AnyReference::from(args)...};
212  int methodId = findMethod(methodName, anyArgs);
213  if (methodId < 0) // in that case, the method ID is an error number
214  return makeFutureError<R>(makeFindMethodErrorMessage(methodName, anyArgs, methodId));
215  auto futureMeta = metaCallNoUnwrap(methodId, anyArgs, MetaCallType_Queued, typeOf<R>()->signature());
216  qi::Promise<R> result;
217  qi::adaptFutureUnwrap(futureMeta, result);
218  return result.future();
219 }
220 
221 template<typename T>
223 {
224  int pid = metaObject().propertyId(name);
225  if (pid < 0)
226  {
227  std::ostringstream ss;
228  ss << "property \"" << name << "\" was not found";
229  return makeFutureError<T>(ss.str());
230  }
232  qi::Promise<T> p;
233  f.connect(boost::bind(&detail::futureAdapterVal<T>,_1, p),
235  return p.future();
236 }
237 
238 template<typename T>
239 qi::FutureSync<void> GenericObject::setProperty(const std::string& name, const T& val)
240 {
241  int pid = metaObject().propertyId(name);
242  if (pid < 0)
243  {
244  std::ostringstream ss;
245  ss << "property \"" << name << "\" was not found";
246  return makeFutureError<void>(ss.str());
247  }
248  return setProperty(pid, AnyValue::from(val));
249 }
250 
251 /* An AnyObject is actually of a Dynamic type: The underlying TypeInterface*
252  * is not allways the same.
253  * Override backend shared_ptr<GenericObject>
254 */
255 template<>
256 class QI_API TypeImpl<boost::shared_ptr<GenericObject>> :
257  public DynamicTypeInterface
258 {
259 public:
260  AnyReference get(void* storage) override
261  {
262  detail::ManagedObjectPtr* val = (detail::ManagedObjectPtr*)ptrFromStorage(&storage);
263  AnyReference result;
264  if (!*val)
265  {
266  return AnyReference();
267  }
268  return AnyReference((*val)->type, (*val)->value);
269  }
270 
271  void set(void** storage, AnyReference source) override
272  {
273  qiLogCategory("qitype.object");
274  detail::ManagedObjectPtr* val = (detail::ManagedObjectPtr*)ptrFromStorage(storage);
275 
276  if (!source.type())
277  throw std::runtime_error("cannot set object from an invalid value");
278 
279  if (source.type()->info() == info())
280  { // source is objectptr
282  if (!*src)
283  qiLogWarning() << "NULL Object";
284  *val = *src;
285  }
286  else if (source.kind() == TypeKind_Dynamic)
287  { // try to dereference dynamic type in case it contains an object
288  auto content = source.content();
289  if (!content.isValid())
290  throw std::runtime_error("cannot set object from an invalid dynamic value");
291  set(storage, source.content());
292  }
293  else if (source.kind() == TypeKind_Object)
294  { // wrap object in objectptr: we do not keep it alive,
295  // but source type offers no tracking capability
296  detail::ManagedObjectPtr op(new GenericObject(static_cast<ObjectTypeInterface*>(source.type()), source.rawValue()));
297  *val = op;
298  }
299  else if (source.kind() == TypeKind_Pointer)
300  {
301  PointerTypeInterface* ptype = static_cast<PointerTypeInterface*>(source.type());
302  // FIXME: find a way!
303  if (ptype->pointerKind() == PointerTypeInterface::Shared)
304  qiLogInfo() << "Object will *not* track original shared pointer";
305  set(storage, *source);
306  }
307  else if (source.kind() == TypeKind_Optional)
308  {
309  set(storage, source.content());
310  }
311  else
312  throw std::runtime_error((std::string)"Cannot assign non-object " + source.type()->infoString() + " to Object");
313  }
314 
315  using Methods = DefaultTypeImplMethods<detail::ManagedObjectPtr, TypeByPointerPOD<detail::ManagedObjectPtr>>;
316  _QI_BOUNCE_TYPE_METHODS(Methods);
317 };
318 
319 }
320 
321 #ifdef _MSC_VER
322 # pragma warning( pop )
323 #endif
324 
325 #endif
boost::shared_ptr< GenericObject > ManagedObjectPtr
qi::Future< R > async(const std::string &methodName, Args &&...args)
ObjectUid uid
Uid of "value".
void connect(const AF &fun, FutureCallbackType type=FutureCallbackType_Auto)
Definition: future_fwd.hpp:545
#define QI_API
Definition: api.hpp:33
qi::FutureSync< SignalLink > connect(const std::string &eventName, FUNCTOR_TYPE callback, MetaCallType threadingModel=MetaCallType_Direct)
qi::Future< AnyReference > metaCall(ExecutionContext *ec, ObjectThreadingModel objectThreadingModel, MetaCallType methodThreadingModel, MetaCallType callType, AnyObject manageable, unsigned int methodId, AnyFunction func, const GenericFunctionParameters &params, bool noCloneFirst=false, unsigned int callerId=0, qi::os::timeval postTimestamp=qi::os::timeval())
#define qiLogCategory(Cat)
Definition: log.hpp:53
int propertyId(const std::string &name) const
static AnyValue from(const T &r)
Definition: anyvalue.hpp:94
Honor the default behavior.
Definition: typeobject.hpp:26
dll import/export and compiler message
int findMethod(const std::string &name, const GenericFunctionParameters &parameters)
Find method named name callable with arguments parameters.
#define qiLogWarning(...)
Log in warning mode.
Definition: log.hpp:109
Future< T > future() const
Get a future linked to this promise. Can be called multiple times.
Definition: future_fwd.hpp:881
R call(const std::string &methodName, Args &&...args)
Force a synchronous call.
Definition: typeobject.hpp:28
#define qiLogInfo(...)
Log in info mode.
Definition: log.hpp:98
#define _QI_BOUNCE_TYPE_METHODS(Bounce)
Implement all methods of Type as bouncers to Bouncer.
Definition: typeimpl.hxx:273
qi::FutureSync< void > setProperty(const std::string &name, const T &val)
auto async(F &&callback) -> decltype(asyncDelay(std::forward< F >(callback), qi::Duration(0)))
Definition: async.hpp:53
ObjectTypeInterface * type
qi::FutureSync< T > property(const std::string &name)
MetaCallType
Definition: typeobject.hpp:24
const MetaObject & metaObject()
T src(const std::atomic< T > &x)
Definition: atomic.hpp:318
static AnyFunction from(F &&func)
static AnyReference from(const T &ref)
qi::uint64_t SignalLink
Definition: signal.hpp:36
qi::Future< AnyReference > metaCall(const std::string &nameWithOptionalSignature, const GenericFunctionParameters &params, MetaCallType callType=MetaCallType_Auto, Signature returnSignature=Signature())
Force an asynchronous call in an other thread.
Definition: typeobject.hpp:30
std::enable_if< std::is_function< RF >::value, boost::function< RF > >::type bind(AF &&fun, Arg0 &&arg0, Args &&...args)
Definition: trackable.hxx:308
Description of the signals and methods accessible on an ObjectTypeInterface.
Definition: metaobject.hpp:25
void adaptFutureUnwrap(Future< AnyReference > &f, Promise< R > &p)
Feed a promise from a generic future which may be unwrapped if it contains itself a future...
Definition: future.hxx:528