main.cpp 72 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660
  1. #include <array>
  2. #include <iostream>
  3. #include <memory>
  4. #include <unordered_map>
  5. #include <vector>
  6. #include "assert.h"
  7. #define GI_CLASS_IMPL_PRAGMA
  8. #define GI_TEST 1
  9. #include "gi.hpp"
  10. #include "test/test_boxed.h"
  11. #include "test/test_object.h"
  12. using namespace gi;
  13. namespace GLib = gi::repository::GLib;
  14. namespace GObject_ = gi::repository::GObject;
  15. #define BOXED_COPY 0
  16. #if BOXED_COPY
  17. namespace gi
  18. {
  19. namespace repository
  20. {
  21. GI_ENABLE_BOXED_COPY(GBExample)
  22. }
  23. } // namespace gi
  24. #endif
  25. // test examples;
  26. // GBoxed
  27. class GBoxedExampleBase
  28. : public detail::GBoxedWrapperBase<GBoxedExampleBase, GBExample>
  29. {
  30. typedef detail::GBoxedWrapperBase<GBoxedExampleBase, GBExample> super_type;
  31. public:
  32. static GType get_type_() { return GI_CPP_TYPE_BOXED_EXAMPLE; }
  33. GBoxedExampleBase(std::nullptr_t = nullptr) : super_type() {}
  34. };
  35. class GBoxedExampleRef;
  36. class GBoxedExample : public detail::GBoxedWrapper<GBoxedExample, GBExample,
  37. GBoxedExampleBase, GBoxedExampleRef>
  38. {
  39. typedef detail::GBoxedWrapper<GBoxedExample, GBExample, GBoxedExampleBase,
  40. GBoxedExampleRef>
  41. super_type;
  42. using super_type::super_type;
  43. };
  44. class GBoxedExampleRef : public detail::GBoxedRefWrapper<GBoxedExample,
  45. GBExample, GBoxedExampleBase>
  46. {
  47. typedef detail::GBoxedRefWrapper<GBoxedExample, GBExample, GBoxedExampleBase>
  48. super_type;
  49. using super_type::super_type;
  50. };
  51. // plain C
  52. class CBoxedExampleBase
  53. : public detail::CBoxedWrapperBase<CBoxedExampleBase, CBExample>
  54. {
  55. typedef detail::CBoxedWrapperBase<CBoxedExampleBase, CBExample> super_type;
  56. public:
  57. CBoxedExampleBase(std::nullptr_t = nullptr) : super_type() {}
  58. };
  59. class CBoxedExampleRef;
  60. class CBoxedExample : public detail::CBoxedWrapper<CBoxedExample, CBExample,
  61. CBoxedExampleBase, CBoxedExampleRef>
  62. {
  63. typedef detail::CBoxedWrapper<CBoxedExample, CBExample, CBoxedExampleBase,
  64. CBoxedExampleRef>
  65. super_type;
  66. using super_type::super_type;
  67. };
  68. class CBoxedExampleRef : public detail::CBoxedRefWrapper<CBoxedExample,
  69. CBExample, CBoxedExampleBase>
  70. {
  71. typedef detail::CBoxedRefWrapper<CBoxedExample, CBExample, CBoxedExampleBase>
  72. super_type;
  73. using super_type::super_type;
  74. };
  75. enum class CppEnum { VALUE_0 = ENUM_VALUE_0, VALUE_1 = ENUM_VALUE_1 };
  76. enum class CppFlags { VALUE_0 = FLAG_VALUE_0, VALUE_1 = FLAG_VALUE_1 };
  77. GI_FLAG_OPERATORS(CppFlags)
  78. namespace gi
  79. {
  80. namespace repository
  81. {
  82. template<>
  83. struct declare_cpptype_of<GBExample>
  84. {
  85. typedef GBoxedExample type;
  86. };
  87. template<>
  88. struct declare_cpptype_of<CBExample>
  89. {
  90. typedef CBoxedExample type;
  91. };
  92. template<>
  93. struct declare_ctype_of<CppEnum>
  94. {
  95. typedef CEnum type;
  96. };
  97. template<>
  98. struct declare_cpptype_of<CEnum>
  99. {
  100. typedef CppEnum type;
  101. };
  102. template<>
  103. struct declare_gtype_of<CppEnum>
  104. {
  105. static GType get_type() { return GI_CPP_TYPE_ENUM; }
  106. };
  107. template<>
  108. struct is_enumeration<CppEnum> : public std::true_type
  109. {};
  110. template<>
  111. struct declare_ctype_of<CppFlags>
  112. {
  113. typedef CFlags type;
  114. };
  115. template<>
  116. struct declare_cpptype_of<CFlags>
  117. {
  118. typedef CppFlags type;
  119. };
  120. template<>
  121. struct declare_gtype_of<CppFlags>
  122. {
  123. static GType get_type() { return GI_CPP_TYPE_FLAGS; }
  124. };
  125. template<>
  126. struct is_bitfield<CppFlags> : public std::true_type
  127. {};
  128. } // namespace repository
  129. } // namespace gi
  130. #define DECLARE_PROPERTY(pname, ptype) \
  131. property_proxy<ptype> property_##pname() \
  132. { \
  133. return property_proxy<ptype>(*this, #pname); \
  134. } \
  135. const property_proxy<ptype> property_##pname() const \
  136. { \
  137. return property_proxy<ptype>(*this, #pname); \
  138. }
  139. #define DECLARE_SIGNAL(name, sig) \
  140. signal_proxy<sig> signal_##name() { return signal_proxy<sig>(*this, #name); }
  141. // simulate override construction
  142. class Derived;
  143. typedef GICppExample CDerived;
  144. namespace base
  145. {
  146. class DerivedBase : public GObject_::Object
  147. {
  148. typedef Object super_type;
  149. public:
  150. typedef Derived self;
  151. typedef CDerived BaseObjectType;
  152. DerivedBase(std::nullptr_t = nullptr) : super_type() {}
  153. BaseObjectType *gobj_() { return (BaseObjectType *)super_type::gobj_(); }
  154. const BaseObjectType *gobj_() const
  155. {
  156. return (const BaseObjectType *)super_type::gobj_();
  157. }
  158. BaseObjectType *gobj_copy_() const
  159. {
  160. return (BaseObjectType *)super_type::gobj_copy_();
  161. }
  162. static GType get_type_() { return GI_CPP_TYPE_EXAMPLE; }
  163. DECLARE_PROPERTY(number, int)
  164. DECLARE_PROPERTY(fnumber, double)
  165. DECLARE_PROPERTY(data, std::string)
  166. DECLARE_PROPERTY(present, gboolean)
  167. DECLARE_PROPERTY(object, Object)
  168. DECLARE_PROPERTY(choice, CppEnum)
  169. DECLARE_PROPERTY(flags, CppFlags)
  170. DECLARE_PROPERTY(error, GLib::Error)
  171. DECLARE_SIGNAL(
  172. to_int, int(Derived, Object, bool, gboolean, const std::string &))
  173. DECLARE_SIGNAL(to_string, std::string(Derived, int, gint64))
  174. DECLARE_SIGNAL(to_void, void(Derived, double, CppEnum, CppFlags))
  175. DECLARE_SIGNAL(to_output_int,
  176. void(Derived, unsigned &,
  177. gi::Collection<::GPtrArray, char *, gi::transfer_none_t>,
  178. gi::Collection<::GSList, char *, gi::transfer_none_t>))
  179. };
  180. } // namespace base
  181. class Derived : public base::DerivedBase
  182. {
  183. typedef base::DerivedBase super;
  184. using super::super;
  185. };
  186. namespace gi
  187. {
  188. namespace repository
  189. {
  190. template<>
  191. struct declare_cpptype_of<CDerived>
  192. {
  193. typedef Derived type;
  194. };
  195. } // namespace repository
  196. } // namespace gi
  197. void
  198. test_trait()
  199. {
  200. static_assert(traits::is_basic<int>::value, "");
  201. static_assert(traits::is_basic<float>::value, "");
  202. static_assert(traits::is_basic<void *>::value, "");
  203. static_assert(!traits::is_basic<char *>::value, "");
  204. static_assert(traits::is_boxed<GBoxedExample>::value, "");
  205. static_assert(traits::is_object<Derived>::value, "");
  206. static_assert(!traits::is_object<int>::value, "");
  207. static_assert(traits::is_reftype<GBoxedExampleRef>::value, "");
  208. static_assert(!traits::is_reftype<GBoxedExample>::value, "");
  209. static_assert(!traits::is_reftype<int>::value, "");
  210. static_assert(traits::has_ctype_member<Derived>::value, "");
  211. static_assert(!traits::has_ctype_member<int>::value, "");
  212. static_assert(
  213. std::is_same<traits::ctype<Derived>::type, CDerived *>::value, "");
  214. static_assert(
  215. std::is_same<traits::ctype<const Derived>::type, const CDerived *>::value,
  216. "");
  217. static_assert(
  218. std::is_same<traits::cpptype<CDerived *>::type, Derived>::value, "");
  219. static_assert(std::is_same<traits::cpptype<const CDerived *>::type,
  220. const Derived>::value,
  221. "");
  222. static_assert(std::is_same<traits::ctype<CppEnum>::type, CEnum>::value, "");
  223. static_assert(std::is_same<traits::cpptype<CEnum>::type, CppEnum>::value, "");
  224. static_assert(
  225. std::is_same<traits::ctype<CBoxedExample>::type, CBExample *>::value, "");
  226. static_assert(
  227. std::is_same<traits::cpptype<CBExample>::type, CBoxedExample>::value, "");
  228. static_assert(std::is_same<traits::reftype<CBoxedExample>::type,
  229. CBoxedExampleRef>::value,
  230. "");
  231. static_assert(
  232. std::is_same<traits::ctype<GBoxedExample>::type, GBExample *>::value, "");
  233. static_assert(
  234. std::is_same<traits::cpptype<GBExample>::type, GBoxedExample>::value, "");
  235. static_assert(std::is_same<traits::reftype<GBoxedExample>::type,
  236. GBoxedExampleRef>::value,
  237. "");
  238. static_assert(
  239. std::is_same<traits::cpptype<GBExample *, transfer_none_t>::type,
  240. GBoxedExampleRef>::value,
  241. "");
  242. static_assert(
  243. std::is_same<traits::ctype<GObject_::Object>::type, _GObject *>::value,
  244. "");
  245. static_assert(
  246. std::is_same<traits::cpptype<_GObject>::type, GObject_::Object>::value,
  247. "");
  248. static_assert(std::is_same<traits::cpptype<bool>::type, bool>::value, "");
  249. static_assert(traits::gtype<int>::value, "");
  250. static_assert(traits::gtype<std::string>::value, "");
  251. static_assert(traits::gvalue<int>::value, "");
  252. static_assert(traits::gvalue<CppEnum>::value, "");
  253. static_assert(traits::is_enumeration<CppEnum>::value, "");
  254. static_assert(!traits::is_bitfield<CppEnum>::value, "");
  255. static_assert(traits::is_bitfield<CppFlags>::value, "");
  256. static_assert(
  257. std::is_pointer<GLib::DestroyNotify::cfunction_type>::value, "");
  258. static_assert(!detail::allocator<int>::value, "");
  259. static_assert(detail::allocator<GObject_::Value>::value, "");
  260. static_assert(detail::allocator<GBoxedExample>::value, "");
  261. static_assert(traits::is_type_complete<GBExample>::value, "");
  262. struct BlackBox;
  263. static_assert(!traits::is_type_complete<BlackBox>::value, "");
  264. static_assert(
  265. std::is_copy_constructible<GBoxedExample>::value == BOXED_COPY, "");
  266. static_assert(
  267. std::is_copy_assignable<GBoxedExample>::value == BOXED_COPY, "");
  268. static_assert(std::is_move_constructible<GBoxedExample>::value, "");
  269. static_assert(std::is_move_assignable<GBoxedExample>::value, "");
  270. static_assert(std::is_copy_constructible<GBoxedExampleRef>::value, "");
  271. static_assert(std::is_copy_assignable<GBoxedExampleRef>::value, "");
  272. static_assert(
  273. std::is_copy_constructible<CBoxedExample>::value == BOXED_COPY, "");
  274. static_assert(
  275. std::is_copy_assignable<CBoxedExample>::value == BOXED_COPY, "");
  276. static_assert(std::is_move_constructible<CBoxedExample>::value, "");
  277. static_assert(std::is_move_assignable<CBoxedExample>::value, "");
  278. static_assert(std::is_copy_constructible<CBoxedExampleRef>::value, "");
  279. static_assert(std::is_copy_assignable<CBoxedExampleRef>::value, "");
  280. // internal
  281. static_assert(detail::_traits::is_basic_argument<int>::value, "");
  282. static_assert(!detail::_traits::is_basic_argument<int &>::value, "");
  283. static_assert(!detail::_traits::is_basic_argument<std::string>::value, "");
  284. static_assert(
  285. detail::_traits::is_basic_argument<char *const *const>::value, "");
  286. static_assert(
  287. detail::_traits::is_const_lvalue<const std::string &>::value, "");
  288. static_assert(!detail::_traits::is_const_lvalue<GBoxedExample &>::value, "");
  289. }
  290. // test helper
  291. template<typename T>
  292. int
  293. refcount(T *obj)
  294. {
  295. return (((GObject *)(obj))->ref_count);
  296. }
  297. void
  298. test_wrap()
  299. {
  300. { // plain boxed
  301. CBExample *ex = gi_cpp_cbexample_new();
  302. auto cb = wrap(ex, transfer_full);
  303. assert(cb.gobj_() == ex);
  304. auto cb2 = wrap(ex, transfer_none);
  305. assert(cb2 == cb);
  306. assert(cb.gobj_() == cb2.gobj_());
  307. auto cb3 = cb2;
  308. assert(cb3 == cb2);
  309. assert(cb2.gobj_() == cb3.gobj_());
  310. auto cbn = CBoxedExample::new_();
  311. assert(cbn.gobj_() != nullptr);
  312. assert(cbn.gobj_()->data == 0);
  313. // a peek
  314. auto ex2 = unwrap(cbn, transfer_none);
  315. assert(ex2 == cbn.gobj_());
  316. // a fresh copy
  317. auto ex3 = unwrap(std::move(cbn), transfer_full);
  318. assert(ex3 != cbn.gobj_());
  319. gi_cpp_cbexample_free(ex3);
  320. cbn = CBoxedExample();
  321. assert(cbn == nullptr);
  322. assert(cbn.gobj_() == nullptr);
  323. assert(!cbn);
  324. auto ex4 = unwrap(std::move(cbn), transfer_full);
  325. assert(ex4 == nullptr);
  326. // various basic operations
  327. CBoxedExample cbm(std::move(cbn));
  328. cbm = std::move(cbn);
  329. assert(!cbn);
  330. std::swap(cbm, cbn);
  331. assert(!cbm);
  332. // compile check
  333. CBoxedExample f = CBoxedExample::new_();
  334. f = nullptr;
  335. // ref
  336. CBoxedExampleRef r(f);
  337. assert(r.gobj_() == f.gobj_());
  338. r = nullptr;
  339. assert(r.gobj_() == nullptr);
  340. r = f;
  341. assert(r.gobj_() == f.gobj_());
  342. // ref wrap
  343. auto r2 = wrap(ex, transfer_none);
  344. static_assert(std::is_same<decltype(r2), CBoxedExampleRef>::value, "");
  345. r = r2;
  346. assert(r.gobj_() == ex);
  347. auto ro = unwrap(r, transfer_none);
  348. auto ri = unwrap(r, transfer_none);
  349. assert(ri == ro);
  350. }
  351. { // similarly so gboxed
  352. GBExample *exc = gi_cpp_gbexample_new();
  353. GBoxedExample w1 = wrap(exc, transfer_full);
  354. GBoxedExample w2 = std::move(w1);
  355. assert(!w1);
  356. assert(w2.gobj_() == exc);
  357. GBoxedExample w3 = w2.copy_();
  358. assert(w3);
  359. assert(w3 != w2);
  360. assert(w3.gobj_() != w2.gobj_());
  361. w3 = nullptr;
  362. // ref
  363. GBoxedExampleRef r(w2);
  364. assert(r.gobj_() == w2.gobj_());
  365. r = nullptr;
  366. assert(r.gobj_() == nullptr);
  367. r = w2;
  368. assert(r.gobj_() == w2.gobj_());
  369. // ref wrap
  370. r = wrap(exc, transfer_none);
  371. assert(r.gobj_() == exc);
  372. auto ro = unwrap(r, transfer_none);
  373. auto ri = unwrap(r, transfer_none);
  374. assert(ri == ro);
  375. auto rc = r.copy_();
  376. assert(rc != r);
  377. #if BOXED_COPY
  378. {
  379. GBoxedExample ww{w3};
  380. ww = w3;
  381. r = w3;
  382. ww = r;
  383. ww = std::move(r);
  384. }
  385. #endif
  386. }
  387. { // string
  388. const gchar *str{};
  389. std::string s1 = wrap(str, transfer_none);
  390. assert(s1.empty());
  391. str = "TEST";
  392. std::string s2 = wrap(str, transfer_none);
  393. assert(s2 == str);
  394. auto *cs = unwrap(s2, transfer_none);
  395. assert(g_strcmp0(cs, str) == 0);
  396. // now something we should be able to free
  397. cs = unwrap(s2, transfer_full);
  398. g_free((gpointer)cs);
  399. // unwrap empty optional
  400. const std::string &emptytest = "";
  401. auto cempty = unwrap(emptytest, transfer_none);
  402. assert(*cempty == 0);
  403. auto ocempty = unwrap(
  404. static_cast<const detail::optional_string &>(emptytest), transfer_none);
  405. assert(ocempty == nullptr);
  406. }
  407. { // some more plain cases
  408. wrap(5);
  409. unwrap(5, transfer_none);
  410. const double ex = 5.0;
  411. auto w = wrap(ex);
  412. auto ex2 = unwrap(w);
  413. assert(ex == ex2);
  414. CEnum ec{};
  415. CppEnum ecpp{};
  416. ecpp = wrap(ec);
  417. unwrap(ecpp, transfer_none);
  418. }
  419. { // object
  420. CDerived *ob = gi_cpp_example_new();
  421. assert(refcount(ob) == 1);
  422. auto wo = wrap(ob, transfer_none);
  423. assert(refcount(ob) == 2);
  424. assert(wo.gobj_() == ob);
  425. {
  426. auto wo2 = wo;
  427. assert(wo2 == wo);
  428. assert(wo2.gobj_() == ob);
  429. assert(refcount(ob) == 3);
  430. // cast to own type should work fine
  431. auto wo3 = object_cast<Derived>(wo2);
  432. assert(wo3);
  433. assert(refcount(ob) == 4);
  434. }
  435. assert(refcount(ob) == 2);
  436. auto ob2 = unwrap(wo, transfer_none);
  437. assert(ob2 == ob);
  438. assert(refcount(ob) == 2);
  439. ob2 = unwrap(wo, transfer_full);
  440. assert(ob2 == ob);
  441. assert(refcount(ob) == 3);
  442. g_object_unref(ob2);
  443. ob2 = nullptr;
  444. assert(refcount(ob) == 2);
  445. // no change for full transfer
  446. auto wo2 = wrap(ob, transfer_full);
  447. assert(wo2.gobj_() == ob);
  448. assert(refcount(ob) == 2);
  449. // compensate
  450. g_object_ref(ob);
  451. wo2 = Derived();
  452. assert(wo2.gobj_() == nullptr);
  453. assert(refcount(ob) == 2);
  454. wo2 = std::move(wo);
  455. assert(wo.gobj_() == nullptr);
  456. assert(wo2.gobj_() == ob);
  457. wo2 = wo;
  458. assert(refcount(ob) == 1);
  459. g_object_unref(ob);
  460. Derived wo3(wo2);
  461. if (wo3)
  462. wo3 = nullptr;
  463. }
  464. {
  465. // object creation
  466. Derived ob = GObject_::Object::new_<Derived>();
  467. ob = GObject_::Object::new_<Derived>(
  468. NAME_NUMBER, (int)5, NAME_PRESENT, true);
  469. assert(ob.property_number().get() == 5);
  470. assert(ob.property_present().get() == true);
  471. Derived ob2 = GObject_::Object::new_<Derived>();
  472. std::swap(ob2, ob);
  473. }
  474. {
  475. // paramspec
  476. auto pspec = GObject_::ParamSpec::new_<int>("p", "p", "p", 0, 10);
  477. // is otherwise similar to property and is tested there further
  478. }
  479. { // wrap_to
  480. int x = 5;
  481. auto y = wrap_to<int>(x, transfer_none);
  482. assert(x == y);
  483. wrap_to<std::string>("x", transfer_none);
  484. }
  485. { // unwrap_maybe_float
  486. CDerived *ob = gi_cpp_example_new();
  487. assert(refcount(ob) == 1);
  488. auto wo = wrap(ob, transfer_full);
  489. assert(refcount(ob) == 1);
  490. CDerived *uwo = detail::unwrap_maybe_float(std::move(wo), transfer_none);
  491. assert(uwo == ob);
  492. assert(!wo);
  493. assert(refcount(ob) == 1);
  494. assert(g_object_is_floating(ob));
  495. wo = wrap(ob, transfer_none);
  496. assert(refcount(ob) == 1);
  497. assert(!g_object_is_floating(ob));
  498. uwo = detail::unwrap_maybe_float(std::move(wo), transfer_full);
  499. assert(!wo);
  500. assert(uwo == ob);
  501. assert(refcount(ob) == 1);
  502. wo = wrap(ob, transfer_full);
  503. assert(refcount(ob) == 1);
  504. // wrapper will clean up
  505. GBExample *exc = gi_cpp_gbexample_new();
  506. GBoxedExample w1 = wrap(exc, transfer_full);
  507. GBExample *uw1 = detail::unwrap_maybe_float(std::move(w1), transfer_full);
  508. assert(!w1);
  509. assert(uw1 == exc);
  510. w1 = wrap(exc, transfer_full);
  511. // wrapper will clean up
  512. }
  513. { // compile checks on cs_ptr helper
  514. using Object = gi::repository::GObject::Object;
  515. auto g = [](Object) {};
  516. auto f = [&g](const gi::cs_ptr<Object> &ob) {
  517. ob->handler_block(0);
  518. Object obx = ob;
  519. auto y = ob;
  520. auto x = [y]() { y->handler_block(1); };
  521. g(ob);
  522. };
  523. Object ob{};
  524. if (false)
  525. f(ob);
  526. }
  527. }
  528. using gi::detail::Collection;
  529. using gi::detail::CollectionHolder;
  530. namespace collection_helpers
  531. {
  532. struct LVHandler
  533. {
  534. template<typename T>
  535. T &f(T &t)
  536. {
  537. return t;
  538. }
  539. };
  540. struct RVHandler
  541. {
  542. template<typename T>
  543. T &&f(T &t)
  544. {
  545. return std::move(t);
  546. }
  547. };
  548. template<typename ListType, typename T, typename Transfer>
  549. using CollectionProxy =
  550. Collection<ListType, typename traits::ctype<T>::type, Transfer>;
  551. template<typename ListType, typename T, typename Transfer>
  552. using CollectionHolderProxy =
  553. CollectionHolder<ListType, typename traits::ctype<T>::type, Transfer>;
  554. std::string
  555. get_value(const std::string &x)
  556. {
  557. return x;
  558. }
  559. std::string
  560. get_value(const gi::cstring &x)
  561. {
  562. return x;
  563. }
  564. template<typename T>
  565. auto
  566. get_value(const T &x) -> decltype(unwrap(x, transfer_none))
  567. {
  568. return unwrap(const_cast<T &>(x), transfer_none);
  569. }
  570. template<template<typename, typename, typename> class CT = CollectionProxy,
  571. typename CppType, typename Transfer, typename LVRHandler>
  572. void
  573. check_collection(std::vector<CppType> &&v, const Transfer &t, LVRHandler h)
  574. {
  575. // collect size
  576. const auto VS = v.size();
  577. // and (internal) value for later check
  578. using VT = decltype(get_value(v.front()));
  579. std::vector<VT> baseline;
  580. auto get_values = [&v] {
  581. decltype(baseline) out;
  582. for (auto &val : v)
  583. out.push_back(get_value(val));
  584. return out;
  585. };
  586. baseline = get_values();
  587. auto do_check = [&get_values, &baseline]() {
  588. auto current = get_values();
  589. assert(current == baseline);
  590. };
  591. auto check_list_it = [&baseline](auto &list) {
  592. decltype(baseline) current;
  593. int cnt = 0;
  594. for (auto &e : list) {
  595. // e should be const & iff Transfer none
  596. using el_type = typename std::remove_reference<decltype(e)>::type;
  597. static_assert(std::is_const<el_type>::value ==
  598. std::is_same<Transfer, transfer_none_t>::value,
  599. "");
  600. assert(e);
  601. ++cnt;
  602. current.push_back(get_value(e));
  603. }
  604. assert(cnt == int(baseline.size()));
  605. assert(current == baseline);
  606. cnt = 0;
  607. current.clear();
  608. const auto &clist = list;
  609. for (auto &e : clist) {
  610. // e should always be const & here
  611. using el_type = typename std::remove_reference<decltype(e)>::type;
  612. static_assert(std::is_const<el_type>::value, "");
  613. assert(e);
  614. ++cnt;
  615. current.push_back(get_value(e));
  616. }
  617. assert(cnt == int(baseline.size()));
  618. assert(current == baseline);
  619. // assign from non-const to const
  620. auto cb = clist.begin();
  621. cb = list.begin();
  622. assert(!cnt || *cb);
  623. };
  624. // various trips through variations
  625. CT<::GList, CppType, Transfer> l{h.f(v)};
  626. static constexpr bool is_sub = std::is_same<decltype(l),
  627. CollectionHolderProxy<::GList, CppType, Transfer>>::value;
  628. static_assert(is_sub || (sizeof(l) == sizeof(::GList *)), "");
  629. check_list_it(l);
  630. v = std::move(l);
  631. assert(!l);
  632. assert(v.size() == VS);
  633. do_check();
  634. l = h.f(v);
  635. v = std::move(l);
  636. assert(!l);
  637. assert(v.size() == VS);
  638. do_check();
  639. CT<::GSList, CppType, Transfer> sl{h.f(v)};
  640. static_assert(is_sub || (sizeof(l) == sizeof(::GSList *)), "");
  641. check_list_it(sl);
  642. v = std::move(sl);
  643. assert(!sl);
  644. assert(v.size() == VS);
  645. do_check();
  646. sl = h.f(v);
  647. v = std::move(sl);
  648. assert(!sl);
  649. assert(v.size() == VS);
  650. do_check();
  651. CT<::GPtrArray, CppType, Transfer> pa{h.f(v)};
  652. static_assert(is_sub || (sizeof(l) == sizeof(::GPtrArray *)), "");
  653. check_list_it(pa);
  654. v = std::move(pa);
  655. assert(!pa);
  656. assert(v.size() == VS);
  657. do_check();
  658. pa = h.f(v);
  659. v = std::move(pa);
  660. assert(!pa);
  661. assert(v.size() == VS);
  662. do_check();
  663. CT<DSpan, CppType, Transfer> da{h.f(v)};
  664. check_list_it(da);
  665. v = std::move(da);
  666. assert(!da);
  667. assert(v.size() == VS);
  668. do_check();
  669. da = h.f(v);
  670. v = std::move(da);
  671. assert(!da);
  672. assert(v.size() == VS);
  673. do_check();
  674. CT<ZTSpan, CppType, Transfer> za{h.f(v)};
  675. check_list_it(za);
  676. v = std::move(za);
  677. assert(!za);
  678. za = h.f(v);
  679. v = std::move(za);
  680. assert(!za);
  681. assert(v.size() == VS);
  682. do_check();
  683. l = h.f(v);
  684. // temporarily use a separate sv
  685. // (so v can keep its elements alive, e.g. std::string case)
  686. std::vector<CppType> sv;
  687. sv.resize(VS);
  688. std::move(l).move_to(sv.data());
  689. assert(!l);
  690. v = std::move(sv);
  691. sv.clear();
  692. do_check();
  693. // in case of holder; l has ownership here (so none wrap/unwrap below ok)
  694. l = h.f(v);
  695. auto lu = unwrap(std::move(l), t);
  696. assert(!l || !t.value);
  697. // last part; always need to wrap to a basic wrapper
  698. using WrapTypeL = CollectionProxy<::GList, CppType, Transfer>;
  699. auto ln = wrap_to<WrapTypeL>(lu, t);
  700. assert(lu == ln.gobj_());
  701. v = std::move(ln);
  702. do_check();
  703. pa = h.f(v);
  704. auto pau = unwrap(std::move(pa), t);
  705. assert(!pa || !t.value);
  706. // ref'ed case, so it can always take ownership
  707. using WrapTypeA = CollectionProxy<::GPtrArray, CppType, Transfer>;
  708. auto pan = wrap_to<WrapTypeA>(pau, t);
  709. assert(pau == pan.gobj_());
  710. }
  711. template<template<typename, typename, typename> class CT = CollectionProxy,
  712. typename CppKey, typename CppType, typename Transfer, typename LVRHandler>
  713. void
  714. check_collection(std::map<CppKey, CppType> &&v, const Transfer &t, LVRHandler h)
  715. {
  716. const auto VS = v.size();
  717. using VT = decltype(get_value(v.begin()->second));
  718. std::map<CppKey, VT> baseline;
  719. auto get_values = [](auto &c) {
  720. decltype(baseline) out;
  721. for (auto &val : c)
  722. out[val.first] = get_value(val.second);
  723. return out;
  724. };
  725. baseline = get_values(v);
  726. auto do_check = [&get_values, &baseline](auto &c) {
  727. auto current = get_values(c);
  728. assert(current == baseline);
  729. };
  730. auto check_map_it = [&baseline](auto &list) {
  731. decltype(baseline) current;
  732. int cnt = 0;
  733. for (auto &e : list) {
  734. assert(e.first);
  735. assert(e.second);
  736. ++cnt;
  737. current[get_value(e.first)] = get_value(e.second);
  738. }
  739. assert(cnt == int(baseline.size()));
  740. assert(current == baseline);
  741. cnt = 0;
  742. current.clear();
  743. const auto &clist = list;
  744. for (auto &e : clist) {
  745. assert(e.first);
  746. assert(e.second);
  747. ++cnt;
  748. current[get_value(e.first)] = get_value(e.second);
  749. }
  750. assert(cnt == int(baseline.size()));
  751. assert(current == baseline);
  752. };
  753. CT<::GHashTable, std::pair<CppKey, CppType>, Transfer> l{h.f(v)};
  754. static constexpr bool is_sub = std::is_same<decltype(l),
  755. CollectionHolderProxy<::GHashTable, std::pair<CppKey, CppType>,
  756. Transfer>>::value;
  757. static_assert(is_sub || (sizeof(l) == sizeof(::GHashTable *)), "");
  758. check_map_it(l);
  759. v = std::move(l);
  760. assert(!l);
  761. assert(v.size() == VS);
  762. do_check(v);
  763. l = h.f(v);
  764. v = std::move(l);
  765. assert(!l);
  766. assert(v.size() == VS);
  767. do_check(v);
  768. l = h.f(v);
  769. std::unordered_map<std::string, CppType> w;
  770. w = std::move(l);
  771. assert(!l);
  772. assert(w.size() == VS);
  773. do_check(w);
  774. // in case of holder; l has ownership here (so none wrap/unwrap below ok)
  775. l = h.f(w);
  776. auto lu = unwrap(std::move(l), t);
  777. assert(!l || !t.value);
  778. // last part; always need to wrap to a basic wrapper
  779. using WrapType =
  780. CollectionProxy<::GHashTable, std::pair<CppKey, CppType>, Transfer>;
  781. auto ln = wrap_to<WrapType>(lu, t);
  782. assert(lu == ln.gobj_());
  783. }
  784. template<typename ListType, typename Transfer>
  785. static void
  786. check_collection_null()
  787. { // check nullptr cases
  788. // type not relevant in these cases
  789. using BT = CDerived *;
  790. std::vector<Derived> bv;
  791. Transfer t;
  792. {
  793. auto ln =
  794. wrap_to<Collection<ListType, BT, Transfer>>((ListType *)(nullptr), t);
  795. assert(!ln);
  796. ln = nullptr;
  797. assert(!ln);
  798. bv = std::move(ln);
  799. assert(bv.empty());
  800. }
  801. }
  802. } // namespace collection_helpers
  803. void
  804. test_collection()
  805. {
  806. using namespace collection_helpers;
  807. auto make_object = [] { return wrap(gi_cpp_example_new(), transfer_full); };
  808. auto make_box = []() -> GBoxedExample {
  809. return wrap(gi_cpp_gbexample_new(), transfer_full);
  810. };
  811. { // init list construction
  812. CollectionProxy<::GPtrArray, Derived, transfer_full_t> coll_pa{
  813. make_object(), make_object()};
  814. assert(coll_pa.size() == 2);
  815. CollectionProxy<gi::DSpan, int, transfer_full_t> coll_da{2, 3, 4};
  816. assert(coll_da.size() == 3);
  817. #if 0
  818. // will not work, since not copyable
  819. CollectionProxy<gi::ZTSpan, GBoxedExample, transfer_full_t> coll_za{
  820. make_box()};
  821. assert(coll_za.size() == 1);
  822. // but neither will the following
  823. std::vector<std::unique_ptr<int>> x{std::make_unique<int>(5)};
  824. #endif
  825. }
  826. // full
  827. { // object
  828. std::vector<Derived> v{make_object(), make_object()};
  829. check_collection(std::move(v), transfer_full, LVHandler());
  830. // map
  831. std::map<std::string, Derived> m{
  832. {"x", make_object()}, {"y", make_object()}};
  833. check_collection(std::move(m), transfer_full, LVHandler());
  834. }
  835. { // non-copyable boxed
  836. std::vector<GBoxedExample> v;
  837. v.push_back(make_box());
  838. v.push_back(make_box());
  839. check_collection(std::move(v), transfer_full, RVHandler());
  840. // map
  841. std::map<std::string, GBoxedExample> m;
  842. m["x"] = make_box();
  843. m["y"] = make_box();
  844. check_collection(std::move(m), transfer_full, RVHandler());
  845. }
  846. { // string
  847. std::vector<std::string> v{"foo", "bar"};
  848. check_collection(std::move(v), transfer_full, LVHandler());
  849. // map
  850. std::map<std::string, std::string> m{{"x", "foo"}, {"y", "bar"}};
  851. check_collection(std::move(m), transfer_full, LVHandler());
  852. }
  853. { // cstring
  854. std::vector<gi::cstring> v{"foo", "bar"};
  855. check_collection(std::move(v), transfer_full, LVHandler());
  856. // map
  857. std::map<gi::cstring, gi::cstring> m{{"x", "foo"}, {"y", "bar"}};
  858. check_collection(std::move(m), transfer_full, LVHandler());
  859. }
  860. { // plain
  861. std::vector<int> v{2, 3};
  862. auto w = v;
  863. Collection<gi::DSpan, int, transfer_full_t> da{v.data(), v.size()};
  864. v = std::move(da);
  865. assert(!da);
  866. assert(v == w);
  867. da = v;
  868. std::move(da).move_to(v.data());
  869. assert(v == w);
  870. }
  871. // container
  872. { // object
  873. std::vector<Derived> v{make_object(), make_object()};
  874. // hold item ownership as they are moved about
  875. auto t = v;
  876. check_collection(std::move(v), transfer_container, LVHandler());
  877. // map
  878. std::map<std::string, Derived> m{
  879. {"x", make_object()}, {"y", make_object()}};
  880. auto tm = m;
  881. check_collection(std::move(m), transfer_container, LVHandler());
  882. }
  883. { // copyable ref boxed
  884. std::vector<GBoxedExample> v;
  885. v.push_back(make_box());
  886. v.push_back(make_box());
  887. std::vector<GBoxedExampleRef> w{v.begin(), v.end()};
  888. check_collection(std::move(w), transfer_container, LVHandler());
  889. // map
  890. std::map<std::string, GBoxedExampleRef> m{
  891. {"x", v.front()}, {"y", v.back()}};
  892. check_collection(std::move(m), transfer_container, LVHandler());
  893. }
  894. { // string
  895. std::vector<std::string> v{"foo", "bar"};
  896. check_collection(std::move(v), transfer_container, LVHandler());
  897. // map
  898. std::map<std::string, std::string> m{{"x", "foo"}, {"y", "bar"}};
  899. check_collection(std::move(m), transfer_container, LVHandler());
  900. }
  901. { // cstring
  902. std::vector<gi::cstring> v{"foo", "bar"};
  903. std::vector<gi::cstring_v> w{v.begin(), v.end()};
  904. check_collection(std::move(w), transfer_container, LVHandler());
  905. // map
  906. std::map<gi::cstring, gi::cstring_v> m{{"x", v.front()}, {"y", v.back()}};
  907. check_collection(std::move(m), transfer_container, LVHandler());
  908. }
  909. { // plain
  910. std::vector<CppEnum> v{CppEnum::VALUE_0, CppEnum::VALUE_1};
  911. auto w = v;
  912. CollectionProxy<gi::DSpan, CppEnum, transfer_container_t> da{
  913. v.data(), v.size()};
  914. v = std::move(da);
  915. assert(!da);
  916. assert(v == w);
  917. da = v;
  918. std::move(da).move_to(v.data());
  919. assert(v == w);
  920. }
  921. // none
  922. {
  923. static_assert(!std::is_copy_constructible<
  924. CollectionHolder<::GList, CDerived *>>::value,
  925. "");
  926. static_assert(std::is_move_constructible<
  927. CollectionHolder<::GList, CDerived *>>::value,
  928. "");
  929. }
  930. // parameter helper should behave much as a dynamic container transfer
  931. { // object
  932. std::vector<Derived> v{make_object(), make_object()};
  933. // hold item ownership as they are moved about
  934. auto t = v;
  935. check_collection<CollectionHolderProxy>(
  936. std::move(v), transfer_none, LVHandler());
  937. // map
  938. std::map<std::string, Derived> m{
  939. {"x", make_object()}, {"y", make_object()}};
  940. auto tm = m;
  941. check_collection<CollectionHolderProxy>(
  942. std::move(m), transfer_none, LVHandler());
  943. }
  944. { // copyable ref boxed
  945. std::vector<GBoxedExample> v;
  946. v.push_back(make_box());
  947. v.push_back(make_box());
  948. std::vector<GBoxedExampleRef> w{v.begin(), v.end()};
  949. check_collection<CollectionHolderProxy>(
  950. std::move(w), transfer_none, LVHandler());
  951. // map
  952. std::map<std::string, GBoxedExampleRef> m{
  953. {"x", v.front()}, {"y", v.back()}};
  954. check_collection<CollectionHolderProxy>(
  955. std::move(m), transfer_none, LVHandler());
  956. }
  957. { // string
  958. std::vector<std::string> v{"foo", "bar"};
  959. check_collection<CollectionHolderProxy>(
  960. std::move(v), transfer_none, LVHandler());
  961. // map
  962. std::map<std::string, std::string> m{{"x", "foo"}, {"y", "bar"}};
  963. check_collection<CollectionHolderProxy>(
  964. std::move(m), transfer_none, LVHandler());
  965. }
  966. { // cstring
  967. std::vector<gi::cstring> v{"foo", "bar"};
  968. std::vector<gi::cstring_v> w{v.begin(), v.end()};
  969. check_collection<CollectionHolderProxy>(
  970. std::move(w), transfer_none, LVHandler());
  971. // map
  972. std::map<gi::cstring, gi::cstring_v> m{{"x", v.front()}, {"y", v.back()}};
  973. check_collection<CollectionHolderProxy>(
  974. std::move(m), transfer_none, LVHandler());
  975. }
  976. // some other array cases
  977. {
  978. std::array<const char *, 2> sa{{"x", "y"}};
  979. Collection<gi::DSpan, char *, transfer_none_t> sc;
  980. sc = wrap_to<decltype(sc)>(sa.data(), sa.size(), transfer_none);
  981. assert(sc.gobj_() == sa.data());
  982. auto usa = unwrap(sc, transfer_none);
  983. assert(usa == sa.data());
  984. }
  985. {
  986. std::array<int, 2> a{3, 4};
  987. CollectionHolderProxy<gi::DSpan, int, transfer_none_t> ac{
  988. a.data(), a.size()};
  989. // optimization applies
  990. assert(ac.gobj_() == a.data());
  991. assert(ac._size() == a.size());
  992. auto rc = ac.gobj_();
  993. auto uac = unwrap(std::move(ac), transfer_none);
  994. assert(rc == uac);
  995. for (int i : {0, 1})
  996. assert(uac[i] == a[i]);
  997. ac = wrap_to<decltype(ac)>(uac, a.size(), transfer_none);
  998. assert(ac.gobj_() == uac);
  999. }
  1000. {
  1001. std::array<int, 2> a{5, 6};
  1002. // allocate new array
  1003. Collection<gi::DSpan, int, transfer_full_t> ac{a.data(), a.size()};
  1004. assert(ac.gobj_() != a.data());
  1005. assert(ac._size() == a.size());
  1006. auto rc = ac.gobj_();
  1007. auto uac = unwrap(std::move(ac), transfer_full);
  1008. // now owned by uac above
  1009. assert(!ac);
  1010. assert(rc == uac);
  1011. for (int i : {0, 1})
  1012. assert(uac[i] == a[i]);
  1013. // transfer full to ac again
  1014. ac = wrap_to<decltype(ac)>(uac, a.size(), transfer_full);
  1015. assert(ac.gobj_() == uac);
  1016. }
  1017. { // check GHashTable transfer_none hack
  1018. using VT = std::pair<char *, char *>;
  1019. using TT = gi::CollectionParameter<::GHashTable, VT, transfer_none_t>;
  1020. static_assert(
  1021. std::is_same<TT,
  1022. gi::detail::Collection<::GHashTable, VT, transfer_full_t>>::value,
  1023. "");
  1024. // should work for refcnt case
  1025. TT t;
  1026. unwrap(t, transfer_none);
  1027. // also check null handling
  1028. assert(!t);
  1029. t = nullptr;
  1030. assert(!t);
  1031. std::map<std::string, std::string> m = std::move(t);
  1032. assert(m.empty());
  1033. }
  1034. { // nullptr handling
  1035. check_collection_null<::GList, transfer_full_t>();
  1036. check_collection_null<::GList, transfer_none_t>();
  1037. check_collection_null<::GSList, transfer_full_t>();
  1038. check_collection_null<::GSList, transfer_none_t>();
  1039. check_collection_null<::GPtrArray, transfer_full_t>();
  1040. check_collection_null<::GPtrArray, transfer_none_t>();
  1041. // array cases
  1042. using BT = int;
  1043. std::vector<int> bv;
  1044. {
  1045. auto ln = wrap_to<Collection<ZTSpan, BT, transfer_full_t>>(
  1046. (BT *)(nullptr), transfer_full);
  1047. assert(!ln);
  1048. ln = nullptr;
  1049. assert(!ln);
  1050. bv = std::move(ln);
  1051. assert(bv.empty());
  1052. }
  1053. {
  1054. auto ln = wrap_to<Collection<DSpan, BT, transfer_none_t>>(
  1055. (BT *)(nullptr), transfer_none);
  1056. assert(!ln);
  1057. ln = nullptr;
  1058. assert(!ln);
  1059. bv = std::move(ln);
  1060. assert(bv.empty());
  1061. }
  1062. }
  1063. { // transition to other transfer types
  1064. auto check_equal = [](auto &l1, auto &l2) {
  1065. assert(!l1.empty());
  1066. assert(!l2.empty());
  1067. assert(l1.front());
  1068. assert(l2.front());
  1069. auto it1 = l1.begin();
  1070. auto it2 = l2.begin();
  1071. for (; it1 != l1.end() && it2 != l2.end(); ++it1, ++it2) {
  1072. assert(*it1 == *it2);
  1073. }
  1074. };
  1075. CollectionProxy<::GList, GBoxedExample, transfer_full_t> lf;
  1076. lf.push_back(make_box());
  1077. lf.push_back(make_box());
  1078. assert(!lf.empty());
  1079. assert(++lf.begin() != lf.end());
  1080. assert(++(++lf.begin()) == lf.end());
  1081. // generic container creation
  1082. CollectionProxy<::GList, GBoxedExample, transfer_container_t> lc{lf};
  1083. check_equal(lf, lc);
  1084. // special case to none
  1085. CollectionProxy<::GList, GBoxedExample, transfer_none_t> ln{lf};
  1086. check_equal(lf, ln);
  1087. // also this way
  1088. lc = lf;
  1089. check_equal(lf, lc);
  1090. ln = lc;
  1091. check_equal(ln, lc);
  1092. }
  1093. auto uw = [](const auto &obj) { return unwrap(obj, transfer_none); };
  1094. auto check_list = [&uw](auto &lf, auto factory) {
  1095. lf.push_back(factory());
  1096. assert(!lf.empty());
  1097. auto p = uw(lf.front());
  1098. lf.push_back(factory());
  1099. assert(uw(lf.front()) == p);
  1100. assert(std::next(lf.begin()) != lf.end());
  1101. assert(std::next(lf.begin(), 2) == lf.end());
  1102. lf.push_front(factory());
  1103. assert(uw(lf.front()) != p);
  1104. lf.pop_front();
  1105. assert(uw(lf.front()) == p);
  1106. lf.pop_back();
  1107. assert(uw(lf.front()) == p);
  1108. lf.pop_back();
  1109. assert(lf.empty());
  1110. lf.push_front(factory());
  1111. assert(!lf.empty());
  1112. lf.pop_front();
  1113. assert(lf.empty());
  1114. lf.push_front(factory());
  1115. assert(!lf.empty());
  1116. lf.clear();
  1117. assert(lf.empty());
  1118. auto it = lf.insert(lf.begin(), factory());
  1119. p = uw(lf.front());
  1120. assert(it == lf.begin());
  1121. it = lf.insert(lf.begin(), factory());
  1122. assert(it == lf.begin());
  1123. assert(uw(lf.front()) != p);
  1124. lf.insert(lf.end(), factory());
  1125. assert(uw(*std::next(lf.begin())) == p);
  1126. it = std::next(lf.begin());
  1127. while (it != lf.end())
  1128. it = lf.erase(it);
  1129. assert(std::next(lf.begin()) == lf.end());
  1130. it = lf.erase(lf.begin());
  1131. assert(it == lf.end());
  1132. assert(lf.empty());
  1133. lf.push_front(factory());
  1134. typename std::remove_reference<decltype(lf)>::type lfo;
  1135. lf.swap(lfo);
  1136. assert(lf.empty());
  1137. assert(!lfo.empty());
  1138. lfo.pop_front();
  1139. assert(lfo.empty());
  1140. };
  1141. auto check_array = [&uw](auto &l, auto factory) {
  1142. l.clear();
  1143. l.push_back(factory());
  1144. auto p = uw(l.front());
  1145. assert(p);
  1146. assert(l.data()[0] == l[0]);
  1147. assert(l.data()[0] == l.at(0));
  1148. assert(l.data()[0] == l.front());
  1149. assert(l.at(0));
  1150. l.resize(10);
  1151. assert(l.size() == 10);
  1152. assert(!l.back());
  1153. l.resize(1);
  1154. assert(l.size() == 1);
  1155. assert(l.back() == l.front());
  1156. assert(uw(l.back()) == p);
  1157. };
  1158. { // check common operations on lists
  1159. CollectionProxy<::GList, GBoxedExample, transfer_full_t> lf;
  1160. check_list(lf, make_box);
  1161. // special list part
  1162. lf.clear();
  1163. lf.push_back(make_box());
  1164. lf.push_back(make_box());
  1165. auto p = lf.front().gobj_();
  1166. lf.reverse();
  1167. assert(lf.front().gobj_() != p);
  1168. lf.reverse();
  1169. assert(lf.front().gobj_() == p);
  1170. // ptrarray
  1171. CollectionProxy<::GPtrArray, GBoxedExample, transfer_full_t> pa;
  1172. check_list(pa, make_box);
  1173. check_array(pa, make_box);
  1174. // dyn array
  1175. CollectionProxy<gi::DSpan, GBoxedExample, transfer_full_t> da;
  1176. check_list(da, make_box);
  1177. check_array(da, make_box);
  1178. // zt array
  1179. CollectionProxy<gi::ZTSpan, GBoxedExample, transfer_full_t> za;
  1180. check_list(za, make_box);
  1181. check_array(za, make_box);
  1182. // check ZT
  1183. za.clear();
  1184. za.push_back(make_box());
  1185. za.push_back(make_box());
  1186. assert(*za.end() == nullptr);
  1187. p = za.front().gobj_();
  1188. // auto d = za.data();
  1189. auto cap = za.capacity();
  1190. za.reserve(5 * cap);
  1191. assert(za.capacity() >= 5 * cap);
  1192. // NOTE new alloc might match old alloc
  1193. // assert(d != za.data());
  1194. assert(za.front().gobj_() == p);
  1195. // plain array
  1196. CollectionProxy<gi::DSpan, int, transfer_full_t> pda;
  1197. int gen = 1;
  1198. auto make_int = [&gen]() { return ++gen; };
  1199. check_list(pda, make_int);
  1200. check_array(pda, make_int);
  1201. }
  1202. { // map operations
  1203. Collection<::GHashTable, std::pair<char *, GBExample *>, transfer_full_t>
  1204. mf;
  1205. assert(mf.empty());
  1206. const char *KEY1 = "key1";
  1207. const char *KEY2 = "key2";
  1208. auto v1 = make_box();
  1209. auto v2 = make_box();
  1210. auto p1 = uw(v1);
  1211. auto p2 = uw(v2);
  1212. auto ret = mf.replace(KEY1, std::move(v1));
  1213. assert(ret);
  1214. assert(mf.size() == 1);
  1215. ret = mf.replace(KEY2, std::move(v2));
  1216. assert(ret);
  1217. assert(mf.size() == 2);
  1218. assert(std::next(std::next(mf.begin())) == mf.end());
  1219. assert(mf.find("blah") == mf.end());
  1220. assert(!mf.lookup("blah"));
  1221. auto it = mf.find(KEY1);
  1222. assert(it != mf.end());
  1223. assert(uw(it->second) == p1);
  1224. it = mf.find(KEY2);
  1225. assert(it != mf.end());
  1226. assert(uw(it->second) == p2);
  1227. // transfer to variant container
  1228. // generic to container
  1229. Collection<::GHashTable, std::pair<char *, GBExample *>,
  1230. transfer_container_t>
  1231. mc{mf};
  1232. assert(mc.size() == mf.size());
  1233. mc.clear();
  1234. assert(mc.empty());
  1235. mc = mf;
  1236. assert(mc.size() == mf.size());
  1237. assert(uw(mc.lookup(KEY2)) == p2);
  1238. // always down to none
  1239. Collection<::GHashTable, std::pair<char *, GBExample *>, transfer_none_t>
  1240. mn{mf};
  1241. assert(mn.size() == mf.size());
  1242. assert(uw(mn.lookup(KEY2)) == p2);
  1243. mn = mc;
  1244. assert(mn.size() == mf.size());
  1245. assert(uw(mn.lookup(KEY1)) == p1);
  1246. }
  1247. }
  1248. namespace string_helpers
  1249. {
  1250. struct MyView
  1251. {
  1252. const char *c_str() const { return nullptr; }
  1253. size_t size() const { return 0; }
  1254. };
  1255. struct MyViewCustom
  1256. {};
  1257. using cstr = detail::cstring;
  1258. using cstrv = detail::cstring_v;
  1259. template<typename StringType>
  1260. void
  1261. check_string()
  1262. {
  1263. constexpr bool is_view = std::is_same<cstrv, StringType>::value;
  1264. // construct
  1265. const char *STR = "ab";
  1266. StringType cs(STR);
  1267. assert((cs.data() == STR) == is_view);
  1268. std::string s("cd");
  1269. StringType tcs(s);
  1270. cs = s;
  1271. assert((cs.data() == s.data()) == is_view);
  1272. cstrv csv(cs);
  1273. assert(csv.data() == cs.data());
  1274. tcs = std::move(cs);
  1275. assert(tcs.data() == csv.data());
  1276. cs = std::move(tcs);
  1277. assert(cs.data() == csv.data());
  1278. // ops
  1279. for (auto &c : cs)
  1280. assert(c);
  1281. assert(cs.size() == s.size());
  1282. assert(cs.length() == cs.size());
  1283. assert(!cs.empty());
  1284. assert(cs.at(0) == s.at(0));
  1285. assert(cs[0] == s[0]);
  1286. assert(cs.front() == s.front());
  1287. assert(cs.compare(cs) == 0);
  1288. assert(cs.find(s) == 0);
  1289. assert(cs.find(s, 1) == cs.npos);
  1290. assert(cs.rfind(s) == 0);
  1291. assert(cs.rfind(s, 1) == cs.npos);
  1292. // assign/construct to string
  1293. std::string ns{cs};
  1294. assert(ns == s);
  1295. ns = cs;
  1296. assert(ns == s);
  1297. assert(ns == cs);
  1298. assert(cs == cs);
  1299. ns = "xy";
  1300. assert(cs <= ns);
  1301. assert(cs < ns);
  1302. assert(ns > cs);
  1303. assert(ns >= cs);
  1304. assert(ns != cs);
  1305. // construct using convert
  1306. {
  1307. MyViewCustom cv;
  1308. StringType cs(cv);
  1309. assert(!cs);
  1310. }
  1311. cs.swap(tcs);
  1312. assert(tcs);
  1313. cs = nullptr;
  1314. assert(!cs);
  1315. assert(!s.empty());
  1316. {
  1317. std::map<StringType, int> m;
  1318. cs = s;
  1319. m[cs] = 5;
  1320. assert(m[cs] == 5);
  1321. }
  1322. {
  1323. std::unordered_map<StringType, int> m;
  1324. cs = s;
  1325. m[cs] = 5;
  1326. assert(m[cs] == 5);
  1327. }
  1328. #if __cplusplus >= 201703L
  1329. // C++17 specifics
  1330. cs = std::nullopt;
  1331. std::optional<std::string> os;
  1332. cs = os;
  1333. assert(!cs);
  1334. os = s;
  1335. cs = os;
  1336. assert(cs == s);
  1337. os = std::nullopt;
  1338. os = cs;
  1339. assert(os && os.value() == s);
  1340. cs = nullptr;
  1341. assert(!cs);
  1342. os = cs.opt_();
  1343. assert(!os);
  1344. cs = STR;
  1345. assert(cs.find_first_of("b") == 1);
  1346. assert(cs.find_first_of('b') == 1);
  1347. #endif
  1348. }
  1349. } // namespace string_helpers
  1350. namespace gi
  1351. {
  1352. namespace convert
  1353. {
  1354. template<typename Transfer>
  1355. struct converter<string_helpers::MyViewCustom, detail::cstr<Transfer>>
  1356. : public converter_base<string_helpers::MyViewCustom,
  1357. detail::cstr<Transfer>>
  1358. {
  1359. static detail::cstr<Transfer> convert(const string_helpers::MyViewCustom &v)
  1360. {
  1361. (void)v;
  1362. return nullptr;
  1363. }
  1364. };
  1365. } // namespace convert
  1366. } // namespace gi
  1367. void
  1368. test_string()
  1369. {
  1370. using namespace string_helpers;
  1371. { // generic
  1372. check_string<cstr>();
  1373. check_string<cstrv>();
  1374. }
  1375. std::string s("xy");
  1376. { // string only
  1377. cstr cs(s, 1, 1);
  1378. {
  1379. MyView cv;
  1380. cstr cs(cv);
  1381. assert(!cs);
  1382. }
  1383. {
  1384. auto *s = (char *)g_malloc0(5);
  1385. cstr cs(s, transfer_full);
  1386. assert(cs.data() == s);
  1387. }
  1388. // ops
  1389. cs = s;
  1390. cs = cs + s;
  1391. assert(cs == s + s);
  1392. assert(cs.size() == 4);
  1393. cs = s;
  1394. cs = s + cs;
  1395. assert(cs == s + s);
  1396. cs.pop_back();
  1397. assert(cs.size() == 3);
  1398. cs.push_back(s.back());
  1399. assert(cs.size() == 4);
  1400. assert(cs == s + s);
  1401. cs = cs.substr(0, 2);
  1402. assert(cs == s);
  1403. cs += s;
  1404. assert(cs == s + s);
  1405. cs.assign(2, 'x');
  1406. assert(cs == "xx");
  1407. cs = 'y' + cs;
  1408. assert(cs == "yxx");
  1409. cs = cs + 'y';
  1410. assert(cs == "yxxy");
  1411. cs.clear();
  1412. assert(!cs);
  1413. cs = s;
  1414. auto sp = unwrap(std::move(cs), transfer_full);
  1415. assert(s == sp);
  1416. assert(sp);
  1417. assert(!cs);
  1418. cs = cstr{sp, transfer_full};
  1419. assert(cs.data() == sp);
  1420. sp = unwrap(std::move(cs), transfer_full);
  1421. assert(!cs);
  1422. cs = wrap(sp, transfer_full);
  1423. assert(cs.data() == sp);
  1424. // C++17 string view
  1425. #if __cplusplus >= 201703L
  1426. std::string_view sv(s);
  1427. cs = sv;
  1428. assert(cs.data() != sv.data());
  1429. assert(sv == cs);
  1430. assert(cs == sv);
  1431. sv = "zz";
  1432. assert(cs <= sv);
  1433. assert(cs < sv);
  1434. assert(sv > cs);
  1435. assert(sv >= cs);
  1436. assert(sv != cs);
  1437. #endif
  1438. }
  1439. { // view only
  1440. cstrv cv(s);
  1441. assert(cv.data() == s.data());
  1442. cv.remove_prefix(1);
  1443. assert(cv.size() == s.size() - 1);
  1444. assert(cv == s.substr(1));
  1445. const cstrv ccv(s);
  1446. std::string ns(ccv);
  1447. }
  1448. { // combination
  1449. cstr cs("blah");
  1450. cstrv cv(cs);
  1451. assert(cv.data() == cs.data());
  1452. cv = cs;
  1453. assert(cv.data() == cs.data());
  1454. cs = cv;
  1455. assert(cs.data() != cv.data());
  1456. }
  1457. }
  1458. void
  1459. test_exception()
  1460. {
  1461. static_assert(traits::is_gboxed<GLib::Error>::value, "");
  1462. GQuark domain = g_quark_from_string("test-domain");
  1463. const char *msg = "exception_test";
  1464. const int code = 42;
  1465. GError *err = g_error_new_literal(domain, code, msg);
  1466. auto w = wrap(err, transfer_full);
  1467. assert(w.matches(domain, code));
  1468. auto what = w.what();
  1469. assert(strstr(what, msg) != NULL);
  1470. auto wr = wrap(err, transfer_none);
  1471. assert(wr.matches(domain, code));
  1472. GLib::Error e{std::move(w)};
  1473. assert(!w);
  1474. assert(e.matches(domain, code));
  1475. check_error(nullptr);
  1476. err = g_error_new_literal(domain, code, msg);
  1477. detail::make_unexpected(err);
  1478. bool value = true;
  1479. auto r = make_result<bool>(value, nullptr);
  1480. static_assert(detail::is_result<decltype(r)>::value, "");
  1481. static_assert(!detail::is_result<bool>::value, "");
  1482. // make sure we have bool result
  1483. auto s = expect(std::move(r));
  1484. static_assert(std::is_same<bool, decltype(s)>::value, "");
  1485. auto &e2 = expect(e);
  1486. assert(&e2 == &e);
  1487. }
  1488. void
  1489. test_enumflag()
  1490. {
  1491. const char *name = "EnumValue1";
  1492. const char *nick = "v1";
  1493. auto v = CppEnum::VALUE_1;
  1494. auto w = value_info(v);
  1495. auto w1 = EnumValue<CppEnum>::get_by_name(name);
  1496. auto w2 = EnumValue<CppEnum>::get_by_nick(nick);
  1497. assert(w == w1);
  1498. assert(w1 == w2);
  1499. assert(w1.value_name() == name);
  1500. assert(w1.value_nick() == nick);
  1501. // convenient operations
  1502. auto f = CppFlags::VALUE_0 | CppFlags::VALUE_1;
  1503. f = f & CppFlags::VALUE_1;
  1504. f = ~f;
  1505. f ^= CppFlags::VALUE_0;
  1506. }
  1507. typedef int(CCallback)(int, float);
  1508. typedef detail::callback<int(int, float), transfer_none_t,
  1509. std::tuple<transfer_none_t, transfer_none_t>>
  1510. CppCallback;
  1511. void
  1512. test_callback()
  1513. {
  1514. { // argument selection helper
  1515. auto f = [](int a, int b) { return a - b; };
  1516. using Y = detail::args_index<1, 0>;
  1517. auto rr = detail::apply_with_args<Y>(f, 7, 3, 5);
  1518. assert(rr == -4);
  1519. }
  1520. {
  1521. const char *t = "";
  1522. auto f = [](const char *s) -> decltype(auto) { return *s; };
  1523. static_assert(std::is_reference<decltype(f(t))>::value, "");
  1524. using Y = detail::args_index<0>;
  1525. auto &rr = detail::apply_with_args<Y>(f, t);
  1526. assert(&rr == t);
  1527. }
  1528. {
  1529. using T = typename detail::arg_traits<transfer_none_t>::transfer_type;
  1530. static_assert(std::is_same<transfer_none_t, T>::value, "");
  1531. static_assert(detail::is_simple_cb<std::tuple<transfer_none_t>>::value, "");
  1532. using TC = std::tuple<
  1533. detail::arg_info<transfer_full_t, false, void, detail::args_index<0>>,
  1534. detail::arg_info<transfer_full_t, false, void, detail::args_index<1>>>;
  1535. static_assert(!detail::is_simple_cb<TC>::value, "");
  1536. }
  1537. { // exception helpers
  1538. detail::report_exception<true>(std::runtime_error("fail"), 5, nullptr);
  1539. detail::report_exception(
  1540. std::runtime_error("fail"), 5, (::GError **)(nullptr));
  1541. GError *error = nullptr;
  1542. detail::report_exception(std::runtime_error("fail"), 5, &error);
  1543. assert(error);
  1544. g_error_free(error);
  1545. error = nullptr;
  1546. }
  1547. int calls = 0;
  1548. auto l = [&](int a, float b) {
  1549. ++calls;
  1550. return a * b;
  1551. };
  1552. detail::transform_callback_wrapper<int(int, float)>::with_transfer<false,
  1553. transfer_full_t, transfer_none_t, transfer_none_t>
  1554. x{l};
  1555. x.wrapper(1, 2, &x);
  1556. assert(calls == 1);
  1557. x.take_data(std::make_shared<int>(0));
  1558. auto m = [&](int a, CBoxedExample /*b*/, int &x, int *y) {
  1559. x = 1;
  1560. *y = 2;
  1561. ++calls;
  1562. return a;
  1563. };
  1564. detail::transform_callback_wrapper<void(
  1565. int, CBoxedExample, int &, int *)>::with_transfer<false, transfer_full_t,
  1566. transfer_full_t, transfer_full_t, transfer_none_t, transfer_none_t>
  1567. y{m};
  1568. int p = 0, q = 0;
  1569. y.wrapper(1, gi_cpp_cbexample_new(), &p, &q, &y);
  1570. assert(calls == 2);
  1571. assert(p == 1);
  1572. assert(q == 2);
  1573. auto w = wrap(gi_cpp_example_new(), transfer_full);
  1574. auto w2 = wrap(gi_cpp_example_new(), transfer_full);
  1575. char str[] = "blah";
  1576. auto n = [&](GBoxedExample /*b*/, Derived &ob, CppEnum *e, gi::cstring_v &s,
  1577. gpointer &vb, GLib::Error * /*error*/) {
  1578. ++calls;
  1579. if (e)
  1580. *e = CppEnum::VALUE_1;
  1581. ob = w2;
  1582. s = str;
  1583. vb = str;
  1584. return w;
  1585. };
  1586. detail::transform_callback_wrapper<Derived(GBoxedExample, Derived &,
  1587. CppEnum *, gi::cstring_v &, gpointer &, GLib::Error *)>::
  1588. with_transfer<false, transfer_full_t, transfer_full_t, transfer_full_t,
  1589. transfer_none_t, transfer_none_t, transfer_none_t, transfer_full_t>
  1590. z{n};
  1591. CDerived *ob{};
  1592. CEnum e{};
  1593. char *s{};
  1594. gpointer vb{};
  1595. auto r = z.wrapper(gi_cpp_gbexample_new(), &ob, &e, &s, &vb, nullptr, &z);
  1596. assert(calls == 3);
  1597. assert(r == w.gobj_());
  1598. assert(refcount(r) == 2);
  1599. g_object_unref(r);
  1600. assert(e == CEnum::ENUM_VALUE_1);
  1601. assert(s == str);
  1602. assert(vb == s);
  1603. assert(ob == w2.gobj_());
  1604. assert(refcount(ob) == 2);
  1605. g_object_unref(ob);
  1606. // extended case
  1607. {
  1608. using CLocalCallback_CF_CType = int (*)(int, gpointer);
  1609. struct CLocalCallback_CF_Trait
  1610. {
  1611. using handler_cb_type = CLocalCallback_CF_CType;
  1612. static auto handler(int x, handler_cb_type cb, gpointer ud)
  1613. {
  1614. return cb(x, ud);
  1615. };
  1616. };
  1617. using CppLocalCallback = detail::callback<int(int), transfer_none_t,
  1618. std::tuple<transfer_none_t>>;
  1619. int xx = 0;
  1620. auto nx = [&](GBoxedExample /*b*/, Derived &ob, CppEnum *e, int x,
  1621. CppLocalCallback cb, GLib::Error * /*error*/) {
  1622. ++calls;
  1623. xx = x;
  1624. ob = w2;
  1625. if (e)
  1626. *e = CppEnum::VALUE_1;
  1627. auto r = cb(x);
  1628. // supplied cb below is identity function
  1629. assert(r == x);
  1630. return w;
  1631. };
  1632. detail::transform_callback_wrapper<Derived(GBoxedExample, Derived &,
  1633. CppEnum *, int, CppLocalCallback,
  1634. GLib::Error *),
  1635. CDerived *(GBExample *, CDerived **, CEnum *, int,
  1636. CLocalCallback_CF_CType, gpointer,
  1637. ::GError **)>::with_transfer<false, transfer_none_t,
  1638. detail::arg_info<transfer_full_t, false, void, detail::args_index<0>>,
  1639. detail::arg_info<transfer_none_t, false, void, detail::args_index<1>>,
  1640. detail::arg_info<transfer_full_t, false, void, detail::args_index<2>>,
  1641. detail::arg_info<transfer_full_t, false, void, detail::args_index<3>>,
  1642. detail::arg_info<transfer_full_t, false, CLocalCallback_CF_Trait,
  1643. detail::args_index<4, 5>>,
  1644. detail::arg_info<transfer_full_t, false, void, detail::args_index<6>>>
  1645. zx{nx};
  1646. CDerived *obx{};
  1647. CEnum ex{};
  1648. auto cb = [](int v, gpointer ud) {
  1649. if (ud)
  1650. *(int *)(ud) = v;
  1651. return v;
  1652. };
  1653. int oi = 0;
  1654. auto r = zx.wrapper(
  1655. gi_cpp_gbexample_new(), &obx, &ex, 5, cb, (gpointer)&oi, nullptr, &zx);
  1656. // cpp callback should have been called
  1657. assert(calls == 4);
  1658. assert(xx == 5);
  1659. assert(r == w.gobj_());
  1660. assert(obx != nullptr);
  1661. assert(obx == w2.gobj_());
  1662. assert(e == CEnum::ENUM_VALUE_1);
  1663. // which in turn should have called the supplied callback
  1664. assert(oi == 5);
  1665. //
  1666. // void return case, and sized array out
  1667. char *sx{};
  1668. gpointer vbx{};
  1669. const int V = 56;
  1670. int *a_data{};
  1671. int a_size = 0;
  1672. using TestColType = gi::Collection<gi::DSpan, int, transfer_full_t>;
  1673. auto nnx = [&](gi::cstring_v &s, gpointer &vb, CppLocalCallback cb,
  1674. TestColType &d) {
  1675. ++calls;
  1676. s = str;
  1677. vb = str;
  1678. auto r = cb(V);
  1679. // supplied cb below is identity function
  1680. assert(r == V);
  1681. d.push_back(4);
  1682. };
  1683. detail::transform_callback_wrapper<void(gi::cstring_v & s, gpointer & vb,
  1684. CppLocalCallback, TestColType &),
  1685. void(char **, gpointer *, CLocalCallback_CF_CType, gpointer, int **,
  1686. int *)>::with_transfer<false, transfer_full_t,
  1687. detail::arg_info<transfer_none_t, false, void, detail::args_index<0>>,
  1688. detail::arg_info<transfer_none_t, false, void, detail::args_index<1>>,
  1689. detail::arg_info<transfer_full_t, false, CLocalCallback_CF_Trait,
  1690. detail::args_index<2, 3>>,
  1691. detail::arg_info<transfer_full_t, false, void,
  1692. detail::args_index<4, 5>>>
  1693. zzx{nnx};
  1694. zzx.wrapper(&sx, &vbx, cb, (gpointer)&oi, &a_data, &a_size, &zzx);
  1695. assert(calls == 5);
  1696. assert(sx == str);
  1697. assert(vbx == str);
  1698. // cpp callback should have been called
  1699. assert(oi == V);
  1700. // handle returned array
  1701. assert(a_size == 1);
  1702. assert(*a_data == 4);
  1703. g_free(a_data);
  1704. }
  1705. { // compilation checks
  1706. const CppCallback cppcb(l);
  1707. auto uw{unwrap(cppcb, gi::scope_async)};
  1708. delete uw;
  1709. auto uw2{unwrap(cppcb, gi::scope_notified)};
  1710. delete uw2;
  1711. }
  1712. }
  1713. void
  1714. test_value()
  1715. {
  1716. using GObject_::Value;
  1717. static_assert(traits::gtype<Value>::value, "");
  1718. assert(g_type_is_a(GI_CPP_TYPE_ENUM, G_TYPE_ENUM));
  1719. assert(g_type_is_a(GI_CPP_TYPE_FLAGS, G_TYPE_FLAGS));
  1720. // detail helper
  1721. {
  1722. detail::Value v(5);
  1723. auto vs = detail::transform_value<std::string>(&v);
  1724. assert(vs == "5");
  1725. detail::Value v2("ab");
  1726. auto w = detail::get_value<std::string>(&v2);
  1727. assert(w == "ab");
  1728. }
  1729. // main Value
  1730. {
  1731. Value v;
  1732. v.init(G_TYPE_STRING);
  1733. v.set_value("ab");
  1734. auto w = v.get_value<std::string>();
  1735. assert(w == "ab");
  1736. }
  1737. {
  1738. Value v(0);
  1739. auto w = v.get_value<int>();
  1740. assert(w == 0);
  1741. v.set_value(5);
  1742. w = v.get_value<int>();
  1743. assert(w == 5);
  1744. }
  1745. {
  1746. Value v{std::string()};
  1747. auto w = v.get_value<std::string>();
  1748. assert(w.empty());
  1749. }
  1750. {
  1751. Value v((double)1.0);
  1752. auto w = v.get_value<double>();
  1753. assert(w == 1.0);
  1754. }
  1755. {
  1756. Value v('a');
  1757. auto w = v.get_value<char>();
  1758. assert(w == 'a');
  1759. }
  1760. {
  1761. CDerived *ob = gi_cpp_example_new();
  1762. auto wob = wrap(ob, transfer_none);
  1763. Value v(wob);
  1764. assert(refcount(ob) == 3);
  1765. auto w2 = v.get_value<Derived>();
  1766. assert(w2 == wob);
  1767. assert(refcount(ob) == 4);
  1768. auto wr = wrap(v.gobj_(), transfer_none);
  1769. assert(wr == v);
  1770. assert(refcount(ob) == 4);
  1771. g_object_unref(ob);
  1772. // others clean up by magic
  1773. }
  1774. {
  1775. Value v(GBoxedExample{});
  1776. auto w = v.get_value<GBoxedExample>();
  1777. assert(w.gobj_() == nullptr);
  1778. auto wr = v.get_value<GBoxedExampleRef>();
  1779. assert(wr.gobj_() == nullptr);
  1780. }
  1781. {
  1782. Value v(CppEnum::VALUE_0);
  1783. auto w = v.get_value<CppEnum>();
  1784. assert(w == CppEnum::VALUE_0);
  1785. Value v1(v.copy_());
  1786. assert(v != v1);
  1787. }
  1788. {
  1789. Value v(CppFlags::VALUE_1);
  1790. auto w = v.get_value<CppFlags>();
  1791. assert(w == CppFlags::VALUE_1);
  1792. Value v1(v.copy_());
  1793. assert(v != v1);
  1794. }
  1795. { // test function; auto conversion
  1796. auto tf = [](Value v, GType t) { assert(G_VALUE_TYPE(v.gobj_()) == t); };
  1797. tf(5, G_TYPE_INT);
  1798. tf("ab", G_TYPE_STRING);
  1799. tf(GBoxedExample(), GI_CPP_TYPE_BOXED_EXAMPLE);
  1800. }
  1801. { // wrapping
  1802. GValue *v = (GValue *)1;
  1803. auto w = wrap(v, transfer_none);
  1804. auto v1 = unwrap(w, transfer_none);
  1805. assert(v1 = v);
  1806. }
  1807. }
  1808. void
  1809. test_property()
  1810. {
  1811. CDerived *ob = gi_cpp_example_new();
  1812. // take ownership
  1813. Derived w = wrap(ob, transfer_full);
  1814. // manual
  1815. w.set_property(NAME_NUMBER, 5);
  1816. assert(w.get_property<int>(NAME_NUMBER) == 5);
  1817. w.set_property(NAME_PRESENT, true);
  1818. assert(w.get_property<bool>(NAME_PRESENT) == true);
  1819. const char *str = "value";
  1820. w.set_property(NAME_DATA, str);
  1821. assert(w.get_property<std::string>(NAME_DATA) == str);
  1822. w.set_property(NAME_OBJECT, w);
  1823. auto w2 = w.get_property<Derived>(NAME_OBJECT);
  1824. assert(w2 == w);
  1825. assert(refcount(ob) == 3);
  1826. // remove cycle ref held within ob
  1827. w.set_property(NAME_OBJECT, Derived());
  1828. assert(refcount(ob) == 2);
  1829. w.set_property(NAME_ENUM, CppEnum::VALUE_1);
  1830. assert(w.get_property<CppEnum>(NAME_ENUM) == CppEnum::VALUE_1);
  1831. // multiple props
  1832. w.set_properties(NAME_NUMBER, 10, NAME_FNUMBER, 5.2, NAME_PRESENT, FALSE);
  1833. assert(w.get_property<int>(NAME_NUMBER) == 10);
  1834. assert(w.get_property<double>(NAME_FNUMBER) == 5.2);
  1835. assert(w.get_property<bool>(NAME_PRESENT) == false);
  1836. // generic value
  1837. #ifdef GI_GOBJECT_PROPERTY_VALUE
  1838. w.get_property(NAME_NUMBER);
  1839. #endif
  1840. // via proxy
  1841. Derived w3 = wrap(gi_cpp_example_new(), transfer_full);
  1842. w.property_number().set(7);
  1843. w.property_fnumber().set(6.2);
  1844. w.property_data().set(str);
  1845. w.property_object().set(w3);
  1846. w.property_present().set(true);
  1847. w.property_choice().set(CppEnum::VALUE_0);
  1848. w.property_flags().set(CppFlags::VALUE_0);
  1849. // boxed property
  1850. GQuark domain = g_quark_from_string("test-domain");
  1851. auto error = GLib::Error::new_literal(domain, 1, "msg");
  1852. w.property_error().set(error.copy());
  1853. w.property_error().set(std::move(error));
  1854. const Derived cw = w;
  1855. assert(cw.property_number().get() == 7);
  1856. assert(cw.property_fnumber().get() == 6.2);
  1857. assert(cw.property_data().get() == str);
  1858. assert(cw.property_object().get() == w3);
  1859. assert(cw.property_data().get() == str);
  1860. assert(cw.property_choice().get() == CppEnum::VALUE_0);
  1861. assert(cw.property_flags().get() == CppFlags::VALUE_0);
  1862. // property queries
  1863. auto pspec = cw.find_property(NAME_NUMBER);
  1864. assert(pspec);
  1865. assert(pspec.get_name() == NAME_NUMBER);
  1866. auto pspecs = cw.list_properties();
  1867. assert(pspecs.size() == PROP_LAST);
  1868. }
  1869. void
  1870. test_signal()
  1871. {
  1872. // example values
  1873. double v_d = 2.7;
  1874. int v_i = 4;
  1875. std::string v_s = "values";
  1876. bool v_b = true;
  1877. CppEnum v_e = CppEnum::VALUE_1;
  1878. CppFlags v_f = CppFlags::VALUE_1;
  1879. Derived v_o = wrap(gi_cpp_example_new(), transfer_full);
  1880. // object to signal on
  1881. CDerived *ob = gi_cpp_example_new();
  1882. // take ownership
  1883. Derived w = wrap(ob, transfer_full);
  1884. // lambda callbacks
  1885. int recv = 0;
  1886. int ret = 7;
  1887. auto l1 = [&](Derived src, GObject_::Object o, bool b, bool c,
  1888. const std::string &s) -> int {
  1889. assert(src == w);
  1890. assert(o == v_o);
  1891. assert(s == v_s);
  1892. assert(b == v_b);
  1893. assert(c == !b);
  1894. ++recv;
  1895. return ret;
  1896. };
  1897. w.signal_to_int().connect(l1);
  1898. auto r = w.signal_to_int().emit(v_o, v_b, !v_b, v_s);
  1899. assert(recv == 1);
  1900. assert(r == ret);
  1901. // another signal
  1902. auto l2 = [&](Derived src, int i, gint64 ll) -> std::string {
  1903. assert(src == w);
  1904. ++recv;
  1905. return std::to_string(i + ll);
  1906. };
  1907. w.signal_to_string().connect(l2);
  1908. gint64 ll = 4;
  1909. auto sr = w.signal_to_string().emit(v_i, ll);
  1910. assert(recv == 2);
  1911. assert(std::stoi(sr) == v_i + ll);
  1912. // and another
  1913. auto l3 = w.signal_to_void().slot(
  1914. [&](Derived src, double d, CppEnum e, CppFlags f) {
  1915. assert(src == w);
  1916. assert(d == v_d);
  1917. assert(e == v_e);
  1918. assert(f == v_f);
  1919. ++recv;
  1920. });
  1921. auto id = w.signal_to_void().connect(l3);
  1922. w.signal_to_void().emit(v_d, v_e, v_f);
  1923. assert(recv == 3);
  1924. auto conn = make_connection(id, l3, w);
  1925. assert(conn.connected());
  1926. {
  1927. // safe to disconnect twice (or attempt so)
  1928. GObject_::SignalScopedConnection sconn(conn), sconn2(conn);
  1929. assert(sconn.connected());
  1930. assert(sconn2.connected());
  1931. }
  1932. assert(!conn.connected());
  1933. w.signal_to_void().emit(v_d, v_e, v_f);
  1934. assert(recv == 3);
  1935. // signal collection and output argument
  1936. auto l4 = [&](Derived src, unsigned &o, auto pa, auto la) {
  1937. assert(src == w);
  1938. o = pa.size() + std::distance(la.begin(), la.end());
  1939. };
  1940. gi::Collection<::GPtrArray, char *, gi::transfer_full_t> pa;
  1941. gi::Collection<::GSList, char *, gi::transfer_full_t> la;
  1942. pa.push_back("blah");
  1943. la = pa;
  1944. assert(!la.empty());
  1945. la.push_back("foo");
  1946. w.signal_to_output_int().connect(l4);
  1947. unsigned result = 0;
  1948. w.signal_to_output_int().emit(result, pa, nullptr);
  1949. assert(result == pa.size());
  1950. w.signal_to_output_int().emit(result, nullptr, la);
  1951. assert(result == 2);
  1952. // assert exception helper
  1953. auto assert_exc = [](const std::function<void()> &func) {
  1954. bool exc = false;
  1955. try {
  1956. func();
  1957. } catch (std::exception &) {
  1958. exc = true;
  1959. }
  1960. assert(exc);
  1961. };
  1962. // check connect check
  1963. assert_exc(
  1964. [&]() { w.connect<std::string(Derived, int, gint64)>("to_void", l2); });
  1965. // check property value conversion
  1966. assert_exc([&]() { w.set_property<std::string>(NAME_OBJECT, "blah"); });
  1967. }
  1968. // ExampleInterface
  1969. class ExampleInterface : public gi::InterfaceBase
  1970. {
  1971. public:
  1972. typedef GICppExampleItf BaseObjectType;
  1973. static GType get_type_() G_GNUC_CONST
  1974. {
  1975. return gi_cpp_example_interface_get_type();
  1976. }
  1977. };
  1978. class ExampleInterfaceDef
  1979. {
  1980. typedef ExampleInterfaceDef self;
  1981. public:
  1982. typedef ExampleInterface instance_type;
  1983. typedef GICppExampleInterface interface_type;
  1984. using GI_MEMBER_CHECK_CONFLICT(vmethod) = self;
  1985. using GI_MEMBER_CHECK_CONFLICT(imethod) = self;
  1986. struct TypeInitData;
  1987. protected:
  1988. ~ExampleInterfaceDef() = default;
  1989. static void interface_init(gpointer iface, gpointer /*data*/);
  1990. virtual int vmethod_(int a) = 0;
  1991. virtual int imethod_(int a) = 0;
  1992. };
  1993. using ExampleInterfaceImpl = gi::detail::InterfaceImpl<ExampleInterfaceDef>;
  1994. class ExampleInterfaceClassImpl
  1995. : public gi::detail::InterfaceClassImpl<ExampleInterfaceImpl>
  1996. {
  1997. friend class ExampleInterfaceDef;
  1998. typedef ExampleInterfaceImpl self;
  1999. typedef gi::detail::InterfaceClassImpl<ExampleInterfaceImpl> super;
  2000. protected:
  2001. using super::super;
  2002. int vmethod_(int a) override
  2003. {
  2004. auto _struct = get_struct_();
  2005. return _struct->vmethod(this->gobj_(), a);
  2006. }
  2007. int imethod_(int a) override
  2008. {
  2009. auto _struct = get_struct_();
  2010. return _struct->imethod(this->gobj_(), a);
  2011. }
  2012. };
  2013. struct ExampleInterfaceDef::TypeInitData
  2014. {
  2015. GI_MEMBER_DEFINE(ExampleInterfaceClassImpl, vmethod)
  2016. GI_MEMBER_DEFINE(ExampleInterfaceClassImpl, imethod)
  2017. template<typename SubClass>
  2018. constexpr static TypeInitData factory()
  2019. {
  2020. using DefData = detail::DefinitionData<SubClass, TypeInitData>;
  2021. return {GI_MEMBER_HAS_DEFINITION(SubClass, DefData, vmethod),
  2022. GI_MEMBER_HAS_DEFINITION(SubClass, DefData, imethod)};
  2023. }
  2024. };
  2025. void
  2026. ExampleInterfaceDef::interface_init(gpointer iface, gpointer data)
  2027. {
  2028. auto init_data = GI_MEMBER_INIT_DATA(TypeInitData, data);
  2029. auto itf = (interface_type *)(iface);
  2030. if (init_data.vmethod)
  2031. itf->vmethod = gi::detail::method_wrapper<self, int (*)(int),
  2032. transfer_full_t, std::tuple<transfer_none_t>>::wrapper<&self::vmethod_>;
  2033. if (init_data.imethod)
  2034. itf->imethod = gi::detail::method_wrapper<self, int (*)(int),
  2035. transfer_full_t, std::tuple<transfer_none_t>>::wrapper<&self::imethod_>;
  2036. }
  2037. // PropertyInterface
  2038. class PropertyInterface : public gi::InterfaceBase
  2039. {
  2040. public:
  2041. typedef GICppPropertyItf BaseObjectType;
  2042. static GType get_type_() G_GNUC_CONST
  2043. {
  2044. return gi_cpp_property_interface_get_type();
  2045. }
  2046. };
  2047. class PropertyInterfaceDef
  2048. {
  2049. typedef PropertyInterfaceDef self;
  2050. public:
  2051. typedef PropertyInterface instance_type;
  2052. typedef GICppPropertyInterface interface_type;
  2053. protected:
  2054. static void interface_init(gpointer iface, gpointer /*data*/)
  2055. {
  2056. auto itf = (interface_type *)(iface);
  2057. (void)itf;
  2058. }
  2059. };
  2060. using PropertyInterfaceImpl = gi::detail::InterfaceImpl<PropertyInterfaceDef>;
  2061. class PropertyInterfaceClassImpl
  2062. : public gi::detail::InterfaceClassImpl<PropertyInterfaceImpl>
  2063. {
  2064. typedef PropertyInterfaceImpl self;
  2065. typedef gi::detail::InterfaceClassImpl<PropertyInterfaceImpl> super;
  2066. protected:
  2067. using super::super;
  2068. };
  2069. class DerivedClassDef
  2070. {
  2071. typedef DerivedClassDef self;
  2072. public:
  2073. typedef Derived instance_type;
  2074. typedef GICppExampleClass class_type;
  2075. struct TypeInitData;
  2076. using GI_MEMBER_CHECK_CONFLICT(vmethod) = self;
  2077. using GI_MEMBER_CHECK_CONFLICT(cmethod) = self;
  2078. protected:
  2079. ~DerivedClassDef() = default;
  2080. static void class_init(gpointer g_class, gpointer class_data_factory);
  2081. virtual int vmethod_(int a, int b) = 0;
  2082. virtual int cmethod_(int a, int b) = 0;
  2083. };
  2084. GI_CLASS_IMPL_BEGIN
  2085. class DerivedClass
  2086. : public gi::detail::ClassTemplate<DerivedClassDef,
  2087. GObject_::impl::internal::ObjectClass, ExampleInterfaceClassImpl>
  2088. {
  2089. friend class DerivedClassDef;
  2090. typedef DerivedClass self;
  2091. typedef gi::detail::ClassTemplate<DerivedClassDef,
  2092. GObject_::impl::internal::ObjectClass, ExampleInterfaceClassImpl>
  2093. super;
  2094. public:
  2095. typedef ExampleInterfaceClassImpl ExampleInterface_type;
  2096. private:
  2097. // make local helpers private
  2098. using super::get_struct_;
  2099. using super::gobj_;
  2100. protected:
  2101. GI_DISABLE_DEPRECATED_WARN_BEGIN
  2102. using super::super;
  2103. GI_DISABLE_DEPRECATED_WARN_END
  2104. virtual int vmethod_(int a, int b) override
  2105. {
  2106. auto _struct = get_struct_();
  2107. return _struct->vmethod(gobj_(), a, b);
  2108. }
  2109. virtual int cmethod_(int a, int b) override
  2110. {
  2111. auto _struct = get_struct_();
  2112. return _struct->cmethod(gobj_(), a, b);
  2113. }
  2114. };
  2115. struct DerivedClassDef::TypeInitData
  2116. {
  2117. GI_MEMBER_DEFINE(DerivedClass, vmethod)
  2118. GI_MEMBER_DEFINE(DerivedClass, cmethod)
  2119. template<typename SubClass>
  2120. constexpr static TypeInitData factory()
  2121. {
  2122. using DefData = detail::DefinitionData<SubClass, TypeInitData>;
  2123. return {GI_MEMBER_HAS_DEFINITION(SubClass, DefData, vmethod),
  2124. GI_MEMBER_HAS_DEFINITION(SubClass, DefData, cmethod)};
  2125. }
  2126. };
  2127. void
  2128. DerivedClassDef::class_init(gpointer g_class, gpointer class_data_factory)
  2129. {
  2130. auto class_data = GI_MEMBER_INIT_DATA(TypeInitData, class_data_factory);
  2131. GICppExampleClass *klass = (GICppExampleClass *)g_class;
  2132. if (class_data.vmethod)
  2133. klass->vmethod = gi::detail::method_wrapper<self, int (*)(int, int),
  2134. transfer_full_t,
  2135. std::tuple<transfer_none_t, transfer_none_t>>::wrapper<&self::vmethod_>;
  2136. if (class_data.cmethod)
  2137. klass->cmethod = gi::detail::method_wrapper<self, int (*)(int, int),
  2138. transfer_full_t,
  2139. std::tuple<transfer_none_t, transfer_none_t>>::wrapper<&self::cmethod_>;
  2140. // local compile check
  2141. (void)gi::detail::method_wrapper<self, int (*)(int, int),
  2142. std::nullptr_t>::wrapper<&self::cmethod_>;
  2143. }
  2144. GI_CLASS_IMPL_END
  2145. using DerivedImpl = gi::detail::ObjectImpl<Derived, DerivedClass>;
  2146. template<typename T>
  2147. class custom_property : public gi::property<T>
  2148. {
  2149. public:
  2150. using super = gi::property<T>;
  2151. using super::super;
  2152. using handler = std::function<void(const T &)>;
  2153. handler handler_;
  2154. void set_property(const GValue *value) override
  2155. {
  2156. super::set_property(value);
  2157. if (handler_)
  2158. handler_(this->get_value());
  2159. }
  2160. };
  2161. class UserDerived : public DerivedImpl
  2162. {
  2163. public:
  2164. // possible conflict for vmethod
  2165. // so we specify the override situation explicity
  2166. struct DefinitionData
  2167. {
  2168. GI_DEFINES_MEMBER(DerivedClassDef, vmethod, true)
  2169. GI_DEFINES_MEMBER(ExampleInterfaceDef, vmethod, true)
  2170. };
  2171. UserDerived()
  2172. : DerivedImpl(this), prop_int_set(this, "prop_int_set", "prop_int_set",
  2173. "prop_int_set", 0, 10, 0),
  2174. prop_bool_override(this, NAME_PRESENT)
  2175. {
  2176. // check detection of method definitions
  2177. constexpr auto class_def =
  2178. DerivedClassDef::TypeInitData::factory<UserDerived>();
  2179. static_assert(class_def.vmethod.value, "");
  2180. static_assert(!class_def.cmethod.value, "");
  2181. constexpr auto itf_def =
  2182. ExampleInterfaceDef::TypeInitData::factory<UserDerived>();
  2183. static_assert(itf_def.vmethod.value, "");
  2184. static_assert(!itf_def.imethod.value, "");
  2185. }
  2186. int vmethod_(int a, int b) override { return a * b; }
  2187. int pvmethod(int a, int b) { return DerivedImpl::vmethod_(a, b); }
  2188. int vmethod_(int a) override { return 2 * a; }
  2189. int pivmethod(int a) { return ExampleInterface_type::vmethod_(a); }
  2190. custom_property<int> prop_int_set;
  2191. custom_property<bool> prop_bool_override;
  2192. };
  2193. class UserDerived2 : public DerivedImpl
  2194. {
  2195. public:
  2196. // possible conflict for vmethod
  2197. // so we specify the override situation explicity
  2198. struct DefinitionData
  2199. {
  2200. GI_DEFINES_MEMBER(DerivedClassDef, vmethod, true)
  2201. GI_DEFINES_MEMBER(ExampleInterfaceDef, vmethod, false)
  2202. };
  2203. UserDerived2() : DerivedImpl(this)
  2204. {
  2205. // check detection of method definitions
  2206. constexpr auto x = DerivedClassDef::TypeInitData::factory<UserDerived2>();
  2207. static_assert(x.vmethod.value, "");
  2208. static_assert(x.cmethod.value, "");
  2209. constexpr auto itf_def =
  2210. ExampleInterfaceDef::TypeInitData::factory<UserDerived2>();
  2211. static_assert(!itf_def.vmethod.value, "");
  2212. static_assert(itf_def.imethod.value, "");
  2213. }
  2214. int vmethod_(int a, int b) override { return a * b; }
  2215. int cmethod_(int a, int b) override { return a * b; }
  2216. int imethod_(int a) override { return 5 * a; }
  2217. };
  2218. GI_DISABLE_DEPRECATED_WARN_BEGIN
  2219. class OldUserDerived : public DerivedImpl
  2220. {
  2221. public:
  2222. OldUserDerived() : DerivedImpl(typeid(*this)) {}
  2223. };
  2224. GI_DISABLE_DEPRECATED_WARN_END
  2225. static const int DEFAULT_PROP_INT = 7;
  2226. class UserObject : public ExampleInterfaceImpl,
  2227. public PropertyInterfaceImpl,
  2228. public GObject_::impl::ObjectImpl
  2229. {
  2230. public:
  2231. UserObject()
  2232. : ObjectImpl(this, {}, {{NAME_INUMBER, {&prop_itf_int, nullptr}}}),
  2233. signal_demo_(this, "demo"), prop_itf_int(this, NAME_INUMBER),
  2234. prop_int(
  2235. this, "prop_int", "prop_int", "prop_int", 0, 10, DEFAULT_PROP_INT),
  2236. prop_bool(this, "prop_bool", "prop_bool", "prop_bool", false),
  2237. prop_str(this, "prop_str", "prop_str", "prop_str", ""),
  2238. prop_object(this, "prop_object", "prop_object", "prop_object"),
  2239. prop_enum(this, "prop_enum", "prop_enum", "prop_enum")
  2240. {}
  2241. int vmethod_(int a) override { return 5 * a; }
  2242. int imethod_(int a) override { return 7 * a; }
  2243. gi::signal<void(Object, int)> signal_demo_;
  2244. gi::property<int> prop_itf_int;
  2245. gi::property<int> prop_int;
  2246. gi::property<bool> prop_bool;
  2247. gi::property<std::string> prop_str;
  2248. gi::property<Object> prop_object;
  2249. gi::property<CppEnum> prop_enum;
  2250. };
  2251. void
  2252. test_impl()
  2253. {
  2254. {
  2255. // base object implements interface
  2256. UserDerived u, v;
  2257. assert(u.gobj_type_() == v.gobj_type_());
  2258. assert(u.pvmethod(2, 3) == 5);
  2259. auto klass =
  2260. G_TYPE_INSTANCE_GET_CLASS(u.gobj_(), u.gobj_type(), GICppExampleClass);
  2261. assert(klass->vmethod(u.gobj_(), 2, 3) == 6);
  2262. // no cmethod
  2263. assert(!klass->cmethod);
  2264. // interface
  2265. assert(u.pivmethod(4) == 6);
  2266. auto iface = G_TYPE_INSTANCE_GET_INTERFACE(
  2267. u.gobj_(), ExampleInterface::get_type_(), GICppExampleInterface);
  2268. assert(iface->vmethod((GICppExampleItf *)u.gobj_(), 4) == 8);
  2269. assert(!iface->imethod);
  2270. // implemented here
  2271. UserDerived2 w;
  2272. assert(w.imethod_(2) == 10);
  2273. // compilation check
  2274. assert(u.gobj_klass()->vmethod);
  2275. { // check custom property (on a non-Object derived class)
  2276. int value = 0;
  2277. auto &tp = u.prop_int_set;
  2278. tp.handler_ = [&value](int setv) { value = setv; };
  2279. auto proxy = tp.get_proxy();
  2280. //
  2281. const int NEW_VALUE = 7;
  2282. proxy.set(NEW_VALUE);
  2283. assert(value == NEW_VALUE);
  2284. assert(tp.get_value() == NEW_VALUE);
  2285. tp.handler_ = nullptr;
  2286. }
  2287. { // likewise on overriden property
  2288. auto &tp = u.prop_bool_override;
  2289. auto proxy = tp.get_proxy();
  2290. proxy.set(false);
  2291. assert(!proxy.get());
  2292. bool value = false;
  2293. tp.handler_ = [&value](bool setv) { value = setv; };
  2294. const bool NEW_VALUE = true;
  2295. //
  2296. proxy.set(NEW_VALUE);
  2297. assert(value == NEW_VALUE);
  2298. assert(tp.get_value() == NEW_VALUE);
  2299. tp.handler_ = nullptr;
  2300. }
  2301. }
  2302. {
  2303. // vanilla object
  2304. UserObject u, v;
  2305. assert(u.gobj_type_() == v.gobj_type_());
  2306. auto iface = G_TYPE_INSTANCE_GET_INTERFACE(
  2307. u.gobj_(), ExampleInterface::get_type_(), GICppExampleInterface);
  2308. assert(iface);
  2309. assert(iface->vmethod((GICppExampleItf *)u.gobj_(), 4) == 20);
  2310. // signal
  2311. int i = 0, j = 5;
  2312. u.signal_demo_.connect([&i](GObject_::Object, int in) -> void { i = in; });
  2313. u.signal_demo_.emit(j);
  2314. assert(i == j);
  2315. // properties
  2316. {
  2317. // also check notification
  2318. bool notified = false;
  2319. auto proxy = u.prop_int.get_proxy();
  2320. auto l = proxy.signal_notify().slot(
  2321. [&notified](
  2322. GObject_::Object, GObject_::ParamSpec) { notified = true; });
  2323. GObject_::SignalScopedConnection conn =
  2324. make_connection(proxy.signal_notify().connect(l), l, u);
  2325. assert(u.prop_int == DEFAULT_PROP_INT);
  2326. u.prop_int = j;
  2327. assert(notified);
  2328. notified = false;
  2329. assert(proxy.get() == j);
  2330. proxy.set(2 * j);
  2331. assert(u.prop_int == 2 * j);
  2332. assert(notified);
  2333. }
  2334. {
  2335. auto proxy = u.prop_bool.get_proxy();
  2336. u.prop_bool = true;
  2337. assert(proxy.get() == true);
  2338. proxy.set(false);
  2339. assert(u.prop_bool == false);
  2340. }
  2341. {
  2342. auto proxy = u.prop_str.get_proxy();
  2343. const std::string strv = "value";
  2344. u.prop_str = strv;
  2345. assert(proxy.get() == strv);
  2346. proxy.set(strv + strv);
  2347. assert(u.prop_str.get_value() == (strv + strv));
  2348. }
  2349. {
  2350. auto proxy = u.prop_object.get_proxy();
  2351. u.prop_object = v;
  2352. assert(proxy.get() == v);
  2353. proxy.set(nullptr);
  2354. assert(u.prop_object.get_value() == nullptr);
  2355. }
  2356. {
  2357. CppEnum v1 = CppEnum::VALUE_1, v0 = CppEnum::VALUE_0;
  2358. auto proxy = u.prop_enum.get_proxy();
  2359. u.prop_enum = v1;
  2360. assert(proxy.get() == v1);
  2361. proxy.set(v0);
  2362. assert(u.prop_enum == v0);
  2363. }
  2364. {
  2365. const int val = 8;
  2366. u.prop_itf_int = val;
  2367. auto proxy = u.prop_itf_int.get_proxy();
  2368. assert(proxy.get() == val);
  2369. proxy.set(val);
  2370. assert(u.prop_itf_int == val);
  2371. }
  2372. {
  2373. // local properties
  2374. property_read<bool> p{&u, "p", "p", "p", false};
  2375. p.get_proxy();
  2376. property_write<bool> q{&u, "p", "p", "p", false};
  2377. q.get_proxy();
  2378. }
  2379. }
  2380. {
  2381. // create non-stack
  2382. auto u = gi::make_ref<UserObject>();
  2383. assert(u->list_properties().size() > 0);
  2384. // cast works ok
  2385. GObject_::Object v = u;
  2386. assert(refcount(v.gobj_()) == 2);
  2387. auto l = [](GObject_::Object) {};
  2388. l(u);
  2389. auto u2 = ref_ptr_cast<UserObject>(v);
  2390. assert(u2 == u);
  2391. assert(refcount(v.gobj_()) == 3);
  2392. auto u3 = u2;
  2393. assert(refcount(v.gobj_()) == 4);
  2394. auto u4 = std::move(u3);
  2395. assert(refcount(v.gobj_()) == 4);
  2396. assert(!u3);
  2397. }
  2398. }
  2399. int
  2400. main(int argc, char *argv[])
  2401. {
  2402. (void)argc;
  2403. (void)argv;
  2404. test_trait();
  2405. test_wrap();
  2406. test_collection();
  2407. test_string();
  2408. test_exception();
  2409. test_enumflag();
  2410. test_value();
  2411. test_property();
  2412. test_signal();
  2413. test_callback();
  2414. test_impl();
  2415. return 0;
  2416. }