Merge branch 'ewlsh/gi-async-function-annotations' into 'main'

girepository: Add APIs for sync, async, and finish function annotations

See merge request GNOME/glib!3746
This commit is contained in:
Philip Withnall 2024-08-26 16:40:54 +00:00
commit c242972043
14 changed files with 685 additions and 10 deletions

View File

@ -16,6 +16,7 @@ variables:
DEBIAN_IMAGE: "registry.gitlab.gnome.org/gnome/glib/debian-stable:v19"
ALPINE_IMAGE: "registry.gitlab.gnome.org/gnome/glib/alpine:v3"
MINGW_IMAGE: "registry.gitlab.gnome.org/gnome/glib/mingw:v39.1"
GOBJECT_INTROSPECTION_TAG: "1.80.1"
MESON_TEST_TIMEOUT_MULTIPLIER: 4
G_MESSAGES_DEBUG: all
MESON_COMMON_OPTIONS: "--buildtype debug --wrap-mode=nodownload --fatal-meson-warnings"
@ -105,6 +106,17 @@ variables:
when: manual
allow_failure: true
.build-gobject-introspection:
before_script:
- mkdir -p gobject-introspection
- git clone --branch $GOBJECT_INTROSPECTION_TAG https://gitlab.gnome.org/GNOME/gobject-introspection.git gobject-introspection
- meson gobject-introspection gobject-introspection/build --prefix=/usr
- sudo meson install -C gobject-introspection/build
artifacts:
expire_in: 3 days
paths:
- gobject-introspection
.build-linux:
before_script:
- bash .gitlab-ci/show-execution-environment.sh
@ -167,6 +179,7 @@ style-check-mandatory:
fedora-x86_64:
extends:
- .build-gobject-introspection
- .build-linux
- .only-default-and-merges
- .with-git
@ -179,6 +192,7 @@ fedora-x86_64:
before_script:
- !reference [".build-linux", "before_script"]
- !reference [".with-git", "before_script"]
- !reference [".build-gobject-introspection", "before_script"]
script:
- meson setup ${MESON_COMMON_OPTIONS}
--werror
@ -374,6 +388,7 @@ G_DISABLE_ASSERT:
- .build-linux
- .only-schedules-or-manual
- .with-git
- .build-gobject-introspection
image: $FEDORA_IMAGE
stage: build
needs: []
@ -382,6 +397,7 @@ G_DISABLE_ASSERT:
before_script:
- !reference [".build-linux", "before_script"]
- !reference [".with-git", "before_script"]
- !reference [".build-gobject-introspection", "before_script"]
script:
- meson setup ${MESON_COMMON_OPTIONS}
--werror
@ -412,6 +428,7 @@ valgrind:
- .build-linux
- .only-schedules-or-manual
- .with-git
- .build-gobject-introspection
image: $FEDORA_IMAGE
stage: analysis
needs: []
@ -420,6 +437,7 @@ valgrind:
before_script:
- !reference [".build-linux", "before_script"]
- !reference [".with-git", "before_script"]
- !reference [".build-gobject-introspection", "before_script"]
script:
- meson setup ${MESON_COMMON_OPTIONS}
--werror
@ -748,6 +766,7 @@ scan-build:
extends:
- .build-linux
- .only-schedules-or-manual
- .build-gobject-introspection
image: $FEDORA_IMAGE
stage: analysis
needs: []
@ -768,6 +787,8 @@ scan-build:
--exclude gio/xdgmime/
-disable-checker deadcode.DeadStores
--status-bugs
before_script:
- !reference [".build-gobject-introspection", "before_script"]
script:
- meson setup ${MESON_COMMON_OPTIONS}
--werror
@ -793,12 +814,15 @@ scan-build:
extends:
- .build-linux
- .only-schedules-or-manual-in-default-branch
- .build-gobject-introspection
image: $COVERITY_IMAGE
stage: analysis
needs: []
variables:
# cov-build doesnt like GLIB_DEPRECATED_ENUMERATOR
CFLAGS: '-DGLIB_DISABLE_DEPRECATION_WARNINGS'
before_script:
- !reference [".build-gobject-introspection", "before_script"]
script:
- meson setup ${MESON_COMMON_OPTIONS}
--werror

View File

