wrap.hpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. #ifndef GI_WRAP_HPP
  2. #define GI_WRAP_HPP
  3. #include "base.hpp"
  4. #include "string.hpp"
  5. namespace gi
  6. {
  7. // object/wrapper conversion
  8. template<typename CType, typename TransferType,
  9. typename CppType = typename traits::cpptype<CType *>::type,
  10. typename Enable =
  11. typename std::enable_if<traits::is_wrapper<CppType>::value>::type>
  12. inline typename std::remove_const<CppType>::type
  13. wrap(CType *v, const TransferType &t)
  14. {
  15. // should be called with a concrete transfer subtype
  16. static_assert(!std::is_same<TransferType, transfer_t>::value, "");
  17. // the class wrap only has to deal with non-const class type
  18. typedef typename std::remove_const<CppType>::type TNC;
  19. return CppType::template wrap<TNC>(v, t.value);
  20. }
  21. // special case; wrap an owned box with full transfer
  22. template<typename CType,
  23. typename CppType = typename traits::cpptype<CType *>::type,
  24. typename Enable =
  25. typename std::enable_if<traits::is_boxed<CppType>::value>::type,
  26. typename TNC = typename std::remove_const<CppType>::type>
  27. inline TNC
  28. wrap(CType *v, const transfer_full_t &)
  29. {
  30. return CppType::template wrap<TNC>(v);
  31. }
  32. // special case; wrap a unowned box (that is, transfer none) to the Ref type
  33. template<typename CType,
  34. typename CppType = typename traits::cpptype<CType *>::type,
  35. typename Enable =
  36. typename std::enable_if<traits::is_boxed<CppType>::value>::type,
  37. typename RefType = typename traits::reftype<
  38. typename std::remove_const<CppType>::type>::type>
  39. inline RefType
  40. wrap(CType *v, const transfer_none_t &)
  41. {
  42. // unowned and no copy in all cases
  43. return RefType::template wrap<RefType>(v);
  44. }
  45. template<typename T,
  46. typename std::remove_reference<T>::type::BaseObjectType * = nullptr>
  47. inline typename traits::ctype<T>::type
  48. unwrap(T &&v, const transfer_none_t &)
  49. {
  50. using DT = typename std::decay<T>::type;
  51. // test convenience
  52. #ifndef GI_TEST
  53. static constexpr bool ALLOW_ALL = false;
  54. #else
  55. static constexpr bool ALLOW_ALL = true;
  56. #endif
  57. static_assert(ALLOW_ALL || traits::is_wrapper<DT>::value ||
  58. traits::is_reftype<DT>::value,
  59. "transfer none expects refcnt wrapper or reftype (not owning box)");
  60. return v.gobj_();
  61. }
  62. namespace detail
  63. {
  64. // lvalue
  65. template<typename T,
  66. typename std::enable_if<!traits::is_boxed<T>::value>::type * = nullptr>
  67. inline typename traits::ctype<T>::type
  68. unwrap(const T &v, const transfer_full_t &, std::true_type)
  69. {
  70. // no implicit copy for boxed; should end up in other case
  71. static_assert(!traits::is_boxed<T>::value, "boxed copy");
  72. return v.gobj_copy_();
  73. }
  74. // rvalue
  75. template<typename T,
  76. typename std::enable_if<!traits::is_reftype<T>::value>::type * = nullptr>
  77. inline typename traits::ctype<T>::type
  78. unwrap(T &&v, const transfer_full_t &, std::false_type)
  79. {
  80. // in case of wrapper/object;
  81. // release only provided on base case with void* return
  82. return (typename traits::ctype<T>::type)v.release_();
  83. }
  84. } // namespace detail
  85. template<typename T, typename std::decay<T>::type::BaseObjectType * = nullptr>
  86. inline typename traits::ctype<T>::type
  87. unwrap(T &&v, const transfer_full_t &t)
  88. {
  89. // universal reference dispatch
  90. return detail::unwrap(std::forward<T>(v), t, std::is_lvalue_reference<T>());
  91. }
  92. // container types
  93. template<typename T, typename Transfer,
  94. typename std::decay<T>::type::_detail::DataType * = nullptr>
  95. inline typename std::decay<T>::type::_detail::DataType
  96. unwrap(T &&v, const Transfer &t)
  97. {
  98. // universal reference dispatch
  99. return std::forward<T>(v)._unwrap(t);
  100. }
  101. // to wrap a container, the target wrapped type needs to be explicitly specified
  102. // (in particular the contained element type)
  103. // (target type should be decay'ed type)
  104. // generic case, let wrap take care of it (usually no target type is needed)
  105. template<typename TargetType, typename CType, typename Transfer,
  106. decltype(wrap(std::declval<typename std::decay<CType>::type>(),
  107. Transfer())) * = nullptr>
  108. TargetType
  109. wrap_to(CType v, const Transfer &t)
  110. {
  111. static_assert(traits::is_decayed<TargetType>::value, "");
  112. return wrap(v, t);
  113. }
  114. // container case
  115. template<typename TargetType, typename CType, typename Transfer,
  116. typename TargetType::_detail::DataType * = nullptr>
  117. TargetType
  118. wrap_to(CType v, const Transfer &t)
  119. {
  120. static_assert(traits::is_decayed<TargetType>::value, "");
  121. return TargetType::template _wrap<TargetType>(v, t);
  122. }
  123. // container size case
  124. template<typename TargetType, typename CType, typename Transfer,
  125. typename TargetType::_detail::DataType * = nullptr>
  126. TargetType
  127. wrap_to(CType v, int s, const Transfer &t)
  128. {
  129. static_assert(traits::is_decayed<TargetType>::value, "");
  130. return TargetType::template _wrap<TargetType>(v, s, t);
  131. }
  132. #if 0
  133. // string conversion
  134. inline std::string
  135. wrap(const char *v, const transfer_none_t &,
  136. const direction_t & = direction_dummy)
  137. {
  138. return detail::make_string(v);
  139. }
  140. // actually should not accept const input (as it makes no sense for full
  141. // transfer) but let's go the runtime way and not mind that too much (code
  142. // generation will warn though)
  143. inline std::string
  144. wrap(const char *v, const transfer_full_t &,
  145. const direction_t & = direction_dummy)
  146. {
  147. // a custom type that would allow direct mem transfer might be nice
  148. // but that might be too nifty and create yet-another-string-type
  149. std::string s;
  150. if (v) {
  151. s = v;
  152. g_free((char *)v);
  153. }
  154. return s;
  155. }
  156. #else
  157. // string conversion
  158. inline gi::cstring_v
  159. wrap(const char *v, const transfer_none_t &)
  160. {
  161. return cstring_v(v);
  162. }
  163. // actually should not accept const input (as it makes no sense for full
  164. // transfer) but let's go the runtime way and not mind that too much (code
  165. // generation will warn though)
  166. inline gi::cstring
  167. wrap(const char *v, const transfer_full_t &)
  168. {
  169. // as said, never mind const
  170. return cstring{(char *)v, transfer_full};
  171. }
  172. #endif
  173. // return const here, as somewhat customary, also
  174. // wrapped function call is force-casted anyway (to const char* parameter)
  175. // FIXME ?? though const is generally rare and it breaks consistency that way
  176. inline const gchar *
  177. unwrap(const std::string &v, const transfer_none_t &)
  178. {
  179. return v.c_str();
  180. }
  181. inline const gchar *
  182. unwrap(const detail::optional_string &v, const transfer_none_t &)
  183. {
  184. return v.empty() ? nullptr : v.c_str();
  185. }
  186. template<typename Transfer>
  187. inline const gchar *
  188. unwrap(const detail::cstr<Transfer> &v, const transfer_none_t &)
  189. {
  190. return v.c_str();
  191. }
  192. inline gchar *
  193. unwrap(const std::string &v, const transfer_full_t &)
  194. {
  195. return g_strdup(v.c_str());
  196. }
  197. inline gchar *
  198. unwrap(const detail::optional_string &v, const transfer_full_t &)
  199. {
  200. return v.empty() ? nullptr : g_strdup(v.c_str());
  201. }
  202. template<typename Transfer>
  203. inline gchar *
  204. unwrap(const gi::detail::cstr<Transfer> &v, const transfer_full_t &)
  205. {
  206. return g_strdup(v.c_str());
  207. }
  208. inline gchar *
  209. unwrap(gi::cstring &&v, const transfer_full_t &)
  210. {
  211. return v.release_();
  212. }
  213. // enum conversion
  214. template<typename T,
  215. typename std::enable_if<std::is_enum<T>::value>::type * = nullptr>
  216. inline typename traits::cpptype<T>::type
  217. wrap(T v, const transfer_t & = transfer_dummy)
  218. {
  219. return (typename traits::cpptype<T>::type)v;
  220. }
  221. template<typename T,
  222. typename std::enable_if<std::is_enum<T>::value>::type * = nullptr>
  223. inline typename traits::ctype<T>::type
  224. unwrap(T v, const transfer_t & = transfer_dummy)
  225. {
  226. return (typename traits::ctype<T>::type)v;
  227. }
  228. // plain basic pass along
  229. template<typename T,
  230. typename std::enable_if<traits::is_basic<T>::value>::type * = nullptr>
  231. inline T
  232. wrap(T v, const transfer_t & = transfer_dummy)
  233. {
  234. return v;
  235. }
  236. template<typename T,
  237. typename std::enable_if<traits::is_basic<T>::value>::type * = nullptr>
  238. inline T
  239. unwrap(T v, const transfer_t & = transfer_dummy)
  240. {
  241. return v;
  242. }
  243. // callback conversion
  244. // async or destroy-notify;
  245. // signature forces copy, and std::move is used in unwrap call
  246. template<typename T,
  247. typename std::remove_reference<T>::type::CallbackWrapperType * = nullptr>
  248. inline typename std::remove_reference<T>::type::CallbackWrapperType
  249. unwrap(T &&v, const transfer_t & = transfer_dummy)
  250. {
  251. return typename std::remove_reference<T>::type::CallbackWrapperType(
  252. std::forward<T>(v));
  253. }
  254. // call or destroy-notify scope
  255. template<typename T>
  256. inline typename std::remove_reference<T>::type::template wrapper_type<false> *
  257. unwrap(T &&v, const scope_t &)
  258. {
  259. return new
  260. typename std::remove_reference<T>::type::template wrapper_type<false>(
  261. std::forward<T>(v));
  262. }
  263. // async scope
  264. template<typename T>
  265. inline typename std::remove_reference<T>::type::template wrapper_type<true> *
  266. unwrap(T &&v, const scope_async_t &)
  267. {
  268. return new
  269. typename std::remove_reference<T>::type::template wrapper_type<true>(
  270. std::forward<T>(v));
  271. }
  272. // dynamic GType casting within GObject/interface hierarchy
  273. template<typename T, typename I,
  274. typename std::enable_if<
  275. traits::is_object<T>::value &&
  276. traits::is_object<typename std::decay<I>::type>::value>::type * =
  277. nullptr>
  278. inline T
  279. object_cast(I &&t)
  280. {
  281. if (!t || !g_type_is_a(t.gobj_type_(), T::get_type_())) {
  282. return T();
  283. } else {
  284. return wrap((typename T::BaseObjectType *)t.gobj_copy_(), transfer_full);
  285. }
  286. }
  287. // this utility can be used to arrange for pointer-like const-ness
  288. // that is, a const shared_ptr<T> is still usable like (non-const) T*
  289. // in a way, any wrapper object T acts much like a smart-pointer,
  290. // but as the (code generated) methods are non-const, they are not usable
  291. // if the wrapper object is const (e.g. captured in a lambda)
  292. // this helper object/class can be wrapped around the wrapper (phew)
  293. // to absorb/shield the (outer) `const` (as it behaves as other smart pointers)
  294. template<typename T>
  295. class cs_ptr
  296. {
  297. T t;
  298. public:
  299. // rough check; T is expected to be a pointer wrapper
  300. static_assert(sizeof(T) == sizeof(void *), "");
  301. // if T not copy-able, argument may need to be move'd
  302. cs_ptr(T _t) : t(std::move(_t)) {}
  303. operator T() const & { return t; }
  304. operator T() && { return std::move(t); }
  305. T *get() const { return &t; }
  306. // C++ sacrilege,
  307. // but the const of pointer in T does not extend to pointee anyway
  308. T *operator*() const { return const_cast<T *>(&t); }
  309. T *operator->() const { return const_cast<T *>(&t); }
  310. };
  311. } // namespace gi
  312. #endif // GI_WRAP_HPP