static
void
store_fields (HV *fields, GIBaseInfo *info, GIInfoType info_type)
{
const
gchar *
namespace
;
AV *av;
gint i;
namespace
= g_base_info_get_name (info);
av = newAV ();
switch
(info_type) {
case
GI_INFO_TYPE_BOXED:
case
GI_INFO_TYPE_STRUCT:
{
gint n_fields = g_struct_info_get_n_fields (
(GIStructInfo *) info);
for
(i = 0; i < n_fields; i++) {
GIFieldInfo *field_info;
const
gchar *field_name;
field_info = g_struct_info_get_field ((GIStructInfo *) info, i);
field_name = g_base_info_get_name ((GIBaseInfo *) field_info);
av_push (av, newSVpv (field_name, 0));
g_base_info_unref ((GIBaseInfo *) field_info);
}
break
;
}
case
GI_INFO_TYPE_UNION:
{
gint n_fields = g_union_info_get_n_fields ((GIUnionInfo *) info);
for
(i = 0; i < n_fields; i++) {
GIFieldInfo *field_info;
const
gchar *field_name;
field_info = g_union_info_get_field ((GIUnionInfo *) info, i);
field_name = g_base_info_get_name ((GIBaseInfo *) field_info);
av_push (av, newSVpv (field_name, 0));
g_base_info_unref ((GIBaseInfo *) field_info);
}
break
;
}
default
:
ccroak (
"store_fields: unsupported info type %d"
, info_type);
}
gperl_hv_take_sv (fields,
namespace
,
strlen
(
namespace
),
newRV_noinc ((SV *) av));
}
static
SV *
get_field (GIFieldInfo *field_info, gpointer mem, GITransfer transfer)
{
GITypeInfo *field_type;
GITypeTag field_tag;
GIBaseInfo *interface_info;
GIInfoType interface_type;
GIArgument value;
SV *sv = NULL;
field_type = g_field_info_get_type (field_info);
field_tag = g_type_info_get_tag (field_type);
interface_info = g_type_info_get_interface (field_type);
interface_type = interface_info
? g_base_info_get_type (interface_info)
: GI_INFO_TYPE_INVALID;
if
(!g_type_info_is_pointer (field_type) &&
field_tag == GI_TYPE_TAG_INTERFACE &&
interface_type == GI_INFO_TYPE_STRUCT)
{
gint offset = g_field_info_get_offset (field_info);
value.v_pointer = G_STRUCT_MEMBER_P (mem, offset);
sv = arg_to_sv (&value,
field_type,
GI_TRANSFER_NOTHING,
GPERL_I11N_MEMORY_SCOPE_IRRELEVANT,
NULL);
}
else
if
(field_tag == GI_TYPE_TAG_VOID &&
g_type_info_is_pointer (field_type))
{
gint offset = g_field_info_get_offset (field_info);
value.v_pointer = G_STRUCT_MEMBER (gpointer, mem, offset);
sv = value.v_pointer
? newRV (value.v_pointer)
: &PL_sv_undef;
}
else
if
(g_field_info_get_field (field_info, mem, &value)) {
sv = arg_to_sv (&value,
field_type,
transfer,
GPERL_I11N_MEMORY_SCOPE_IRRELEVANT,
NULL);
}
else
{
ccroak (
"Could not get field '%s'"
,
g_base_info_get_name (field_info));
}
if
(interface_info)
g_base_info_unref (interface_info);
g_base_info_unref ((GIBaseInfo *) field_type);
return
sv;
}
static
void
set_field (GIFieldInfo *field_info, gpointer mem, GITransfer transfer, SV *sv)
{
GITypeInfo *field_type;
GITypeTag field_tag;
GIBaseInfo *interface_info;
GIInfoType interface_type;
GIArgument arg;
field_type = g_field_info_get_type (field_info);
field_tag = g_type_info_get_tag (field_type);
interface_info = g_type_info_get_interface (field_type);
interface_type = interface_info
? g_base_info_get_type (interface_info)
: GI_INFO_TYPE_INVALID;
if
(field_tag == GI_TYPE_TAG_INTERFACE &&
interface_type == GI_INFO_TYPE_STRUCT)
{
gint offset = g_field_info_get_offset (field_info);
if
(!g_type_info_is_pointer (field_type)) {
gsize size;
arg.v_pointer = sv_to_struct (GI_TRANSFER_NOTHING,
interface_info,
interface_type,
sv);
size = g_struct_info_get_size (interface_info);
memmove
(G_STRUCT_MEMBER_P (mem, offset), arg.v_pointer, size);
}
else
{
GType gtype = get_gtype (interface_info);
if
(g_type_is_a (gtype, G_TYPE_BOXED)) {
gpointer old = G_STRUCT_MEMBER (gpointer, mem, offset);
sv_to_interface (NULL, field_type, GI_TRANSFER_NOTHING,
TRUE, sv, &arg, NULL);
if
(arg.v_pointer != old) {
if
(old)
g_boxed_free (gtype, old);
G_STRUCT_MEMBER (gpointer, mem, offset) =
arg.v_pointer
? g_boxed_copy (gtype, arg.v_pointer)
: NULL;
}
}
else
{
g_assert (gtype == G_TYPE_INVALID || gtype == G_TYPE_NONE);
G_STRUCT_MEMBER (gpointer, mem, offset) =
sv_to_struct (GI_TRANSFER_NOTHING,
interface_info,
interface_type,
sv);
}
}
}
else
if
(field_tag == GI_TYPE_TAG_VOID &&
g_type_info_is_pointer (field_type))
{
gint offset = g_field_info_get_offset (field_info);
if
(!gperl_sv_is_ref (sv))
ccroak (
"Can only put references into void fields"
);
G_STRUCT_MEMBER (gpointer, mem, offset) = SvRV (sv);
}
else
{
sv_to_arg (sv, &arg, NULL, field_type,
transfer, TRUE, NULL);
if
(!g_field_info_set_field (field_info, mem, &arg))
ccroak (
"Could not set field '%s'"
,
g_base_info_get_name (field_info));
}
if
(interface_info)
g_base_info_unref (interface_info);
g_base_info_unref (field_type);
}