@ -34,6 +34,11 @@ PATH="$(cygpath "$USERPROFILE")/.local/bin:$HOME/.local/bin:$PATH"
DIR="$(pwd)"
export PATH CFLAGS
mkdir -p gobject-introspection
git clone --branch "${GOBJECT_INTROSPECTION_TAG}" https://gitlab.gnome.org/GNOME/gobject-introspection.git gobject-introspection
meson gobject-introspection gobject-introspection/build --prefix "/c/msys64/${MSYSTEM}/usr"
meson install -C gobject-introspection/build
# FIXME: We cant use ${MESON_COMMON_OPTIONS} here because this script installs
# Meson 1.3. See the comment in .gitlab-ci.yml about the same problem on
# FreeBSD.

View File

@ -35,6 +35,8 @@
#include "girffi.h"
#include "gicallableinfo.h"
#define GET_BLOB(Type, rinfo) ((Type *) &rinfo->typelib->data[rinfo->offset])
/* GICallableInfo functions */
/**
@ -839,3 +841,193 @@ gi_callable_info_class_init (gpointer g_class,
info_class->info_type = GI_INFO_TYPE_CALLABLE;
}
static GICallableInfo *
get_method_callable_info_for_index (GIBaseInfo *rinfo,
unsigned int index)
{
GIBaseInfo *container = rinfo->container;
g_assert (container);
if (GI_IS_OBJECT_INFO (container))
return (GICallableInfo *) gi_object_info_get_method ((GIObjectInfo *) container, index);
if (GI_IS_INTERFACE_INFO (container))
return (GICallableInfo *) gi_interface_info_get_method ((GIInterfaceInfo *) container,
index);
return NULL;
}
static GICallableInfo *
get_callable_info_for_index (GIBaseInfo *rinfo,
unsigned int index)
{
if (!rinfo->container)
{
GIBaseInfo *info = gi_info_from_entry (rinfo->repository, rinfo->typelib, index);
g_assert (GI_IS_CALLABLE_INFO (info));
return (GICallableInfo *) info;
}
return get_method_callable_info_for_index (rinfo, index);
}
/**
* gi_callable_info_get_async_function
* @info: a callable info structure
*
* Gets the callable info for the callable's asynchronous version
*
* Returns: (transfer full) (nullable): a [class@GIRepository.CallableInfo] for the
* async function or `NULL` if not defined.
* Since: 2.84
*/
GICallableInfo *
gi_callable_info_get_async_function (GICallableInfo *info)
{
GIBaseInfo *rinfo = (GIBaseInfo *) info;
switch (gi_base_info_get_info_type (rinfo))
{
case GI_INFO_TYPE_FUNCTION:
{
FunctionBlob *blob = GET_BLOB (FunctionBlob, rinfo);
if (blob->is_async || blob->sync_or_async == ASYNC_SENTINEL)
return NULL;
return get_callable_info_for_index (rinfo, blob->sync_or_async);
}
case GI_INFO_TYPE_VFUNC:
{
VFuncBlob *blob = GET_BLOB (VFuncBlob, rinfo);
if (blob->is_async || blob->sync_or_async == ASYNC_SENTINEL)
return NULL;
return get_method_callable_info_for_index (rinfo, blob->sync_or_async);
}
case GI_INFO_TYPE_CALLBACK:
case GI_INFO_TYPE_SIGNAL:
return NULL;
default:
g_assert_not_reached ();
}
}
/**
* gi_callable_info_get_sync_function
* @info: a callable info structure
*
* Gets the callable info for the callable's synchronous version
*
* Returns: (transfer full) (nullable): a [class@GIRepository.CallableInfo] for the
* sync function or `NULL` if not defined.
* Since: 2.84
*/
GICallableInfo *
gi_callable_info_get_sync_function (GICallableInfo *info)
{
GIBaseInfo *rinfo = (GIBaseInfo *) info;
switch (gi_base_info_get_info_type (rinfo))
{
case GI_INFO_TYPE_FUNCTION:
{
FunctionBlob *blob = GET_BLOB (FunctionBlob, rinfo);
if (!blob->is_async || blob->sync_or_async == ASYNC_SENTINEL)
return NULL;
return get_callable_info_for_index (rinfo, blob->sync_or_async);
}
case GI_INFO_TYPE_VFUNC:
{
VFuncBlob *blob = GET_BLOB (VFuncBlob, rinfo);
if (!blob->is_async || blob->sync_or_async == ASYNC_SENTINEL)
return NULL;
return get_method_callable_info_for_index (rinfo, blob->sync_or_async);
}
case GI_INFO_TYPE_CALLBACK:
case GI_INFO_TYPE_SIGNAL:
return NULL;
default:
g_assert_not_reached ();
}
}
/**
* gi_callable_info_get_finish_function
* @info: a callable info structure
*
* Gets the info for an async function's corresponding finish function
*
* Returns: (transfer full) (nullable): a [class@GIRepository.CallableInfo] for the
* finish function or `NULL` if not defined.
* Since: 2.84
*/
GICallableInfo *
gi_callable_info_get_finish_function (GICallableInfo *info)
{
GIBaseInfo *rinfo = (GIBaseInfo *) info;
switch (gi_base_info_get_info_type (rinfo))
{
case GI_INFO_TYPE_FUNCTION:
{
FunctionBlob *blob = GET_BLOB (FunctionBlob, rinfo);
if (!blob->is_async || blob->finish == ASYNC_SENTINEL)
return NULL;
return get_callable_info_for_index (rinfo, blob->finish);
}
case GI_INFO_TYPE_VFUNC:
{
VFuncBlob *blob = GET_BLOB (VFuncBlob, rinfo);
if (!blob->is_async || blob->finish == ASYNC_SENTINEL)
return NULL;
return get_method_callable_info_for_index (rinfo, blob->finish);
}
case GI_INFO_TYPE_CALLBACK:
case GI_INFO_TYPE_SIGNAL:
return NULL;
default:
g_assert_not_reached ();
}
}
/**
* gi_callable_info_is_async
* @info: a callable info structure
*
* Gets whether a callable is async. Async callables have a
* [type@Gio.AsyncReadyCallback] parameter and user data.
*
* Returns: true if the callable is async
* Since: 2.84
*/
gboolean
gi_callable_info_is_async (GICallableInfo *callable_info)
{
GIBaseInfo *info = (GIBaseInfo *) callable_info;
switch (gi_base_info_get_info_type ((GIBaseInfo *) callable_info))
{
case GI_INFO_TYPE_FUNCTION:
{
return GET_BLOB (FunctionBlob, info)->is_async;
}
case GI_INFO_TYPE_VFUNC:
{
return GET_BLOB (VFuncBlob, info)->is_async;
}
case GI_INFO_TYPE_CALLBACK:
case GI_INFO_TYPE_SIGNAL:
return FALSE;
default:
g_assert_not_reached ();
}
}

