1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322
|
#ifndef GI_WRAP_HPP
#define GI_WRAP_HPP
#include "base.hpp"
#include "string.hpp"
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();
}
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);
}
}
} // namespace gi
#endif // GI_WRAP_HPP
|