libzypp  17.35.14
asyncresult.h
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 ----------------------------------------------------------------------/
9 *
10 * This file contains private API, this might break at any time between releases.
11 * You have been warned!
12 *
13 */
14 #ifndef ZYPPNG_MONADIC_ASYNCRESULT_H_INCLUDED
15 #define ZYPPNG_MONADIC_ASYNCRESULT_H_INCLUDED
16 
17 #include <zypp-core/zyppng/meta/TypeTraits>
18 #include <zypp-core/zyppng/meta/FunctionTraits>
19 #include <zypp-core/zyppng/meta/Functional>
20 #include <zypp-core/zyppng/async/AsyncOp>
21 
22 namespace zyppng {
23 
24 
25  namespace detail {
26 
27  template< typename Callback, typename MsgType, typename = std::void_t<> >
28  struct is_future_monad_cb : public std::false_type{};
29 
30  template< typename Callback, typename MsgType >
31  struct is_future_monad_cb<Callback, MsgType,
32  std::void_t<
33  std::enable_if_t< is_async_op_v<Callback> >,
34  decltype ( std::declval<remove_smart_ptr_t<Callback>>()( std::declval<MsgType>()) )//check if the callback has a operator() member with the correct signature
35  >
36  > : public std::true_type{};
37 
42  template< typename Callback, typename MsgType >
44 
45  template< typename Callback, typename MsgType, typename = std::void_t<> >
46  struct is_sync_monad_cb : public std::false_type{};
47 
48  template< typename Callback, typename MsgType >
49  struct is_sync_monad_cb<Callback, MsgType
50  , std::void_t<
51  std::enable_if_t< !is_async_op_v<Callback> >,
52  std::enable_if_t< !std::is_same_v< void, decltype ( std::declval<Callback>()(std::declval<MsgType>())) > > > //check if the callback has the correct signature: cb( MsgType )
53  > : public std::true_type{};
54 
58  template< typename Callback, typename MsgType, typename = std::void_t<> >
60 
61 
62  template <typename Callback, typename Arg>
64 
65 
66  template< typename Callback, typename MsgType, typename = std::void_t<> >
67  struct is_sync_monad_cb_with_async_res : public std::false_type{};
68 
69  template< typename Callback, typename MsgType >
70  struct is_sync_monad_cb_with_async_res<Callback, MsgType
71  , std::void_t<
72  std::enable_if_t< is_sync_monad_cb<Callback, MsgType>::value >,
73  std::enable_if_t< callback_returns_async_op<Callback, MsgType>::value >>
74  > : public std::true_type{};
75 
76  template< typename Callback, typename MsgType, typename = std::void_t<> >
77  struct is_sync_monad_cb_with_sync_res : public std::false_type{};
78 
79  template< typename Callback, typename MsgType >
80  struct is_sync_monad_cb_with_sync_res<Callback, MsgType
81  , std::void_t<
82  std::enable_if_t< is_sync_monad_cb<Callback, MsgType>::value >,
83  std::enable_if_t< !callback_returns_async_op<Callback, MsgType>::value > >
84  > : public std::true_type{};
85 
89  template <typename Callback, typename Arg>
91 
95  template <typename Callback, typename Arg>
97 
98 
116  //template <typename Prev, typename AOp, typename Enable = void>
117  //struct AsyncResult;
118 
119  template <typename T>
120  struct is_nested_async : public std::false_type {};
121 
122  template <typename T>
123  struct is_nested_async<AsyncOpRef<AsyncOpRef<T>>> : public std::true_type {};
124 
125  template <typename T>
127 
128 
129  // case 1: connect async result to async callback
130  template <typename PrevRes, typename CallbackOp, typename AOpRes = typename CallbackOp::value_type >
131  struct AsyncToAsyncResult : public zyppng::AsyncOp< AOpRes > {
132 
133  static_assert( !is_async_op_v<AOpRes>, "A AsyncResult can never return a async value" );
134  static_assert( !is_async_op_v<PrevRes>, "A incoming value can never be a async value" );
135 
136  AsyncToAsyncResult ( AsyncOpRef<PrevRes> && prevTask, std::shared_ptr<CallbackOp> &&cb )
137  : _prevTask( std::move(prevTask) )
138  , _myTask( std::move(cb) ) {
139  connect();
140  }
141 
142  AsyncToAsyncResult ( const AsyncToAsyncResult &other ) = delete;
143  AsyncToAsyncResult& operator= ( const AsyncToAsyncResult &other ) = delete;
144 
145  AsyncToAsyncResult ( AsyncToAsyncResult &&other ) = delete;
146  AsyncToAsyncResult& operator= ( AsyncToAsyncResult &&other ) = delete;
147 
148  virtual ~AsyncToAsyncResult() {}
149 
150  void connect () {
151  //not using a lambda here on purpose, binding this into a lambda that is stored in the _prev
152  //object causes segfaults on gcc when the lambda is cleaned up with the _prev objects signal instance
153  _prevTask->onReady( std::bind( &AsyncToAsyncResult::readyWasCalled, this, std::placeholders::_1) );
154  _myTask->onReady( [this] ( AOpRes && res ){
155  this->setReady( std::move( res ) );
156  });
157  }
158 
159  private:
160  // we need to store the passed argument in our stack, otherwise we
161  // run into memory issues if the argument is moved out of the _prevTask object
162  // so even though we std::move() the argument further we need to copy it here
163  void readyWasCalled ( PrevRes res ) {
164  //MIL << "Setting ready: " << typeid(this) << std::endl;
165  if ( _prevTask ) {
166  //dumpInfo();
167  _prevTask.reset();
168  }
169 
170  _myTask->operator()(std::move(res));
171  }
172 
174  std::shared_ptr<CallbackOp> _myTask;
175  };
176 
177  template <typename PrevRes, typename Callback, typename Enable = void>
179 
180  // case 2: connect async result to sync callback returning a sync value
181  template <typename PrevRes, typename Callback>
182  struct AsyncToSyncResult<PrevRes, Callback, std::enable_if_t< is_sync_monad_cb_with_sync_res_v<Callback, PrevRes> >>
183  : public zyppng::AsyncOp< typename std::invoke_result_t<Callback, PrevRes> > {
184 
185  using value_type = std::invoke_result_t<Callback, PrevRes>;
186  static_assert( !is_async_op_v<value_type>, "A AsyncResult can never return a async value" );
187  static_assert( !is_async_op_v<PrevRes>, "A incoming value can never be a async value" );
188 
189  template <typename CBType = Callback>
190  AsyncToSyncResult ( AsyncOpRef<PrevRes> && prevTask, CBType &&cb )
191  : _prevTask( std::move(prevTask) )
192  , _myTask( std::forward<CBType>(cb) ) {
193  connect();
194  }
195 
196  AsyncToSyncResult ( const AsyncToSyncResult &other ) = delete;
197  AsyncToSyncResult& operator= ( const AsyncToSyncResult &other ) = delete;
198 
199  AsyncToSyncResult ( AsyncToSyncResult &&other ) = delete;
200  AsyncToSyncResult& operator= ( AsyncToSyncResult &&other ) = delete;
201 
202  virtual ~AsyncToSyncResult() {}
203 
204  void connect () {
205  //not using a lambda here on purpose, binding this into a lambda that is stored in the _prev
206  //object causes segfaults on gcc when the lambda is cleaned up with the _prev objects signal instance
207  _prevTask->onReady( std::bind( &AsyncToSyncResult::readyWasCalled, this, std::placeholders::_1) );
208  }
209 
210  private:
211  // we need to store the passed argument in our stack, otherwise we
212  // run into memory issues if the argument is moved out of the _prevTask object
213  // so even though we std::move() the argument further we need to copy it here
214  void readyWasCalled ( PrevRes res ) {
215  //MIL << "Setting ready: " << typeid(this) << std::endl;
216  if ( _prevTask ) {
217  _prevTask.reset();
218  }
219 
220  this->setReady( std::invoke( _myTask, std::move( res )) );
221  }
223  Callback _myTask;
224  };
225 
226 
227  // case 3: connect async result to sync callback returning a async value
228  template <typename PrevRes, typename Callback>
229  struct AsyncToSyncResult<PrevRes, Callback, std::enable_if_t< is_sync_monad_cb_with_async_res_v<Callback, PrevRes> >>
230  : public zyppng::AsyncOp< typename remove_smart_ptr_t<std::invoke_result_t<Callback, PrevRes>>::value_type> {
231 
233  static_assert(!is_async_op_v< value_type >, "A AsyncResult can never return a async value" );
234 
235  template <typename CBType = Callback>
236  AsyncToSyncResult ( AsyncOpRef<PrevRes> && prevTask, CBType &&cb )
237  : _prevTask( std::move(prevTask) )
238  , _myTask( std::forward<CBType>(cb) ) {
239  connect();
240  }
241 
242  AsyncToSyncResult ( const AsyncToSyncResult &other ) = delete;
243  AsyncToSyncResult& operator= ( const AsyncToSyncResult &other ) = delete;
244 
245  AsyncToSyncResult ( AsyncToSyncResult &&other ) = delete;
246  AsyncToSyncResult& operator= ( AsyncToSyncResult &&other ) = delete;
247 
248  virtual ~AsyncToSyncResult() {}
249 
250  void connect () {
251  //not using a lambda here on purpose, binding this into a lambda that is stored in the _prev
252  //object causes segfaults on gcc when the lambda is cleaned up with the _prev objects signal instance
253  _prevTask->onReady( std::bind( &AsyncToSyncResult::readyWasCalled, this, std::placeholders::_1) );
254  }
255 
256  private:
257  // we need to store the passed argument in our stack, otherwise we
258  // run into memory issues if the argument is moved out of the _prevTask object
259  // so even though we std::move() the argument further we need to copy it here
260  void readyWasCalled ( PrevRes res ) {
261 
262  //MIL << "Setting ready "<<this<<" step 1: " << typeid(this) << std::endl;
263  if ( _prevTask ) {
264  _prevTask.reset();
265  }
266 
267  _asyncResult = std::invoke( _myTask, std::move(res) );
268  _asyncResult->onReady( [this]( value_type &&val ) {
269  //MIL << "Setting ready "<<this<<" step 2: " << typeid(this) << std::endl;
270  this->setReady( std::move(val) );
271  });
272  }
274  Callback _myTask;
276  };
277  }
278 
279  namespace operators {
280 
281  template< typename PrevOp , typename Callback,
284  auto operator| ( std::shared_ptr<PrevOp> &&in, std::shared_ptr<Callback>&& c ) -> AsyncOpRef<typename Callback::value_type>
285  {
286  using PrevOpRes = typename PrevOp::value_type;
287  return std::make_shared<detail::AsyncToAsyncResult<PrevOpRes, Callback>>( std::move(in), std::move(c) );
288  }
289 
290  template< typename PrevOp , typename Callback,
293  >
294  auto operator| ( std::shared_ptr<PrevOp> &&in, Callback &&c )
295  {
296  using PrevOpRes = typename PrevOp::value_type;
297  using CbType = std::remove_reference_t<Callback>;
299  if ( in->isReady() )
300  return AsyncOpRef<Ret>( std::invoke( std::forward<Callback>(c), std::move(in->get()) ) );
301  return AsyncOpRef<Ret>( new detail::AsyncToSyncResult<PrevOpRes, CbType>( std::move(in), std::forward<Callback>(c) ) );
302  }
303 
304  template< typename PrevOp , typename Callback,
307  >
308  auto operator| ( std::shared_ptr<PrevOp> &&in, Callback &&c )
309  {
310  using PrevOpRes = typename PrevOp::value_type;
311  using CbType = std::remove_reference_t<Callback>;
313 
314  if ( in->isReady() )
315  return makeReadyResult( std::invoke( std::forward<Callback>(c), std::move(in->get()) ) );
316  return AsyncOpRef<Ret>( new detail::AsyncToSyncResult<PrevOpRes, CbType>( std::move(in), std::forward<Callback>(c) ) );
317  }
318 
319  template< typename PrevRes , typename CallbackOp,
323  {
324  // sync message to async callback case
325  std::forward<CallbackOp>(c)->operator()( std::forward<PrevRes>(in) );
326  return c;
327  }
328 
329  // sync to sync callback case, we do not need to differentiate between a callback with a async result or a normal one
330  // in both cases we simply can use the return type of the callback function
331  template< typename SyncRes
332  , typename Callback
335  >
336  auto operator| ( SyncRes &&in, Callback &&c )
337  {
338  return std::forward<Callback>(c)(std::forward<SyncRes>(in));
339  }
340  }
341 }
342 
343 #endif
auto operator|(std::shared_ptr< PrevOp > &&in, std::shared_ptr< Callback > &&c) -> AsyncOpRef< typename Callback::value_type >
Definition: asyncresult.h:284
typename make_void< Ts... >::type void_t
Definition: type_traits.h:12
typename remove_reference< T >::type remove_reference_t
Definition: TypeTraits.h:48
Definition: Arch.h:363
void setReady(value_type &&val)
Definition: asyncop.h:183
std::enable_if< std::is_member_pointer< typename std::decay< Functor >::type >::value, typename std::result_of< Functor &&(Args &&...)>::type >::type invoke(Functor &&f, Args &&... args)
Definition: functional.h:32
constexpr bool is_nested_async_v
Definition: asyncresult.h:126
typename enable_if< B, T >::type enable_if_t
Definition: TypeTraits.h:45
AsyncToAsyncResult & operator=(const AsyncToAsyncResult &other)=delete
constexpr bool is_future_monad_cb_v
Definition: asyncresult.h:43
AsyncOpRef< PrevRes > _prevTask
Definition: asyncresult.h:173
std::conditional_t< isAsync, AsyncOpRef< T >, T > makeReadyResult(T &&result)
Definition: asyncop.h:297
std::shared_ptr< AsyncOp< T > > AsyncOpRef
Definition: asyncop.h:255
constexpr bool is_sync_monad_cb_with_async_res_v
Definition: asyncresult.h:90
std::shared_ptr< CallbackOp > _myTask
Definition: asyncresult.h:174
typename remove_smart_ptr_t< std::invoke_result_t< Callback, PrevRes > >::value_type value_type
Definition: asyncresult.h:232
constexpr bool is_sync_monad_cb_v
Definition: asyncresult.h:59
typename remove_smart_ptr< T >::type remove_smart_ptr_t
Definition: type_traits.h:128
AsyncToAsyncResult(AsyncOpRef< PrevRes > &&prevTask, std::shared_ptr< CallbackOp > &&cb)
Definition: asyncresult.h:136
constexpr bool is_sync_monad_cb_with_sync_res_v
Definition: asyncresult.h:96