View File

@ -116,4 +116,16 @@ gboolean gi_callable_info_invoke (GICallableInfo *info
GI_AVAILABLE_IN_ALL
GITransfer gi_callable_info_get_instance_ownership_transfer (GICallableInfo *info);
GI_AVAILABLE_IN_2_84
GICallableInfo *gi_callable_info_get_async_function (GICallableInfo *info);
GI_AVAILABLE_IN_2_84
GICallableInfo *gi_callable_info_get_sync_function (GICallableInfo *info);
GI_AVAILABLE_IN_2_84
GICallableInfo *gi_callable_info_get_finish_function (GICallableInfo *info);
GI_AVAILABLE_IN_2_84
gboolean gi_callable_info_is_async (GICallableInfo *info);
G_END_DECLS

View File

@ -140,6 +140,9 @@ gi_function_info_get_flags (GIFunctionInfo *info)
if (blob->wraps_vfunc)
flags = flags | GI_FUNCTION_WRAPS_VFUNC;
if (blob->is_async)
flags = flags | GI_FUNCTION_IS_ASYNC;
return flags;
}

View File

@ -123,9 +123,13 @@ struct _GIIrNodeFunction
uint8_t wraps_vfunc : 1;
uint8_t throws : 1;
uint8_t instance_transfer_full : 1;
uint8_t is_async : 1;
char *symbol; /* (owned) */
char *property; /* (owned) */
char *finish_func; /* (owned) */
char *sync_func; /* (owned) */
char *async_func; /* (owned) */
GIIrNodeParam *result; /* (owned) */
GList *parameters; /* (element-type GIIrNode) (owned) */
@ -237,8 +241,12 @@ struct _GIIrNodeVFunc
uint8_t is_class_closure : 1;
uint8_t throws : 1;
uint8_t instance_transfer_full : 1;
uint8_t is_async : 1;
char *invoker; /* (owned) */
char *finish_func; /* (owned) */
char *sync_func; /* (owned) */
char *async_func; /* (owned) */
GList *parameters; /* (element-type GIIrNode) (owned) */
GIIrNodeParam *result; /* (owned) */

