callback.hpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984
  1. #ifndef GI_CALLBACK_HPP
  2. #define GI_CALLBACK_HPP
  3. #include "base.hpp"
  4. #include "exception.hpp"
  5. #include "wrap.hpp"
  6. #include <functional>
  7. #include <tuple>
  8. namespace gi
  9. {
  10. namespace detail
  11. {
  12. inline std::string
  13. exception_desc(const std::exception &e)
  14. {
  15. auto desc = e.what();
  16. return desc ? desc : typeid(e).name();
  17. }
  18. inline std::string
  19. exception_desc(...)
  20. {
  21. return "[unknown]";
  22. }
  23. #if GI_CONFIG_EXCEPTIONS
  24. inline ::GError **
  25. find_gerror(bool &has_gerror)
  26. {
  27. has_gerror = false;
  28. return nullptr;
  29. }
  30. inline ::GError **
  31. find_gerror(bool &has_gerror, ::GError **error)
  32. {
  33. has_gerror = true;
  34. return error;
  35. }
  36. template<typename CT, typename... CType>
  37. inline ::GError **
  38. find_gerror(bool &has_gerror, CT /*arg*/, CType... args)
  39. {
  40. return find_gerror(has_gerror, args...);
  41. }
  42. inline ::GError *
  43. exception_error(const repository::GLib::Error &exc)
  44. {
  45. return g_error_copy(exc.gobj_());
  46. }
  47. inline ::GError *
  48. exception_error(const repository::GLib::Error_Ref &exc)
  49. {
  50. return g_error_copy(exc.gobj_());
  51. }
  52. template<typename E>
  53. inline ::GError *
  54. exception_error(const E &exc)
  55. {
  56. static auto quark = g_quark_from_static_string("gi-error-quark");
  57. return g_error_new(quark, 0, "%s", exception_desc(exc).c_str());
  58. }
  59. template<bool SILENT = FALSE, typename E, typename... CType>
  60. void
  61. report_exception(const E &exc, CType... args)
  62. {
  63. // see if we can really report error somewhere
  64. bool has_gerror = false;
  65. GError **error = find_gerror(has_gerror, args...);
  66. if (has_gerror) {
  67. g_return_if_fail(error == NULL || *error == NULL);
  68. if (error)
  69. *error = exception_error(exc);
  70. // if caller does not need/want error, exception disappears here
  71. } else {
  72. // simply report the hard and simple way
  73. // otherwise catch internally if something else/more is desired
  74. if (!SILENT) {
  75. auto msg = std::string("handler exception; ") + exception_desc(exc);
  76. g_critical("%s", msg.c_str());
  77. }
  78. }
  79. }
  80. #endif
  81. // (re)float only applies to GObject
  82. template<typename CppType, typename Transfer,
  83. typename std::enable_if<!traits::is_object<CppType>::value>::type * =
  84. nullptr>
  85. auto
  86. unwrap_maybe_float(CppType &&v, const Transfer &t)
  87. {
  88. return unwrap(std::forward<CppType>(v), t);
  89. }
  90. // (re) float only for transfer none/floating
  91. template<typename CppType,
  92. typename std::enable_if<traits::is_object<CppType>::value>::type * =
  93. nullptr>
  94. inline typename traits::ctype<CppType>::type
  95. unwrap_maybe_float(CppType &&v, const transfer_full_t &t)
  96. {
  97. return unwrap(std::forward<CppType>(v), t);
  98. }
  99. template<typename CppType,
  100. typename std::enable_if<traits::is_object<CppType>::value>::type * =
  101. nullptr>
  102. inline typename traits::ctype<CppType>::type
  103. unwrap_maybe_float(CppType &&v, const transfer_none_t &)
  104. {
  105. // expected called with r-value
  106. static_assert(!std::is_reference<CppType>::value, "");
  107. // steal/take from wrapper
  108. auto result = (typename traits::ctype<CppType>::type)v.release_();
  109. // the following is essentially a bit of a hack as mentioned in
  110. // https://bugzilla.gnome.org/show_bug.cgi?id=693393)
  111. // that is, we are about to return an object to C (from binding/callback)
  112. // and this should be done with none transfer
  113. // this none may actually mean floating (e.g. a factory-like callback)
  114. // but no way to know from annotations
  115. // so if at runtime the wrapper actually holds the only reference,
  116. // then it is about to be destroyed (when wrapper goes away)
  117. // *before* the object can make it back to caller
  118. // so turn that ref into a floating one (as only that makes sense)
  119. // if it is not the only ref, it is kept alive elsewhere
  120. // (as typically so for a "getter" callback)
  121. // so it is really treated as none
  122. auto obj = (GObject *)result;
  123. // theoretically not MT safe, but if == 1, only 1 thread should be involved
  124. if (obj->ref_count == 1) {
  125. g_object_force_floating(obj);
  126. } else {
  127. // otherwise unref as wrapper would have
  128. g_object_unref(obj);
  129. }
  130. return result;
  131. }
  132. template<typename T>
  133. constexpr T
  134. unconst(T t)
  135. {
  136. return t;
  137. }
  138. inline char *
  139. unconst(const char *t)
  140. {
  141. return (char *)t;
  142. }
  143. // helper types to provide additional argument info beyond Transfer
  144. template<std::size_t... index>
  145. struct args_index
  146. {
  147. static constexpr auto value = std::make_tuple(index...);
  148. using value_type = decltype(value);
  149. };
  150. template<typename Transfer, bool _inout, typename CustomTraits = void,
  151. typename ArgsIndex = args_index<>>
  152. struct arg_info
  153. {
  154. using transfer_type = Transfer;
  155. static constexpr bool inout = _inout;
  156. // tuple of index; used to selects the C arguments (to assemble C++ argument)
  157. using args_type = ArgsIndex;
  158. // additional info as used by corresponding cb_arg_handler
  159. using custom_type = CustomTraits;
  160. };
  161. // access above info by forwarding types
  162. template<typename T, typename Enable = void>
  163. struct arg_traits
  164. {
  165. using transfer_type = typename T::transfer_type;
  166. static constexpr bool inout = T::inout;
  167. using args_type = typename T::args_type;
  168. using custom_type = typename T::custom_type;
  169. };
  170. // legacy case; only transfer type
  171. template<typename T>
  172. struct arg_traits<T,
  173. typename std::enable_if<std::is_base_of<transfer_t, T>::value>::type>
  174. {
  175. using transfer_type = T;
  176. static constexpr bool inout = false;
  177. using args_type = args_index<>;
  178. using custom_type = void;
  179. };
  180. // IndexTuple is essentially an args_index<...>
  181. template<typename IndexTuple, std::size_t... Index, typename F,
  182. typename ArgTuple>
  183. decltype(auto)
  184. apply_with_args(std::index_sequence<Index...>, F &&f, ArgTuple &&args)
  185. {
  186. return f(std::get<std::get<Index>(IndexTuple::value)>(args)...);
  187. }
  188. template<typename IndexTuple, typename F, typename... Args>
  189. decltype(auto)
  190. apply_with_args(F &&f, Args &&...args)
  191. {
  192. return apply_with_args<IndexTuple>(
  193. std::make_index_sequence<
  194. std::tuple_size<typename IndexTuple::value_type>::value>(),
  195. std::forward<F>(f), std::forward_as_tuple(args...));
  196. }
  197. // a simple callback has no (need for) args_index
  198. template<typename T>
  199. struct is_simple_cb : public std::true_type
  200. {};
  201. template<typename Transfer, typename... Transfers>
  202. struct is_simple_cb<std::tuple<Transfer, Transfers...>>
  203. {
  204. static constexpr bool value =
  205. std::tuple_size<
  206. typename arg_traits<Transfer>::args_type::value_type>::value == 0 ||
  207. (sizeof...(Transfers) > 0 &&
  208. is_simple_cb<std::tuple<Transfers...>>::value);
  209. };
  210. template<typename T, typename CT = void>
  211. struct map_cpp_function;
  212. // handles all calls C -> C++ (callbacks, virtual method calls)
  213. // restrictions though on types supported (enforced by code generation)
  214. template<typename T, typename RetTransfer, typename ArgTransfers,
  215. typename CT = typename map_cpp_function<T>::type,
  216. bool SIMPLE = is_simple_cb<ArgTransfers>::value>
  217. struct transform_caller;
  218. // helper used below that provides pre-call and post-call steps
  219. // to handle each argument's conversion to and from C++
  220. // in so-called (most) simple cases, there is one-to-one mapping between
  221. // C and C++ arguments and C++ argument type that allows to deduce context
  222. // (in particular, no callbacks or sized array)
  223. // as such, proper steps can be obtained by specialization on Cpp argument type
  224. template<typename CppArg, typename Enable = void>
  225. struct cb_arg_handler;
  226. // in simple cases, C signature can be derived from C++ signature
  227. template<typename T, typename CT>
  228. struct map_cpp_function
  229. {
  230. using type = CT;
  231. };
  232. template<typename R, typename... Args>
  233. struct map_cpp_function<R(Args...), void>
  234. {
  235. using type = typename traits::ctype<R>::type(
  236. typename cb_arg_handler<Args>::c_type...);
  237. };
  238. // signature used in virtual method handling
  239. template<typename R, typename... Args>
  240. struct map_cpp_function<R (*)(Args...), void>
  241. {
  242. using type = typename traits::ctype<R>::type(
  243. typename cb_arg_handler<Args>::c_type...);
  244. };
  245. // NOTE function type R(const A) is identical to R(A)
  246. // so no deduced Args below will retain const (if such)
  247. // in simple cases, *Transfer* is simply a transfer type
  248. // but it may also be a more elaborate argument trait
  249. template<typename R, typename... Args, typename RetTransfer,
  250. typename... Transfers, typename CR, typename... CArgs, bool SIMPLE>
  251. struct transform_caller<R(Args...), RetTransfer, std::tuple<Transfers...>,
  252. CR(CArgs...), SIMPLE>
  253. {
  254. static_assert(sizeof...(Args) == sizeof...(Transfers), "");
  255. static_assert(!SIMPLE || sizeof...(Args) == sizeof...(CArgs), "");
  256. typedef transform_caller self_type;
  257. typedef R (*caller_type)(Args &&..., void *d);
  258. private:
  259. static R do_call(Args &&...args, caller_type func, void *d)
  260. {
  261. return func(std::forward<Args>(args)..., d);
  262. }
  263. // helper that provides context for pack expansion below
  264. static void dummy_call(...){};
  265. template<typename T>
  266. static auto _tt(const T &)
  267. {
  268. return typename arg_traits<T>::transfer_type();
  269. }
  270. // non-void return
  271. template<typename T, std::size_t... Index,
  272. typename std::enable_if<SIMPLE && !std::is_void<T>::value>::type * =
  273. nullptr>
  274. static CR _wrapper(
  275. CArgs... args, caller_type func, void *d, std::index_sequence<Index...>)
  276. {
  277. std::tuple<cb_arg_handler<Args>...> handlers;
  278. auto ret = do_call(
  279. std::get<Index>(handlers).arg(args, _tt(Transfers()), Transfers())...,
  280. func, d);
  281. dummy_call((std::get<Index>(handlers).post(args, _tt(Transfers())), 0)...);
  282. return unconst(unwrap_maybe_float(std::move(ret), RetTransfer()));
  283. }
  284. // void return
  285. template<typename T, std::size_t... Index,
  286. typename std::enable_if<SIMPLE && std::is_void<T>::value>::type * =
  287. nullptr>
  288. static CR _wrapper(
  289. CArgs... args, caller_type func, void *d, std::index_sequence<Index...>)
  290. {
  291. std::tuple<cb_arg_handler<Args>...> handlers;
  292. do_call(
  293. std::get<Index>(handlers).arg(args, _tt(Transfers()), Transfers())...,
  294. func, d);
  295. dummy_call((std::get<Index>(handlers).post(args, _tt(Transfers())), 0)...);
  296. }
  297. // complex; non-void return
  298. template<typename T, std::size_t... Index,
  299. typename std::enable_if<!SIMPLE && !std::is_void<T>::value>::type * =
  300. nullptr>
  301. static CR _wrapper(
  302. CArgs... args, caller_type func, void *d, std::index_sequence<Index...>)
  303. {
  304. std::tuple<cb_arg_handler<Args>...> handlers;
  305. auto ret = do_call(
  306. apply_with_args<typename arg_traits<Transfers>::args_type>(
  307. [&handlers](auto... selargs) mutable -> decltype(auto) {
  308. return std::get<Index>(handlers).arg(selargs...,
  309. typename arg_traits<Transfers>::transfer_type(), Transfers());
  310. },
  311. args...)...,
  312. func, d);
  313. dummy_call((apply_with_args<typename arg_traits<Transfers>::args_type>(
  314. [&handlers](auto... selargs) mutable -> decltype(auto) {
  315. return std::get<Index>(handlers).post(selargs...,
  316. typename arg_traits<Transfers>::transfer_type());
  317. },
  318. args...),
  319. 0)...);
  320. return unconst(unwrap_maybe_float(std::move(ret), RetTransfer()));
  321. }
  322. // complex; void return
  323. template<typename T, std::size_t... Index,
  324. typename std::enable_if<!SIMPLE && std::is_void<T>::value>::type * =
  325. nullptr>
  326. static CR _wrapper(
  327. CArgs... args, caller_type func, void *d, std::index_sequence<Index...>)
  328. {
  329. std::tuple<cb_arg_handler<Args>...> handlers;
  330. do_call(apply_with_args<typename arg_traits<Transfers>::args_type>(
  331. [&handlers](auto... selargs) mutable -> decltype(auto) {
  332. return std::get<Index>(handlers).arg(selargs...,
  333. typename arg_traits<Transfers>::transfer_type(),
  334. Transfers());
  335. },
  336. args...)...,
  337. func, d);
  338. dummy_call((apply_with_args<typename arg_traits<Transfers>::args_type>(
  339. [&handlers](auto... selargs) mutable -> decltype(auto) {
  340. return std::get<Index>(handlers).post(selargs...,
  341. typename arg_traits<Transfers>::transfer_type());
  342. },
  343. args...),
  344. 0)...);
  345. }
  346. public:
  347. static CR wrapper(CArgs... args, caller_type func, void *d)
  348. {
  349. // exceptions should not escape into plain C
  350. #if GI_CONFIG_EXCEPTIONS
  351. try {
  352. #endif
  353. return self_type::template _wrapper<R>(
  354. args..., func, d, std::make_index_sequence<sizeof...(Args)>());
  355. #if GI_CONFIG_EXCEPTIONS
  356. } catch (const repository::GLib::Error &exc) {
  357. report_exception(exc, args...);
  358. } catch (const repository::GLib::Error_Ref &exc) {
  359. report_exception(exc, args...);
  360. } catch (const std::exception &exc) {
  361. report_exception(exc, args...);
  362. } catch (...) {
  363. report_exception(nullptr, args...);
  364. }
  365. return typename traits::ctype<R>::type();
  366. #endif
  367. }
  368. };
  369. // minor helper traits used below
  370. namespace _traits
  371. {
  372. template<typename T>
  373. struct remove_all_pointers
  374. {
  375. using type = T;
  376. };
  377. template<typename T>
  378. struct remove_all_pointers<T *>
  379. {
  380. using type = typename remove_all_pointers<T>::type;
  381. };
  382. template<typename T>
  383. struct remove_all_pointers<T *const>
  384. {
  385. using type = typename remove_all_pointers<T>::type;
  386. };
  387. template<typename T>
  388. using is_basic_or_void = typename std::conditional<traits::is_basic<T>::value ||
  389. std::is_void<T>::value,
  390. std::true_type, std::false_type>::type;
  391. template<typename T>
  392. using is_basic_argument = typename std::conditional<
  393. is_basic_or_void<typename std::remove_cv<
  394. typename remove_all_pointers<T>::type>::type>::value,
  395. std::true_type, std::false_type>::type;
  396. template<typename T>
  397. using is_const_lvalue = typename std::conditional<
  398. std::is_lvalue_reference<T>::value &&
  399. std::is_const<typename std::remove_reference<T>::type>::value,
  400. std::true_type, std::false_type>::type;
  401. } // namespace _traits
  402. // generic fallback case; assume input parameter
  403. // (also covers boxed callerallocates, which pretty much is/becomes input)
  404. template<typename CppArg, typename Enable>
  405. struct cb_arg_handler
  406. {
  407. using c_type = typename traits::ctype<CppArg>::type;
  408. // use generic CType to handle const differences wrt c_type
  409. template<typename CType, typename Transfer, typename ArgTrait>
  410. typename std::decay<CppArg>::type arg(
  411. CType arg, const Transfer &t, const ArgTrait &) noexcept
  412. {
  413. // wrap to normalized destination target (no const &)
  414. // the destination type here is really only relevant for collection cases
  415. // (since that depends on the contained element)
  416. // otherwise all the info is pretty much in c_type type
  417. return wrap_to<typename std::decay<CppArg>::type>(arg, t);
  418. }
  419. // minor variation; dynamic sized array input
  420. // also accepts length input
  421. template<typename CType, typename Transfer, typename ArgTrait>
  422. typename std::decay<CppArg>::type arg(
  423. CType arg, int length, const Transfer &t, const ArgTrait &) noexcept
  424. {
  425. // destination also really needed here
  426. return wrap_to<typename std::decay<CppArg>::type>(arg, length, t);
  427. }
  428. void post(...){};
  429. };
  430. // passthrough on (pointers to) basic values;
  431. // handles input/output of basic values, as well as arrays of such
  432. template<typename CppArg>
  433. struct cb_arg_handler<CppArg,
  434. typename std::enable_if<_traits::is_basic_argument<CppArg>::value>::type>
  435. {
  436. using c_type = CppArg;
  437. template<typename CType, typename Transfer, typename ArgTrait>
  438. CType arg(CType arg, const Transfer &, const ArgTrait &) noexcept
  439. {
  440. return arg;
  441. }
  442. void post(...){};
  443. // array size case; inout C int* to in Cpp int
  444. // (only enable if so tagged by non-default custom trait type)
  445. template<typename CType, typename Transfer, typename ArgTrait>
  446. typename std::enable_if<
  447. !std::is_void<typename arg_traits<ArgTrait>::custom_type>::value,
  448. CType>::type
  449. arg(CType *arg, const Transfer &, const ArgTrait &) noexcept
  450. {
  451. return *arg;
  452. }
  453. };
  454. // handle "complex" (in)out argument
  455. // (though also handles e.g. int& case, which might be optimized, but anyways)
  456. // these are recognized/assumed to be a pointer or reference to non-basic type
  457. template<typename CppArg>
  458. struct cb_arg_handler<CppArg,
  459. typename std::enable_if<
  460. !_traits::is_basic_argument<CppArg>::value &&
  461. (std::is_pointer<CppArg>::value ||
  462. (std::is_lvalue_reference<CppArg>::value &&
  463. !_traits::is_const_lvalue<CppArg>::value))>::type>
  464. {
  465. using BaseCppType =
  466. typename std::decay<typename std::remove_pointer<CppArg>::type>::type;
  467. // no more pointer expected here
  468. // (other than for void* cases, which do not introspect well, but anyways)
  469. static_assert(!std::is_pointer<BaseCppType>::value ||
  470. std::is_same<BaseCppType, gpointer>::value ||
  471. std::is_same<BaseCppType, gconstpointer>::value,
  472. "");
  473. using c_type = typename traits::ctype<BaseCppType>::type *;
  474. // intermediate helper storage
  475. BaseCppType var_{};
  476. // pointer case
  477. CppArg rv(std::true_type) { return &var_; }
  478. // ref case
  479. CppArg rv(std::false_type) { return var_; }
  480. // handle const variations (e.g. const char**)
  481. template<typename T, typename X>
  482. static void assign(T *&t, X val)
  483. {
  484. t = const_cast<T *>(val);
  485. }
  486. template<typename T, typename X>
  487. static void assign(T &t, X val)
  488. {
  489. t = unconst(val);
  490. }
  491. template<typename Transfer, typename ArgTrait>
  492. CppArg arg(c_type arg, const Transfer &t, const ArgTrait &)
  493. {
  494. bool inout = arg_traits<ArgTrait>::inout;
  495. // a plain type has no special needs
  496. // so we can always take any bogus value as-is
  497. // (which is then less sensitive to incorrect annotation)
  498. if (arg && (inout || traits::is_plain<BaseCppType>::value))
  499. var_ = wrap_to<BaseCppType>(*arg, t);
  500. return rv(std::is_pointer<CppArg>());
  501. }
  502. // overall function call happens following arg call above
  503. // post invoked after function call
  504. template<typename Transfer>
  505. void post(c_type arg, const Transfer &t)
  506. {
  507. if (arg)
  508. assign(*arg, unwrap_maybe_float(std::move(var_), t));
  509. }
  510. // sized array variants; arguments (data, size)
  511. // latter could be input (int) or (in)out (int*)
  512. template<typename Transfer, typename Int, typename ArgTrait>
  513. CppArg arg(c_type arg, Int size, const Transfer &t, const ArgTrait &)
  514. {
  515. bool inout = arg_traits<ArgTrait>::inout;
  516. if (arg && inout)
  517. var_ = wrap_to<BaseCppType>(*arg, size, t);
  518. return rv(std::is_pointer<CppArg>());
  519. }
  520. template<typename Transfer, typename Int, typename ArgTrait>
  521. CppArg arg(c_type arg, Int *size, const Transfer &t, const ArgTrait &)
  522. {
  523. bool inout = arg_traits<ArgTrait>::inout;
  524. if (arg && size && inout)
  525. var_ = wrap_to<BaseCppType>(*arg, *size, t);
  526. return rv(std::is_pointer<CppArg>());
  527. }
  528. template<typename Transfer, typename Int>
  529. void post(c_type arg, Int, const Transfer &t)
  530. {
  531. post(arg, nullptr, t);
  532. }
  533. template<typename Transfer, typename Int>
  534. void post(c_type arg, Int *size, const Transfer &t)
  535. {
  536. if (arg)
  537. assign(*arg, unwrap_maybe_float(std::move(var_), t));
  538. if (size)
  539. *size = var_.size();
  540. }
  541. };
  542. #define GI_CB_ARG_CALLBACK_CUSTOM(Type, CF_CType, CF_handler) \
  543. struct Type \
  544. { \
  545. using handler_cb_type = CF_CType; \
  546. static constexpr auto handler = CF_handler; \
  547. }
  548. // handles callback argument
  549. // (as argument in anther callback, most likely a virtual method)
  550. template<typename CppArg>
  551. struct cb_arg_handler<CppArg,
  552. typename std::enable_if<
  553. std::is_pointer<typename CppArg::cfunction_type>::value>::type>
  554. {
  555. template<typename CType, typename Transfer, typename ArgTrait>
  556. CppArg arg(CType cb, gpointer userdata, ::GDestroyNotify destroy,
  557. const Transfer &, const ArgTrait &) noexcept
  558. {
  559. using ct = typename arg_traits<ArgTrait>::custom_type;
  560. // setup shared pointer to userdata with destroy as Deleter
  561. auto sp = destroy ? std::shared_ptr<void>(userdata, destroy) : nullptr;
  562. // keep userdata/destroy alive as long as lambda handler
  563. auto h = [cb, userdata, destroy = std::move(destroy)](
  564. auto &&...args) -> decltype(auto) {
  565. // avoid unused warning
  566. (void)destroy;
  567. // original callback type CType should match deduced handler_cb_tpe
  568. // but let's make sure as usual
  569. return ct::handler(std::forward<decltype(args)>(args)...,
  570. typename ct::handler_cb_type(cb), userdata);
  571. };
  572. return h;
  573. }
  574. template<typename CType, typename Transfer, typename ArgTrait>
  575. CppArg arg(CType cb, gpointer userdata, const Transfer &t,
  576. const ArgTrait &tt) noexcept
  577. {
  578. return arg(cb, userdata, nullptr, t, tt);
  579. }
  580. void post(...){};
  581. };
  582. class connection_status
  583. {
  584. public:
  585. struct data
  586. {
  587. bool connected{false};
  588. };
  589. bool connected() const
  590. {
  591. auto sp = data_.lock();
  592. return sp && sp->connected;
  593. }
  594. protected:
  595. std::weak_ptr<data> data_;
  596. };
  597. // callback handling
  598. template<typename G>
  599. class connectable;
  600. template<typename G, bool AUTODESTROY = false>
  601. class callback_wrapper;
  602. template<typename R, typename... Args>
  603. class connectable<R(Args...)>
  604. {
  605. friend class callback_wrapper<R(Args...)>;
  606. struct data : public connection_status::data
  607. {
  608. template<typename T,
  609. typename Enable = typename detail::disable_if_same_or_derived<data, T>>
  610. data(T &&t) : callable(std::forward<T>(t))
  611. {}
  612. std::function<R(Args... args)> callable;
  613. };
  614. struct connection_status_factory : public connection_status
  615. {
  616. connection_status_factory(std::shared_ptr<data> p)
  617. {
  618. data_ = std::weak_ptr<connection_status::data>(p);
  619. }
  620. };
  621. public:
  622. // avoid copy constructor mishaps
  623. template<typename T,
  624. typename Enable =
  625. typename detail::disable_if_same_or_derived<connectable, T>>
  626. connectable(T &&t) : data_(std::make_shared<data>(std::forward<T>(t)))
  627. {}
  628. connection_status connection() const
  629. {
  630. return connection_status_factory(data_);
  631. }
  632. R operator()(Args... args) const
  633. {
  634. return data_->callable(std::forward<Args>(args)...);
  635. }
  636. explicit operator bool() const { return data_ && data_->callable; }
  637. private:
  638. // state management by wrapper
  639. void connected(bool conn) { data_->connected = conn; }
  640. void disconnect() { data_->connected = false; }
  641. private:
  642. std::shared_ptr<data> data_;
  643. };
  644. template<typename R, typename... Args, bool AUTODESTROY>
  645. class callback_wrapper<R(Args...), AUTODESTROY>
  646. {
  647. typedef callback_wrapper self_type;
  648. public:
  649. template<typename T,
  650. typename Enable =
  651. typename detail::disable_if_same_or_derived<callback_wrapper, T>>
  652. callback_wrapper(T &&t) : _callback(std::forward<T>(t))
  653. {
  654. // mark connected now that it is wrapped
  655. _callback.connected(true);
  656. }
  657. // (only) used by manual callback workaround
  658. static R wrapper(Args... args, gpointer user_data)
  659. {
  660. auto t = reinterpret_cast<callback_wrapper *>(user_data);
  661. std::unique_ptr<self_type> wt(AUTODESTROY ? t : nullptr);
  662. return t->_callback(args...);
  663. }
  664. static void destroy(gpointer user_data)
  665. {
  666. auto t = reinterpret_cast<callback_wrapper *>(user_data);
  667. delete t;
  668. }
  669. // (async scope) wrapper may have to take ownership of additional data
  670. // (other callback wrapper)
  671. template<typename T>
  672. void take_data(std::shared_ptr<T> d)
  673. {
  674. auto cb = std::move(_callback.data_->callable);
  675. auto newcb = [d, cb](Args &&...args) {
  676. return cb(std::forward<Args>(args)...);
  677. };
  678. _callback.data_->callable = std::move(newcb);
  679. }
  680. template<typename T>
  681. void take_data(T *d)
  682. {
  683. take_data(std::shared_ptr<T>(d));
  684. }
  685. ~callback_wrapper()
  686. {
  687. // other shared ptr to data might be around (unlikely though)
  688. // but regardless disconnect now as requested (as wrapper is going away)
  689. _callback.disconnect();
  690. }
  691. connectable<R(Args... args)> _callback;
  692. };
  693. template<typename G, typename CG = typename map_cpp_function<G>::type>
  694. struct transform_callback_wrapper;
  695. template<typename R, typename... Args, typename CR, typename... CArgs>
  696. struct transform_callback_wrapper<R(Args...), CR(CArgs...)>
  697. {
  698. // transfers of arguments
  699. template<bool AUTODESTROY, typename RetTransfer, typename... Transfers>
  700. class with_transfer : public callback_wrapper<R(Args...)>
  701. {
  702. typedef callback_wrapper<R(Args...)> super_type;
  703. typedef with_transfer self_type;
  704. public:
  705. template<typename T>
  706. explicit with_transfer(T &&t) : super_type(std::forward<T>(t))
  707. {}
  708. private:
  709. static R caller(Args &&...args, void *d)
  710. {
  711. auto this_ = (self_type *)d;
  712. return this_->_callback(std::forward<Args>(args)...);
  713. }
  714. public:
  715. static CR wrapper(CArgs... args, gpointer user_data)
  716. {
  717. auto t = reinterpret_cast<self_type *>(user_data);
  718. std::unique_ptr<self_type> wt(AUTODESTROY ? t : nullptr);
  719. return transform_caller<R(Args...), RetTransfer, std::tuple<Transfers...>,
  720. CR(CArgs...)>::wrapper(args..., caller, t);
  721. }
  722. };
  723. };
  724. // used early in declarations, so avoid using unknown types in CSigOrVoid
  725. template<typename CppSig, typename RetTransfer,
  726. typename ArgTransfers = std::tuple<>, typename CSigOrVoid = void>
  727. class callback;
  728. template<typename CppSig, typename RetTransfer, typename... Transfers,
  729. typename CSigOrVoid>
  730. class callback<CppSig, RetTransfer, std::tuple<Transfers...>, CSigOrVoid>
  731. : public connectable<CppSig>
  732. {
  733. typedef connectable<CppSig> super_type;
  734. public:
  735. typedef CppSig function_type;
  736. typedef typename map_cpp_function<CppSig, CSigOrVoid>::type CSig;
  737. template<bool ASYNC = false>
  738. using wrapper_type = typename transform_callback_wrapper<function_type,
  739. CSig>::template with_transfer<ASYNC, RetTransfer, Transfers...>;
  740. typedef typename std::add_pointer<decltype(wrapper_type<>::wrapper)>::type
  741. cfunction_type;
  742. using super_type::super_type;
  743. };
  744. // signal handling;
  745. // transfer none for arguments
  746. // transfer full for return
  747. template<typename G>
  748. struct transform_signal_wrapper;
  749. template<typename T>
  750. struct signal_arg_transfer
  751. {
  752. typedef transfer_none_t type;
  753. };
  754. template<typename R, typename... Args>
  755. struct transform_signal_wrapper<R(Args...)>
  756. : public transform_callback_wrapper<R(
  757. Args...)>::template with_transfer<false, transfer_full_t,
  758. typename detail::signal_arg_transfer<Args>::type...>
  759. {
  760. private:
  761. typedef typename transform_callback_wrapper<R(
  762. Args...)>::template with_transfer<false, transfer_full_t,
  763. typename detail::signal_arg_transfer<Args>::type...>
  764. super_;
  765. public:
  766. template<typename T>
  767. transform_signal_wrapper(T &&t) : super_(std::forward<T>(t))
  768. {}
  769. };
  770. // connection helpers
  771. class connection_impl
  772. {
  773. public:
  774. connection_impl(gulong id, connection_status s) : id_(id), status_(s) {}
  775. bool connected() const { return status_.connected(); }
  776. gulong id() const { return id_; }
  777. protected:
  778. gulong id_;
  779. connection_status status_;
  780. };
  781. template<typename Connection>
  782. class connection
  783. {
  784. typedef Connection impl;
  785. public:
  786. connection() = default;
  787. template<typename... Args>
  788. explicit connection(Args... arg)
  789. : conn_(std::make_shared<impl>(std::forward<Args>(arg)...))
  790. {
  791. // this is to be expected at this time
  792. if (!connected()) {
  793. g_warning("creating non-connected connection");
  794. }
  795. }
  796. // implicit copy/move
  797. bool connected() const { return conn_ && conn_->connected(); }
  798. void disconnect()
  799. {
  800. if (connected())
  801. conn_->disconnect();
  802. }
  803. protected:
  804. std::shared_ptr<impl> conn_;
  805. };
  806. template<typename ConnectionBase>
  807. class scoped_connection : public ConnectionBase
  808. {
  809. typedef ConnectionBase connection;
  810. public:
  811. scoped_connection() : connection() {}
  812. ~scoped_connection() { this->disconnect(); }
  813. void release() { this->conn_.reset(); }
  814. // ensure default movable
  815. scoped_connection(scoped_connection &&other) = default;
  816. scoped_connection &operator=(scoped_connection &&other) = default;
  817. // not copyable; to avoid inadvertent disconnect
  818. scoped_connection(const scoped_connection &other) = delete;
  819. scoped_connection &operator=(const scoped_connection &other) = delete;
  820. // but convert/assign from base class
  821. scoped_connection(const connection &other) : connection(other) {}
  822. scoped_connection &operator=(const connection &other)
  823. {
  824. (*(connection *)(this)) = other;
  825. return *this;
  826. }
  827. scoped_connection &operator=(const connection &&other)
  828. {
  829. (*(connection *)(this)) = std::move(other);
  830. return *this;
  831. }
  832. };
  833. } // namespace detail
  834. // function bind helpers
  835. template<typename R, typename T, typename Tp, typename... Args>
  836. inline std::function<R(Args...)>
  837. mem_fun(R (T::*pm)(Args...), Tp object)
  838. {
  839. return [object, pm](Args... args) {
  840. return (object->*pm)(std::forward<Args>(args)...);
  841. };
  842. }
  843. template<typename R, typename T, typename Tp, typename... Args>
  844. inline std::function<R(Args...)>
  845. mem_fun(R (T::*pm)(Args...) const, Tp object)
  846. {
  847. return [object, pm](Args... args) {
  848. return (object->*pm)(std::forward<Args>(args)...);
  849. };
  850. }
  851. // expose for use in fallback scenarios
  852. using detail::callback_wrapper;
  853. } // namespace gi
  854. #endif // CALLBACK_HPP