Some checks failed
Docker. / Ubuntu (push) Has been cancelled
User-agent updater. / User-agent (push) Failing after 15s
Lock Threads / lock (push) Failing after 10s
Waiting for answer. / waiting-for-answer (push) Failing after 22s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
Close stale issues and PRs / stale (push) Has been cancelled
370 lines
11 KiB
C++
370 lines
11 KiB
C++
#ifndef GI_WRAP_HPP
|
|
#define GI_WRAP_HPP
|
|
|
|
#include "base.hpp"
|
|
#include "string.hpp"
|
|
|
|
GI_MODULE_EXPORT
|
|
namespace gi
|
|
{
|
|
// object/wrapper conversion
|
|
template<typename CType, typename TransferType,
|
|
typename CppType = typename traits::cpptype<CType *>::type,
|
|
typename Enable =
|
|
typename std::enable_if<traits::is_wrapper<CppType>::value>::type>
|
|
inline typename std::remove_const<CppType>::type
|
|
wrap(CType *v, const TransferType &t)
|
|
{
|
|
// should be called with a concrete transfer subtype
|
|
static_assert(!std::is_same<TransferType, transfer_t>::value, "");
|
|
// the class wrap only has to deal with non-const class type
|
|
typedef typename std::remove_const<CppType>::type TNC;
|
|
return CppType::template wrap<TNC>(v, t.value);
|
|
}
|
|
|
|
// special case; wrap an owned box with full transfer
|
|
template<typename CType,
|
|
typename CppType = typename traits::cpptype<CType *>::type,
|
|
typename Enable =
|
|
typename std::enable_if<traits::is_boxed<CppType>::value>::type,
|
|
typename TNC = typename std::remove_const<CppType>::type>
|
|
inline TNC
|
|
wrap(CType *v, const transfer_full_t &)
|
|
{
|
|
return CppType::template wrap<TNC>(v);
|
|
}
|
|
|
|
// special case; wrap a unowned box (that is, transfer none) to the Ref type
|
|
template<typename CType,
|
|
typename CppType = typename traits::cpptype<CType *>::type,
|
|
typename Enable =
|
|
typename std::enable_if<traits::is_boxed<CppType>::value>::type,
|
|
typename RefType = typename traits::reftype<
|
|
typename std::remove_const<CppType>::type>::type>
|
|
inline RefType
|
|
wrap(CType *v, const transfer_none_t &)
|
|
{
|
|
// unowned and no copy in all cases
|
|
return RefType::template wrap<RefType>(v);
|
|
}
|
|
|
|
template<typename T,
|
|
typename std::remove_reference<T>::type::BaseObjectType * = nullptr>
|
|
inline typename traits::ctype<T>::type
|
|
unwrap(T &&v, const transfer_none_t &)
|
|
{
|
|
using DT = typename std::decay<T>::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<DT>::value ||
|
|
traits::is_reftype<DT>::value,
|
|
"transfer none expects refcnt wrapper or reftype (not owning box)");
|
|
return v.gobj_();
|
|
}
|
|
|
|
namespace detail
|
|
{
|
|
// lvalue
|
|
template<typename T,
|
|
typename std::enable_if<!traits::is_boxed<T>::value>::type * = nullptr>
|
|
inline typename traits::ctype<T>::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<T>::value, "boxed copy");
|
|
return v.gobj_copy_();
|
|
}
|
|
|
|
// rvalue
|
|
template<typename T,
|
|
typename std::enable_if<!traits::is_reftype<T>::value>::type * = nullptr>
|
|
inline typename traits::ctype<T>::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<T>::type)v.release_();
|
|
}
|
|
|
|
} // namespace detail
|
|
|
|
template<typename T, typename std::decay<T>::type::BaseObjectType * = nullptr>
|
|
inline typename traits::ctype<T>::type
|
|
unwrap(T &&v, const transfer_full_t &t)
|
|
{
|
|
// universal reference dispatch
|
|
return detail::unwrap(std::forward<T>(v), t, std::is_lvalue_reference<T>());
|
|
}
|
|
|
|
// container types
|
|
template<typename T, typename Transfer,
|
|
typename std::decay<T>::type::_detail::DataType * = nullptr>
|
|
inline typename std::decay<T>::type::_detail::DataType
|
|
unwrap(T &&v, const Transfer &t)
|
|
{
|
|
// universal reference dispatch
|
|
return std::forward<T>(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<typename TargetType, typename CType, typename Transfer,
|
|
decltype(wrap(std::declval<typename std::decay<CType>::type>(),
|
|
Transfer())) * = nullptr>
|
|
TargetType
|
|
wrap_to(CType v, const Transfer &t)
|
|
{
|
|
static_assert(traits::is_decayed<TargetType>::value, "");
|
|
return wrap(v, t);
|
|
}
|
|
|
|
// container case
|
|
template<typename TargetType, typename CType, typename Transfer,
|
|
typename TargetType::_detail::DataType * = nullptr>
|
|
TargetType
|
|
wrap_to(CType v, const Transfer &t)
|
|
{
|
|
static_assert(traits::is_decayed<TargetType>::value, "");
|
|
return TargetType::template _wrap<TargetType>(v, t);
|
|
}
|
|
|
|
// container size case
|
|
template<typename TargetType, typename CType, typename Transfer,
|
|
typename TargetType::_detail::DataType * = nullptr>
|
|
TargetType
|
|
wrap_to(CType v, int s, const Transfer &t)
|
|
{
|
|
static_assert(traits::is_decayed<TargetType>::value, "");
|
|
return TargetType::template _wrap<TargetType>(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<typename Transfer>
|
|
inline const gchar *
|
|
unwrap(const detail::cstr<Transfer> &v, const transfer_none_t &)
|
|
{
|
|
return v.c_str();
|
|
}
|
|
|
|
// R-value variants of the above, akin to transfer_none from an owning R-value
|
|
// bad dangling things would happen
|
|
inline const gchar *unwrap(std::string &&v, const transfer_none_t &) = delete;
|
|
|
|
inline const gchar *unwrap(
|
|
detail::optional_string &&v, const transfer_none_t &) = delete;
|
|
|
|
template<typename Transfer>
|
|
inline const gchar *
|
|
unwrap(detail::cstr<Transfer> &&v, const transfer_none_t &)
|
|
{
|
|
static_assert(std::is_same<Transfer, transfer_none_t>::value,
|
|
"transfer none expects non-owning type");
|
|
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<typename Transfer>
|
|
inline gchar *
|
|
unwrap(const gi::detail::cstr<Transfer> &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<typename T,
|
|
typename std::enable_if<std::is_enum<T>::value>::type * = nullptr>
|
|
inline typename traits::cpptype<T>::type
|
|
wrap(T v, const transfer_t & = transfer_dummy)
|
|
{
|
|
return (typename traits::cpptype<T>::type)v;
|
|
}
|
|
|
|
template<typename T,
|
|
typename std::enable_if<std::is_enum<T>::value>::type * = nullptr>
|
|
inline typename traits::ctype<T>::type
|
|
unwrap(T v, const transfer_t & = transfer_dummy)
|
|
{
|
|
return (typename traits::ctype<T>::type)v;
|
|
}
|
|
|
|
// plain basic pass along
|
|
template<typename T,
|
|
typename std::enable_if<traits::is_basic<T>::value>::type * = nullptr>
|
|
inline T
|
|
wrap(T v, const transfer_t & = transfer_dummy)
|
|
{
|
|
return v;
|
|
}
|
|
|
|
template<typename T,
|
|
typename std::enable_if<traits::is_basic<T>::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<typename T,
|
|
typename std::remove_reference<T>::type::CallbackWrapperType * = nullptr>
|
|
inline typename std::remove_reference<T>::type::CallbackWrapperType
|
|
unwrap(T &&v, const transfer_t & = transfer_dummy)
|
|
{
|
|
return typename std::remove_reference<T>::type::CallbackWrapperType(
|
|
std::forward<T>(v));
|
|
}
|
|
|
|
// call or destroy-notify scope
|
|
template<typename T>
|
|
inline typename std::remove_reference<T>::type::template wrapper_type<false> *
|
|
unwrap(T &&v, const scope_t &)
|
|
{
|
|
return new
|
|
typename std::remove_reference<T>::type::template wrapper_type<false>(
|
|
std::forward<T>(v));
|
|
}
|
|
|
|
// async scope
|
|
template<typename T>
|
|
inline typename std::remove_reference<T>::type::template wrapper_type<true> *
|
|
unwrap(T &&v, const scope_async_t &)
|
|
{
|
|
return new
|
|
typename std::remove_reference<T>::type::template wrapper_type<true>(
|
|
std::forward<T>(v));
|
|
}
|
|
|
|
// dynamic GType casting within GObject/interface hierarchy
|
|
template<typename T, typename I,
|
|
typename std::enable_if<
|
|
traits::is_object<T>::value &&
|
|
traits::is_object<typename std::decay<I>::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<T> 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<typename T>
|
|
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); }
|
|
T *operator->() const { return const_cast<T *>(&t); }
|
|
};
|
|
|
|
} // namespace gi
|
|
|
|
#endif // GI_WRAP_HPP
|