#ifndef GI_WRAP_HPP #define GI_WRAP_HPP #include "base.hpp" #include "string.hpp" namespace gi { // object/wrapper conversion template::type, typename Enable = typename std::enable_if::value>::type> inline typename std::remove_const::type wrap(CType *v, const TransferType &t) { // should be called with a concrete transfer subtype static_assert(!std::is_same::value, ""); // the class wrap only has to deal with non-const class type typedef typename std::remove_const::type TNC; return CppType::template wrap(v, t.value); } // special case; wrap an owned box with full transfer template::type, typename Enable = typename std::enable_if::value>::type, typename TNC = typename std::remove_const::type> inline TNC wrap(CType *v, const transfer_full_t &) { return CppType::template wrap(v); } // special case; wrap a unowned box (that is, transfer none) to the Ref type template::type, typename Enable = typename std::enable_if::value>::type, typename RefType = typename traits::reftype< typename std::remove_const::type>::type> inline RefType wrap(CType *v, const transfer_none_t &) { // unowned and no copy in all cases return RefType::template wrap(v); } template::type::BaseObjectType * = nullptr> inline typename traits::ctype::type unwrap(T &&v, const transfer_none_t &) { using DT = typename std::decay::type; // test convenience #ifndef GI_TEST static constexpr bool ALLOW_ALL = false; #else static constexpr bool ALLOW_ALL = true; #endif static_assert(ALLOW_ALL || traits::is_wrapper
::value || traits::is_reftype
::value, "transfer none expects refcnt wrapper or reftype (not owning box)"); return v.gobj_(); } namespace detail { // lvalue template::value>::type * = nullptr> inline typename traits::ctype::type unwrap(const T &v, const transfer_full_t &, std::true_type) { // no implicit copy for boxed; should end up in other case static_assert(!traits::is_boxed::value, "boxed copy"); return v.gobj_copy_(); } // rvalue template::value>::type * = nullptr> inline typename traits::ctype::type unwrap(T &&v, const transfer_full_t &, std::false_type) { // in case of wrapper/object; // release only provided on base case with void* return return (typename traits::ctype::type)v.release_(); } } // namespace detail template::type::BaseObjectType * = nullptr> inline typename traits::ctype::type unwrap(T &&v, const transfer_full_t &t) { // universal reference dispatch return detail::unwrap(std::forward(v), t, std::is_lvalue_reference()); } // container types template::type::_detail::DataType * = nullptr> inline typename std::decay::type::_detail::DataType unwrap(T &&v, const Transfer &t) { // universal reference dispatch return std::forward(v)._unwrap(t); } // to wrap a container, the target wrapped type needs to be explicitly specified // (in particular the contained element type) // (target type should be decay'ed type) // generic case, let wrap take care of it (usually no target type is needed) template::type>(), Transfer())) * = nullptr> TargetType wrap_to(CType v, const Transfer &t) { static_assert(traits::is_decayed::value, ""); return wrap(v, t); } // container case template TargetType wrap_to(CType v, const Transfer &t) { static_assert(traits::is_decayed::value, ""); return TargetType::template _wrap(v, t); } // container size case template TargetType wrap_to(CType v, int s, const Transfer &t) { static_assert(traits::is_decayed::value, ""); return TargetType::template _wrap(v, s, t); } #if 0 // string conversion inline std::string wrap(const char *v, const transfer_none_t &, const direction_t & = direction_dummy) { return detail::make_string(v); } // actually should not accept const input (as it makes no sense for full // transfer) but let's go the runtime way and not mind that too much (code // generation will warn though) inline std::string wrap(const char *v, const transfer_full_t &, const direction_t & = direction_dummy) { // a custom type that would allow direct mem transfer might be nice // but that might be too nifty and create yet-another-string-type std::string s; if (v) { s = v; g_free((char *)v); } return s; } #else // string conversion inline gi::cstring_v wrap(const char *v, const transfer_none_t &) { return cstring_v(v); } // actually should not accept const input (as it makes no sense for full // transfer) but let's go the runtime way and not mind that too much (code // generation will warn though) inline gi::cstring wrap(const char *v, const transfer_full_t &) { // as said, never mind const return cstring{(char *)v, transfer_full}; } #endif // return const here, as somewhat customary, also // wrapped function call is force-casted anyway (to const char* parameter) // FIXME ?? though const is generally rare and it breaks consistency that way inline const gchar * unwrap(const std::string &v, const transfer_none_t &) { return v.c_str(); } inline const gchar * unwrap(const detail::optional_string &v, const transfer_none_t &) { return v.empty() ? nullptr : v.c_str(); } template inline const gchar * unwrap(const detail::cstr &v, const transfer_none_t &) { return v.c_str(); } inline gchar * unwrap(const std::string &v, const transfer_full_t &) { return g_strdup(v.c_str()); } inline gchar * unwrap(const detail::optional_string &v, const transfer_full_t &) { return v.empty() ? nullptr : g_strdup(v.c_str()); } template inline gchar * unwrap(const gi::detail::cstr &v, const transfer_full_t &) { return g_strdup(v.c_str()); } inline gchar * unwrap(gi::cstring &&v, const transfer_full_t &) { return v.release_(); } // enum conversion template::value>::type * = nullptr> inline typename traits::cpptype::type wrap(T v, const transfer_t & = transfer_dummy) { return (typename traits::cpptype::type)v; } template::value>::type * = nullptr> inline typename traits::ctype::type unwrap(T v, const transfer_t & = transfer_dummy) { return (typename traits::ctype::type)v; } // plain basic pass along template::value>::type * = nullptr> inline T wrap(T v, const transfer_t & = transfer_dummy) { return v; } template::value>::type * = nullptr> inline T unwrap(T v, const transfer_t & = transfer_dummy) { return v; } // callback conversion // async or destroy-notify; // signature forces copy, and std::move is used in unwrap call template::type::CallbackWrapperType * = nullptr> inline typename std::remove_reference::type::CallbackWrapperType unwrap(T &&v, const transfer_t & = transfer_dummy) { return typename std::remove_reference::type::CallbackWrapperType( std::forward(v)); } // call or destroy-notify scope template inline typename std::remove_reference::type::template wrapper_type * unwrap(T &&v, const scope_t &) { return new typename std::remove_reference::type::template wrapper_type( std::forward(v)); } // async scope template inline typename std::remove_reference::type::template wrapper_type * unwrap(T &&v, const scope_async_t &) { return new typename std::remove_reference::type::template wrapper_type( std::forward(v)); } // dynamic GType casting within GObject/interface hierarchy template::value && traits::is_object::type>::value>::type * = nullptr> inline T object_cast(I &&t) { if (!t || !g_type_is_a(t.gobj_type_(), T::get_type_())) { return T(); } else { return wrap((typename T::BaseObjectType *)t.gobj_copy_(), transfer_full); } } // this utility can be used to arrange for pointer-like const-ness // that is, a const shared_ptr is still usable like (non-const) T* // in a way, any wrapper object T acts much like a smart-pointer, // but as the (code generated) methods are non-const, they are not usable // if the wrapper object is const (e.g. captured in a lambda) // this helper object/class can be wrapped around the wrapper (phew) // to absorb/shield the (outer) `const` (as it behaves as other smart pointers) template class cs_ptr { T t; public: // rough check; T is expected to be a pointer wrapper static_assert(sizeof(T) == sizeof(void *), ""); // if T not copy-able, argument may need to be move'd cs_ptr(T _t) : t(std::move(_t)) {} operator T() const & { return t; } operator T() && { return std::move(t); } T *get() const { return &t; } // C++ sacrilege, // but the const of pointer in T does not extend to pointee anyway T *operator*() const { return const_cast(&t); } T *operator->() const { return const_cast(&t); } }; } // namespace gi #endif // GI_WRAP_HPP