View File

@ -223,6 +223,9 @@ gi_ir_node_free (GIIrNode *node)
g_free (node->name);
g_free (function->symbol);
g_free (function->property);
g_free (function->async_func);
g_free (function->sync_func);
g_free (function->finish_func);
gi_ir_node_free ((GIIrNode *)function->result);
for (l = function->parameters; l; l = l->next)
gi_ir_node_free ((GIIrNode *)l->data);
@ -281,6 +284,9 @@ gi_ir_node_free (GIIrNode *node)
GIIrNodeVFunc *vfunc = (GIIrNodeVFunc *)node;
g_free (node->name);
g_free (vfunc->async_func);
g_free (vfunc->sync_func);
g_free (vfunc->finish_func);
g_free (vfunc->invoker);
for (l = vfunc->parameters; l; l = l->next)
gi_ir_node_free ((GIIrNode *)l->data);
@ -1218,6 +1224,27 @@ get_index_of_member_type (GIIrNodeInterface *node,
return index;
}
static int
get_index_for_function (GIIrTypelibBuild *build,
GIIrNode *parent,
const char *name)
{
if (parent == NULL)
{
uint16_t index = find_entry (build, name);
if (index == 0)
return -1;
return index;
}
int index = get_index_of_member_type ((GIIrNodeInterface *) parent, GI_IR_NODE_FUNCTION, name);
if (index != -1)
return index;
return -1;
}
static void
serialize_type (GIIrTypelibBuild *build,
GIIrNodeType *node,
@ -1706,6 +1733,61 @@ gi_ir_node_build_typelib (GIIrNode *node,
blob->name = gi_ir_write_string (node->name, strings, data, offset2);
blob->symbol = gi_ir_write_string (function->symbol, strings, data, offset2);
blob->signature = signature;
blob->finish = ASYNC_SENTINEL;
blob->sync_or_async = ASYNC_SENTINEL;
blob->is_async = function->is_async;
if (function->is_async)
{
if (function->sync_func != NULL)
{
int sync_index =
get_index_for_function (build,
parent,
function->sync_func);
if (sync_index == -1)
{
g_error ("Unknown sync function %s:%s",
parent->name, function->sync_func);
}
blob->sync_or_async = (uint16_t) sync_index;
}
if (function->finish_func != NULL)
{
int finish_index =
get_index_for_function (build,
parent,
function->finish_func);
if (finish_index == -1)
{
g_error ("Unknown finish function %s:%s", parent->name, function->finish_func);
}
blob->finish = (uint16_t) finish_index;
}
}
else
{
if (function->async_func != NULL)
{
int async_index =
get_index_for_function (build,
parent,
function->async_func);
if (async_index == -1)
{
g_error ("Unknown async function %s:%s", parent->name, function->async_func);
}
blob->sync_or_async = (uint16_t) async_index;
}
}
if (function->is_setter || function->is_getter)
{
@ -1876,6 +1958,9 @@ gi_ir_node_build_typelib (GIIrNode *node,
blob->class_closure = 0; /* FIXME */
blob->throws = vfunc->throws; /* Deprecated. Also stored in SignatureBlob. */
blob->reserved = 0;
blob->is_async = vfunc->is_async;
blob->finish = ASYNC_SENTINEL;
blob->sync_or_async = ASYNC_SENTINEL;
if (vfunc->invoker)
{
@ -1889,6 +1974,58 @@ gi_ir_node_build_typelib (GIIrNode *node,
else
blob->invoker = 0x3ff; /* max of 10 bits */
if (vfunc->is_async)
{
if (vfunc->sync_func != NULL)
{
int sync_index =
get_index_of_member_type ((GIIrNodeInterface *) parent,
GI_IR_NODE_VFUNC,
vfunc->sync_func);
if (sync_index == -1)
{
g_error ("Unknown sync vfunc %s:%s for accessor %s",
parent->name, vfunc->sync_func, vfunc->invoker);
}
blob->sync_or_async = (uint16_t) sync_index;
}
if (vfunc->finish_func != NULL)
{
int finish_index =
get_index_of_member_type ((GIIrNodeInterface *) parent,
GI_IR_NODE_VFUNC,
vfunc->finish_func);
if (finish_index == -1)
{
g_error ("Unknown finish vfunc %s:%s for function %s",
parent->name, vfunc->finish_func, vfunc->invoker);
}
blob->finish = (uint16_t) finish_index;
}
}
else
{
if (vfunc->async_func != NULL)
{
int async_index =
get_index_of_member_type ((GIIrNodeInterface *) parent,
GI_IR_NODE_VFUNC,
vfunc->async_func);
if (async_index == -1)
{
g_error ("Unknown async vfunc %s:%s for accessor %s",
parent->name, vfunc->async_func, vfunc->invoker);
}
blob->sync_or_async = (uint16_t) async_index;
}
}
blob->struct_offset = vfunc->offset;
blob->reserved2 = 0;
blob->signature = signature;

View File

@ -391,6 +391,17 @@ locate_gir (GIIrParser *parser,
line_number, char_number, attribute, element); \
} while (0)
#define INVALID_ATTRIBUTE(context,error,element,attribute,reason) \
do { \
int line_number, char_number; \
g_markup_parse_context_get_position (context, &line_number, &char_number); \
g_set_error (error, \
G_MARKUP_ERROR, \
G_MARKUP_ERROR_INVALID_CONTENT, \
"Line %d, character %d: The attribute '%s' on the element '%s' is not valid: %s", \
line_number, char_number, attribute, element, reason); \
} while (0)
static const char *
find_attribute (const char *name,
const char **attribute_names,
@ -901,6 +912,9 @@ start_function (GMarkupParseContext *context,
const char *throws;
const char *set_property;
const char *get_property;
const char *finish_func;
const char *async_func;
const char *sync_func;
GIIrNodeFunction *function;
gboolean found = FALSE;
ParseState in_embedded_state = STATE_NONE;
@ -951,6 +965,9 @@ start_function (GMarkupParseContext *context,
throws = find_attribute ("throws", attribute_names, attribute_values);
set_property = find_attribute ("glib:set-property", attribute_names, attribute_values);
get_property = find_attribute ("glib:get-property", attribute_names, attribute_values);
finish_func = find_attribute ("glib:finish-func", attribute_names, attribute_values);
sync_func = find_attribute ("glib:sync-func", attribute_names, attribute_values);
async_func = find_attribute ("glib:async-func", attribute_names, attribute_values);
if (name == NULL)
{
@ -977,6 +994,55 @@ start_function (GMarkupParseContext *context,
else
function->deprecated = FALSE;
function->is_async = FALSE;
function->async_func = NULL;
function->sync_func = NULL;
function->finish_func = NULL;
// Only asynchronous functions have a glib:sync-func defined
if (sync_func != NULL)
{
if (G_UNLIKELY (async_func != NULL))
{
INVALID_ATTRIBUTE (context, error, element_name, "glib:sync-func", "glib:sync-func should only be defined with asynchronous "
"functions");
return FALSE;
}
function->is_async = TRUE;
function->sync_func = g_strdup (sync_func);
}
// Only synchronous functions have a glib:async-func defined
if (async_func != NULL)
{
if (G_UNLIKELY (sync_func != NULL))
{
INVALID_ATTRIBUTE (context, error, element_name, "glib:async-func", "glib:async-func should only be defined with synchronous "
"functions");
return FALSE;
}
function->is_async = FALSE;
function->async_func = g_strdup (async_func);
}
if (finish_func != NULL)
{
if (G_UNLIKELY (async_func != NULL))
{
INVALID_ATTRIBUTE (context, error, element_name, "glib:finish-func", "glib:finish-func should only be defined with asynchronous "
"functions");
return FALSE;
}
function->is_async = TRUE;
function->finish_func = g_strdup (finish_func);
}
if (strcmp (element_name, "method") == 0 ||
strcmp (element_name, "constructor") == 0)
{
@ -2594,6 +2660,9 @@ start_vfunc (GMarkupParseContext *context,
const char *offset;
const char *invoker;
const char *throws;
const char *finish_func;
const char *async_func;
const char *sync_func;
GIIrNodeInterface *iface;
GIIrNodeVFunc *vfunc;
guint64 parsed_offset;
@ -2613,6 +2682,9 @@ start_vfunc (GMarkupParseContext *context,
offset = find_attribute ("offset", attribute_names, attribute_values);
invoker = find_attribute ("invoker", attribute_names, attribute_values);
throws = find_attribute ("throws", attribute_names, attribute_values);
finish_func = find_attribute ("glib:finish-func", attribute_names, attribute_values);
sync_func = find_attribute ("glib:sync-func", attribute_names, attribute_values);
async_func = find_attribute ("glib:async-func", attribute_names, attribute_values);
if (name == NULL)
{
@ -2666,6 +2738,56 @@ start_vfunc (GMarkupParseContext *context,
return FALSE;
}
vfunc->is_async = FALSE;
vfunc->async_func = NULL;
vfunc->sync_func = NULL;
vfunc->finish_func = NULL;
// Only asynchronous functions have a glib:sync-func defined
if (sync_func != NULL)
{
if (G_UNLIKELY (async_func != NULL))
{
INVALID_ATTRIBUTE (context, error, element_name, "glib:sync-func", "glib:sync-func should only be defined with asynchronous "
"functions");
return FALSE;
}
vfunc->is_async = TRUE;
vfunc->sync_func = g_strdup (sync_func);
}
// Only synchronous functions have a glib:async-func defined
if (async_func != NULL)
{
if (G_UNLIKELY (sync_func != NULL))
{
INVALID_ATTRIBUTE (context, error, element_name, "glib:async-func", "glib:async-func should only be defined with synchronous "
"functions");
return FALSE;
}
vfunc->is_async = FALSE;
vfunc->async_func = g_strdup (async_func);
}
if (finish_func != NULL)
{
if (G_UNLIKELY (async_func != NULL))
{
INVALID_ATTRIBUTE (context, error, element_name, "glib:finish-func", "glib:finish-func should only be defined with asynchronous "
"functions");
return FALSE;
}
vfunc->is_async = TRUE;
vfunc->finish_func = g_strdup (finish_func);
}
vfunc->invoker = g_strdup (invoker);
iface = (GIIrNodeInterface *)CURRENT_NODE (ctx);

View File

@ -461,6 +461,9 @@ write_callable_info (const char *ns,
Xml *file)
{
GITypeInfo *type;
GICallableInfo *async_func;
GICallableInfo *sync_func;
GICallableInfo *finish_func;
if (gi_callable_info_can_throw_gerror (info))
xml_printf (file, " throws=\"1\"");
@ -468,6 +471,18 @@ write_callable_info (const char *ns,
write_attributes (file, (GIBaseInfo*) info);
type = gi_callable_info_get_return_type (info);
async_func = gi_callable_info_get_async_function (info);
sync_func = gi_callable_info_get_sync_function (info);
finish_func = gi_callable_info_get_finish_function (info);
if (sync_func)
xml_printf (file, " glib:sync-func=\"%s\"", gi_base_info_get_name ((GIBaseInfo*) sync_func));
if (finish_func)
xml_printf (file, " glib:finish-func=\"%s\"", gi_base_info_get_name ((GIBaseInfo*) finish_func));
if (async_func)
xml_printf (file, " glib:async-func=\"%s\"", gi_base_info_get_name ((GIBaseInfo*) async_func));
xml_start_element (file, "return-value");

View File

@ -598,7 +598,11 @@ typedef struct {
* return value type.
* @is_static: The function is a "static method"; in other words it's a pure
* function whose name is conceptually scoped to the object.
* @is_async: Whether the function is asynchronous
* @sync_or_async: The index of the synchronous version of the function if is_async is TRUE,
* otherwise, the index of the asynchronous version.
* @reserved: Reserved for future use.
* @finish: The index of the finish function if is_async is TRUE, otherwise ASYNC_SENTINEL
* @reserved2: Reserved for future use.
*
* TODO
@ -614,7 +618,7 @@ typedef struct {
uint16_t constructor : 1;
uint16_t wraps_vfunc : 1;
uint16_t throws : 1;
uint16_t index :10;
uint16_t index : 10;
/* Note the bits above need to match CommonBlob
* and are thus exhausted, extend things using
* the reserved block below. */
@ -623,9 +627,13 @@ typedef struct {
uint32_t symbol;
uint32_t signature;
uint16_t is_static : 1;
uint16_t reserved : 15;
uint16_t reserved2 : 16;
uint16_t is_static : 1;
uint16_t is_async : 1;
uint16_t sync_or_async : 10;
uint16_t reserved : 4;
uint16_t finish : 10;
uint16_t reserved2 : 6;
} FunctionBlob;
/**
@ -993,6 +1001,7 @@ typedef struct {
} EnumBlob;
#define ACCESSOR_SENTINEL 0x3ff
#define ASYNC_SENTINEL 0x3ff
/**
* PropertyBlob:
@ -1098,7 +1107,9 @@ typedef struct {
* @class_closure: Set if this virtual function is the class closure of a
* signal.
* @throws: This is now additionally stored in the #SignatureBlob. (deprecated)
* @reserved: Reserved for future use.
* @is_async: Whether the virtual function is asynchronous
* @sync_or_async: The index of the synchronous version of the virtual function if is_async is TRUE,
* otherwise, the index of the asynchronous version.
* @signal: The index of the signal in the list of signals of the object or
* interface to which this virtual function belongs.
* @struct_offset: The offset of the function pointer in the class struct.
@ -1106,6 +1117,8 @@ typedef struct {
* @invoker: If a method invoker for this virtual exists, this is the offset
* in the class structure of the method. If no method is known, this value
* will be 0x3ff.
* @reserved: Reserved for future use.
* @finish: The index of the finish function if is_async is TRUE, otherwise ASYNC_SENTINEL
* @reserved2: Reserved for future use.
* @reserved3: Reserved for future use.
* @signature: Offset of the SignatureBlob describing the parameter types and
@ -1123,14 +1136,18 @@ typedef struct {
uint16_t must_not_be_implemented : 1;
uint16_t class_closure : 1;
uint16_t throws : 1;
uint16_t reserved :11;
uint16_t is_async : 1;
uint16_t sync_or_async : 10;
uint16_t signal;
uint16_t struct_offset;
uint16_t invoker : 10; /* Number of bits matches @index in FunctionBlob */
uint16_t reserved2 : 6;
uint16_t invoker : 10; /* Number of bits matches @index in FunctionBlob */
uint16_t reserved : 6;
uint16_t finish : 10;
uint16_t reserved2 : 6;
uint16_t reserved3 : 16;
uint32_t reserved3;
uint32_t signature;
} VFuncBlob;

View File

@ -416,6 +416,7 @@ typedef enum
GI_FUNCTION_IS_GETTER = 1 << 2,
GI_FUNCTION_IS_SETTER = 1 << 3,
GI_FUNCTION_WRAPS_VFUNC = 1 << 4,
GI_FUNCTION_IS_ASYNC = 1 << 5,
} GIFunctionInfoFlags;
G_END_DECLS

View File

@ -0,0 +1,136 @@
/*
* Copyright 2024 GNOME Foundation, Inc.
* Copyright 2024 Evan Welsh
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
* Author: Evan Welsh <contact@evanwelsh.com>
*/
#include "girepository.h"
#include "test-common.h"
static void
test_callable_get_sync_function_for_async_function (RepositoryFixture *fx,
const void *unused)
{
GIBaseInfo *info;
info = gi_repository_find_by_name (fx->repository, "Gio", "File");
g_assert_nonnull (info);
g_assert_true (GI_IS_INTERFACE_INFO (info));
GICallableInfo *callable_info = (GICallableInfo *) gi_interface_info_find_method ((GIInterfaceInfo *) info, "load_contents_async");
g_assert_nonnull (callable_info);
g_assert_true (gi_callable_info_is_async (callable_info));
GICallableInfo *sync_info = gi_callable_info_get_sync_function (callable_info);
g_assert_nonnull (sync_info);
GICallableInfo *finish_info = gi_callable_info_get_finish_function (callable_info);
g_assert_nonnull (finish_info);
g_assert_cmpstr (gi_base_info_get_name ((GIBaseInfo *) sync_info), ==, "load_contents");
g_assert_cmpstr (gi_base_info_get_name ((GIBaseInfo *) finish_info), ==, "load_contents_finish");
GICallableInfo *async_info = gi_callable_info_get_async_function (sync_info);
g_assert_cmpstr (gi_base_info_get_name ((GIBaseInfo *) async_info), ==, "load_contents_async");
gi_base_info_unref (async_info);
gi_base_info_unref (sync_info);
gi_base_info_unref (finish_info);
gi_base_info_unref (callable_info);
gi_base_info_unref (info);
}
static void
test_callable_get_async_function_for_sync_function (RepositoryFixture *fx,
const void *unused)
{
GIBaseInfo *info;
info = gi_repository_find_by_name (fx->repository, "Gio", "File");
g_assert_nonnull (info);
g_assert_true (g_type_is_a (G_TYPE_FROM_INSTANCE (info), gi_interface_info_get_type ()));
GICallableInfo *callable_info = (GICallableInfo *) gi_interface_info_find_method ((GIInterfaceInfo *) info, "load_contents");
{
GICallableInfo *async_func = gi_callable_info_get_async_function (callable_info);
g_assert_nonnull (async_func);
GICallableInfo *finish_func = gi_callable_info_get_finish_function (callable_info);
g_assert_null (finish_func);
GICallableInfo *sync_func = gi_callable_info_get_sync_function (callable_info);
g_assert_null (sync_func);
gi_base_info_unref ((GIBaseInfo *) async_func);
}
GICallableInfo *async_info = gi_callable_info_get_async_function (callable_info);
{
GICallableInfo *async_func = gi_callable_info_get_async_function (async_info);
g_assert_null (async_func);
GICallableInfo *finish_func = gi_callable_info_get_finish_function (async_info);
g_assert_nonnull (finish_func);
GICallableInfo *sync_func = gi_callable_info_get_sync_function (async_info);
g_assert_nonnull (sync_func);
gi_base_info_unref ((GIBaseInfo *) finish_func);
gi_base_info_unref ((GIBaseInfo *) sync_func);
}
g_assert_cmpstr (gi_base_info_get_name ((GIBaseInfo *) async_info), ==, "load_contents_async");
GICallableInfo *sync_info = gi_callable_info_get_sync_function (async_info);
{
GICallableInfo *async_func = gi_callable_info_get_async_function (sync_info);
g_assert_nonnull (async_func);
GICallableInfo *finish_func = gi_callable_info_get_finish_function (sync_info);
g_assert_null (finish_func);
GICallableInfo *sync_func = gi_callable_info_get_sync_function (sync_info);
g_assert_null (sync_func);
gi_base_info_unref ((GIBaseInfo *) async_func);
}
g_assert_cmpstr (gi_base_info_get_name ((GIBaseInfo *) sync_info), ==, "load_contents");
gi_base_info_unref ((GIBaseInfo *) async_info);
gi_base_info_unref ((GIBaseInfo *) sync_info);
gi_base_info_unref ((GIBaseInfo *) callable_info);
gi_base_info_unref (info);
}
int
main (int argc, char **argv)
{
repository_init (&argc, &argv);
ADD_REPOSITORY_TEST ("/callable-info/sync-function", test_callable_get_sync_function_for_async_function, &typelib_load_spec_gio);
ADD_REPOSITORY_TEST ("/callable-info/async-function", test_callable_get_async_function_for_sync_function, &typelib_load_spec_gio);
return g_test_run ();
}

View File

@ -43,6 +43,9 @@ if enable_gir
]
girepository_tests += {
'callable-info' : {
'depends': gio_gir_testing_dep,
},
'function-info' : {
'dependencies': [libffi_dep],
'depends': glib_gir_testing_dep,

View File

@ -2600,7 +2600,7 @@ if enable_systemtap
endif
# introspection
gir_scanner = find_program('g-ir-scanner', required: get_option('introspection'))
gir_scanner = find_program('g-ir-scanner', required: get_option('introspection'), version: '>= 1.80.0')
enable_gir = get_option('introspection').allowed() and gir_scanner.found() and meson.can_run_host_binaries()
if get_option('introspection').enabled() and not meson.can_run_host_binaries()