mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-11-10 03:16:17 +01:00
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:
commit
c242972043
@ -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 doesn’t like GLIB_DEPRECATED_ENUMERATOR
|
||||
CFLAGS: '-DGLIB_DISABLE_DEPRECATION_WARNINGS'
|
||||
before_script:
|
||||
- !reference [".build-gobject-introspection", "before_script"]
|
||||
script:
|
||||
- meson setup ${MESON_COMMON_OPTIONS}
|
||||
--werror
|
||||
|
@ -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 can’t 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.
|
||||
|
@ -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 ();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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) */
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
136
girepository/tests/callable-info.c
Normal file
136
girepository/tests/callable-info.c
Normal 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 ();
|
||||
}
|
@ -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,
|
||||
|
@ -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()
|
||||
|
Loading…
Reference in New Issue
Block a user