mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-02-02 17:26:17 +01:00
gibaseinfo: Stop building GIBoxedInfo instances
Instead, add a method on `GIRegisteredTypeInfo` which indicates whether the registered type is a boxed type. This will return true for `GIStructInfo` and `GIUnionInfo` instances which are boxed (not all structs and unions are). This makes `GIBoxedInfo` redundant, and it’ll be dropped in a following commit. --- There are several different things which typelibs need to be able to represent: 1. Plain old datatype (POD) structs 2. POD unions 3. Structs with a copy func and/or free func 4. Unions with a copy func and/or free func 5. Structs which are the ‘GType struct’ for an object or interface (i.e. the class or instance or interface struct) 6. Structs with a copy func and free func *and* boxed GType 7. Unions with a copy func and free func *and* boxed GType 8. Boxed GTypes which represent something other than a struct or union So there’s a lot going on here. In commit e28078c70cbf4a57c7dbd39626f43f9bd2674145, a lot of this was reworked, and support was added for boxed unions and boxed ‘others’ (the last item on the list above). Since then, support for boxed types other than structs seems to have atrophied a bit, and the whole lot has got a bit confusing. It was perhaps less confusing when all the `GIBaseInfo` subclasses were actually aliases of each other, but now they have subtype relationships, the position of `GIBoxedInfo` in that type hierarchy has become unclear. How is it related to `GIStructInfo`, `GIUnionInfo` and `GIRegisteredTypeInfo`? Since a boxed type is necessarily a `GIRegisteredTypeInfo`, and the methods of `GIRegisteredTypeInfo` are all written to allow a `GType` to be optional, so that `GIStructInfo` and `GIUnionInfo` can safely derive from it and still be used to represent plain old datatypes without `GType`s, it makes sense to add a method to `GIRegisteredTypeInfo` to indicate that the registered type is derived from `G_TYPE_BOXED`. Accordingly, the things above are now represented in libgirepository’s type system as: 1. `GIStructInfo` instance, `GIRegisteredTypeInfo` methods return no `GType` info 2. `GIUnionInfo` instance similarly 3. `GIStructInfo` instance, `GIRegisteredTypeInfo` methods return no `GType` info, `gi_struct_info_get_{copy,free}_function_name()` return non-`NULL` values 4. `GIUnionInfo` instance similarly 5. `GIStructInfo` instance, `GIRegisteredTypeInfo` methods return no `GType` info, `gi_struct_info_is_gtype_struct()` returns true 6. `GIStructInfo` instance, `GIRegisteredTypeInfo` methods return valid `GType` information, `gi_registered_type_info_is_boxed()` returns true, `gi_struct_info_get_{copy,free}_function_name()` return `NULL` values (because the copy/free functions are hidden inside the boxed type registration at runtime) 7. `GIUnionInfo` instance similarly 8. Not representable, but could be represented in future by re-adding a `GIBoxedInfo` type which derives from `GIRegisteredTypeInfo` and is used solely for boxed ‘other’ types, *not* boxed structs or unions Signed-off-by: Philip Withnall <pwithnall@gnome.org> Fixes: #3245
This commit is contained in:
parent
54f156bd63
commit
0fd99a9f16
@ -50,6 +50,13 @@
|
|||||||
* Most users want to call [method@GIRepository.RegisteredTypeInfo.get_g_type]
|
* Most users want to call [method@GIRepository.RegisteredTypeInfo.get_g_type]
|
||||||
* and don’t worry about the rest of the details.
|
* and don’t worry about the rest of the details.
|
||||||
*
|
*
|
||||||
|
* If the registered type is a subtype of `G_TYPE_BOXED`,
|
||||||
|
* [method@GIRepository.RegisteredTypeInfo.is_boxed] will return true, and
|
||||||
|
* [method@GIRepository.RegisteredTypeInfo.get_type_name] is guaranteed to
|
||||||
|
* return a non-`NULL` value. This is relevant for the
|
||||||
|
* [class@GIRepository.StructInfo] and [class@GIRepository.UnionInfo]
|
||||||
|
* subclasses.
|
||||||
|
*
|
||||||
* Since: 2.80
|
* Since: 2.80
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -155,6 +162,63 @@ gi_registered_type_info_get_g_type (GIRegisteredTypeInfo *info)
|
|||||||
return (* get_type_func) ();
|
return (* get_type_func) ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gi_registered_type_info_is_boxed:
|
||||||
|
* @info: a #GIRegisteredTypeInfo
|
||||||
|
*
|
||||||
|
* Get whether the registered type is a boxed type.
|
||||||
|
*
|
||||||
|
* A boxed type is a subtype of the fundamental `G_TYPE_BOXED` type.
|
||||||
|
* It’s a type which has registered a [type@GObject.Type], and which has
|
||||||
|
* associated copy and free functions.
|
||||||
|
*
|
||||||
|
* Most boxed types are `struct`s; some are `union`s; and it’s possible for a
|
||||||
|
* boxed type to be neither, but that is currently unsupported by
|
||||||
|
* libgirepository. It’s also possible for a `struct` or `union` to have
|
||||||
|
* associated copy and/or free functions *without* being a boxed type, by virtue
|
||||||
|
* of not having registered a [type@GObject.Type].
|
||||||
|
*
|
||||||
|
* This function will return false for [type@GObject.Type]s which are not boxed,
|
||||||
|
* such as classes or interfaces. It will also return false for the `struct`s
|
||||||
|
* associated with a class or interface, which return true from
|
||||||
|
* [method@GIRepository.StructInfo.is_gtype_struct].
|
||||||
|
*
|
||||||
|
* Returns: true if @info is a boxed type
|
||||||
|
* Since: 2.80
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
gi_registered_type_info_is_boxed (GIRegisteredTypeInfo *info)
|
||||||
|
{
|
||||||
|
GIBaseInfo *base_info = GI_BASE_INFO (info);
|
||||||
|
const RegisteredTypeBlob *blob;
|
||||||
|
|
||||||
|
g_return_val_if_fail (GI_IS_REGISTERED_TYPE_INFO (info), G_TYPE_INVALID);
|
||||||
|
|
||||||
|
blob = (const RegisteredTypeBlob *) &base_info->typelib->data[base_info->offset];
|
||||||
|
|
||||||
|
if (blob->blob_type == BLOB_TYPE_BOXED)
|
||||||
|
{
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
else if (blob->blob_type == BLOB_TYPE_STRUCT)
|
||||||
|
{
|
||||||
|
const StructBlob *struct_blob = (const StructBlob *) &base_info->typelib->data[base_info->offset];
|
||||||
|
|
||||||
|
return !struct_blob->unregistered;
|
||||||
|
}
|
||||||
|
else if (blob->blob_type == BLOB_TYPE_UNION)
|
||||||
|
{
|
||||||
|
const UnionBlob *union_blob = (const UnionBlob *) &base_info->typelib->data[base_info->offset];
|
||||||
|
|
||||||
|
return !union_blob->unregistered;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We don’t currently support boxed ‘other’ types (boxed types which aren’t
|
||||||
|
* a struct or union. */
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
gi_registered_type_info_class_init (gpointer g_class,
|
gi_registered_type_info_class_init (gpointer g_class,
|
||||||
gpointer class_data)
|
gpointer class_data)
|
||||||
|
@ -69,4 +69,7 @@ const char * gi_registered_type_info_get_type_init_function_name (GIRe
|
|||||||
GI_AVAILABLE_IN_ALL
|
GI_AVAILABLE_IN_ALL
|
||||||
GType gi_registered_type_info_get_g_type (GIRegisteredTypeInfo *info);
|
GType gi_registered_type_info_get_g_type (GIRegisteredTypeInfo *info);
|
||||||
|
|
||||||
|
GI_AVAILABLE_IN_ALL
|
||||||
|
gboolean gi_registered_type_info_is_boxed (GIRegisteredTypeInfo *info);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
@ -660,7 +660,7 @@ write_struct_info (const char *ns,
|
|||||||
type_name = gi_registered_type_info_get_type_name ((GIRegisteredTypeInfo*)info);
|
type_name = gi_registered_type_info_get_type_name ((GIRegisteredTypeInfo*)info);
|
||||||
type_init = gi_registered_type_info_get_type_init_function_name ((GIRegisteredTypeInfo*)info);
|
type_init = gi_registered_type_info_get_type_init_function_name ((GIRegisteredTypeInfo*)info);
|
||||||
|
|
||||||
if (GI_IS_BOXED_INFO (info))
|
if (gi_registered_type_info_is_boxed (GI_REGISTERED_TYPE_INFO (info)))
|
||||||
{
|
{
|
||||||
xml_start_element (file, "glib:boxed");
|
xml_start_element (file, "glib:boxed");
|
||||||
xml_printf (file, " glib:name=\"%s\"", name);
|
xml_printf (file, " glib:name=\"%s\"", name);
|
||||||
@ -1257,6 +1257,7 @@ write_union_info (const char *ns,
|
|||||||
type_name = gi_registered_type_info_get_type_name ((GIRegisteredTypeInfo*)info);
|
type_name = gi_registered_type_info_get_type_name ((GIRegisteredTypeInfo*)info);
|
||||||
type_init = gi_registered_type_info_get_type_init_function_name ((GIRegisteredTypeInfo*)info);
|
type_init = gi_registered_type_info_get_type_init_function_name ((GIRegisteredTypeInfo*)info);
|
||||||
|
|
||||||
|
/* FIXME: Add support for boxed unions */
|
||||||
xml_start_element (file, "union");
|
xml_start_element (file, "union");
|
||||||
xml_printf (file, " name=\"%s\"", name);
|
xml_printf (file, " name=\"%s\"", name);
|
||||||
|
|
||||||
|
@ -48,6 +48,14 @@ gi_typelib_blob_type_to_info_type (GITypelibBlobType blob_type)
|
|||||||
{
|
{
|
||||||
switch (blob_type)
|
switch (blob_type)
|
||||||
{
|
{
|
||||||
|
case BLOB_TYPE_BOXED:
|
||||||
|
/* `BLOB_TYPE_BOXED` now always refers to a `StructBlob`, and
|
||||||
|
* `GIRegisteredTypeInfo` (the parent type of `GIStructInfo`) has a method
|
||||||
|
* for distinguishing whether the struct is a boxed type. So presenting
|
||||||
|
* `BLOB_TYPE_BOXED` as its own `GIBaseInfo` subclass is not helpful.
|
||||||
|
* See commit e28078c70cbf4a57c7dbd39626f43f9bd2674145 and
|
||||||
|
* https://gitlab.gnome.org/GNOME/glib/-/issues/3245. */
|
||||||
|
return GI_INFO_TYPE_STRUCT;
|
||||||
default:
|
default:
|
||||||
return (GIInfoType) blob_type;
|
return (GIInfoType) blob_type;
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,9 @@ if enable_gir
|
|||||||
'object-info' : {
|
'object-info' : {
|
||||||
'depends': [gio_gir],
|
'depends': [gio_gir],
|
||||||
},
|
},
|
||||||
|
'registered-type-info' : {
|
||||||
|
'depends': [gobject_gir],
|
||||||
|
},
|
||||||
'repository' : {
|
'repository' : {
|
||||||
'depends': [glib_gir, gio_gir, gobject_gir],
|
'depends': [glib_gir, gio_gir, gobject_gir],
|
||||||
},
|
},
|
||||||
|
137
girepository/tests/registered-type-info.c
Normal file
137
girepository/tests/registered-type-info.c
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2024 GNOME Foundation
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "girepository.h"
|
||||||
|
#include "test-common.h"
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_boxed (RepositoryFixture *fx,
|
||||||
|
const void *unused)
|
||||||
|
{
|
||||||
|
const struct
|
||||||
|
{
|
||||||
|
const char *name;
|
||||||
|
GType expect_info_type;
|
||||||
|
gboolean expect_nonnull_gtype_info;
|
||||||
|
gboolean expect_is_gtype_struct;
|
||||||
|
gboolean expect_boxed;
|
||||||
|
}
|
||||||
|
types[] =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
/* POD struct */
|
||||||
|
.name = "CClosure",
|
||||||
|
.expect_info_type = GI_TYPE_STRUCT_INFO,
|
||||||
|
.expect_nonnull_gtype_info = FALSE,
|
||||||
|
.expect_is_gtype_struct = FALSE,
|
||||||
|
.expect_boxed = FALSE,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
/* POD union */
|
||||||
|
.name = "TypeCValue",
|
||||||
|
.expect_info_type = GI_TYPE_UNION_INFO,
|
||||||
|
.expect_nonnull_gtype_info = FALSE,
|
||||||
|
.expect_is_gtype_struct = FALSE,
|
||||||
|
.expect_boxed = FALSE,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
/* struct for a different non-boxed GType */
|
||||||
|
.name = "InitiallyUnownedClass",
|
||||||
|
.expect_info_type = GI_TYPE_STRUCT_INFO,
|
||||||
|
.expect_nonnull_gtype_info = FALSE,
|
||||||
|
.expect_is_gtype_struct = TRUE,
|
||||||
|
.expect_boxed = FALSE,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
/* boxed struct */
|
||||||
|
.name = "BookmarkFile",
|
||||||
|
.expect_info_type = GI_TYPE_STRUCT_INFO,
|
||||||
|
.expect_nonnull_gtype_info = TRUE,
|
||||||
|
.expect_is_gtype_struct = FALSE,
|
||||||
|
.expect_boxed = TRUE,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
/* boxed struct */
|
||||||
|
.name = "Closure",
|
||||||
|
.expect_info_type = GI_TYPE_STRUCT_INFO,
|
||||||
|
.expect_nonnull_gtype_info = TRUE,
|
||||||
|
.expect_is_gtype_struct = FALSE,
|
||||||
|
.expect_boxed = TRUE,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
/* non-boxed GType */
|
||||||
|
.name = "Object",
|
||||||
|
.expect_info_type = GI_TYPE_OBJECT_INFO,
|
||||||
|
.expect_nonnull_gtype_info = TRUE,
|
||||||
|
.expect_is_gtype_struct = FALSE,
|
||||||
|
.expect_boxed = FALSE,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
g_test_summary ("Test various boxed and non-boxed types for GIRegisteredTypeInfo");
|
||||||
|
|
||||||
|
for (size_t i = 0; i < G_N_ELEMENTS (types); i++)
|
||||||
|
{
|
||||||
|
GIRegisteredTypeInfo *type_info = GI_REGISTERED_TYPE_INFO (gi_repository_find_by_name (fx->repository, "GObject", types[i].name));
|
||||||
|
g_assert_nonnull (type_info);
|
||||||
|
|
||||||
|
g_test_message ("Expecting %s to %s", types[i].name, types[i].expect_boxed ? "be boxed" : "not be boxed");
|
||||||
|
|
||||||
|
g_assert_cmpuint (G_TYPE_FROM_INSTANCE (type_info), ==, types[i].expect_info_type);
|
||||||
|
|
||||||
|
if (types[i].expect_nonnull_gtype_info)
|
||||||
|
{
|
||||||
|
g_assert_nonnull (gi_registered_type_info_get_type_name (type_info));
|
||||||
|
g_assert_nonnull (gi_registered_type_info_get_type_init_function_name (type_info));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_assert_null (gi_registered_type_info_get_type_name (type_info));
|
||||||
|
g_assert_null (gi_registered_type_info_get_type_init_function_name (type_info));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GI_IS_STRUCT_INFO (type_info))
|
||||||
|
{
|
||||||
|
if (types[i].expect_is_gtype_struct)
|
||||||
|
g_assert_true (gi_struct_info_is_gtype_struct (GI_STRUCT_INFO (type_info)));
|
||||||
|
else
|
||||||
|
g_assert_false (gi_struct_info_is_gtype_struct (GI_STRUCT_INFO (type_info)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (types[i].expect_boxed)
|
||||||
|
g_assert_true (gi_registered_type_info_is_boxed (type_info));
|
||||||
|
else
|
||||||
|
g_assert_false (gi_registered_type_info_is_boxed (type_info));
|
||||||
|
|
||||||
|
g_clear_pointer (&type_info, gi_base_info_unref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main (int argc,
|
||||||
|
char *argv[])
|
||||||
|
{
|
||||||
|
repository_init (&argc, &argv);
|
||||||
|
|
||||||
|
ADD_REPOSITORY_TEST ("/registered-type-info/boxed", test_boxed, &typelib_load_spec_gobject);
|
||||||
|
|
||||||
|
return g_test_run ();
|
||||||
|
}
|
@ -234,21 +234,6 @@ test_repository_arg_info (RepositoryFixture *fx,
|
|||||||
g_clear_pointer (&struct_info, gi_base_info_unref);
|
g_clear_pointer (&struct_info, gi_base_info_unref);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
test_repository_boxed_info (RepositoryFixture *fx,
|
|
||||||
const void *unused)
|
|
||||||
{
|
|
||||||
GIBoxedInfo *boxed_info = NULL;
|
|
||||||
|
|
||||||
g_test_summary ("Test retrieving GIBoxedInfos from a typelib");
|
|
||||||
|
|
||||||
/* Test all the methods of GIBoxedInfo. This is simple, because there are none. */
|
|
||||||
boxed_info = GI_BOXED_INFO (gi_repository_find_by_name (fx->repository, "GObject", "BookmarkFile"));
|
|
||||||
g_assert_nonnull (boxed_info);
|
|
||||||
|
|
||||||
g_clear_pointer (&boxed_info, gi_base_info_unref);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
test_repository_callable_info (RepositoryFixture *fx,
|
test_repository_callable_info (RepositoryFixture *fx,
|
||||||
const void *unused)
|
const void *unused)
|
||||||
@ -766,7 +751,6 @@ main (int argc,
|
|||||||
ADD_REPOSITORY_TEST ("/repository/info", test_repository_info, &typelib_load_spec_gobject);
|
ADD_REPOSITORY_TEST ("/repository/info", test_repository_info, &typelib_load_spec_gobject);
|
||||||
ADD_REPOSITORY_TEST ("/repository/dependencies", test_repository_dependencies, &typelib_load_spec_gobject);
|
ADD_REPOSITORY_TEST ("/repository/dependencies", test_repository_dependencies, &typelib_load_spec_gobject);
|
||||||
ADD_REPOSITORY_TEST ("/repository/arg-info", test_repository_arg_info, &typelib_load_spec_gobject);
|
ADD_REPOSITORY_TEST ("/repository/arg-info", test_repository_arg_info, &typelib_load_spec_gobject);
|
||||||
ADD_REPOSITORY_TEST ("/repository/boxed-info", test_repository_boxed_info, &typelib_load_spec_gobject);
|
|
||||||
ADD_REPOSITORY_TEST ("/repository/callable-info", test_repository_callable_info, &typelib_load_spec_gobject);
|
ADD_REPOSITORY_TEST ("/repository/callable-info", test_repository_callable_info, &typelib_load_spec_gobject);
|
||||||
ADD_REPOSITORY_TEST ("/repository/callback-info", test_repository_callback_info, &typelib_load_spec_gobject);
|
ADD_REPOSITORY_TEST ("/repository/callback-info", test_repository_callback_info, &typelib_load_spec_gobject);
|
||||||
ADD_REPOSITORY_TEST ("/repository/char-types", test_repository_char_types, &typelib_load_spec_gobject);
|
ADD_REPOSITORY_TEST ("/repository/char-types", test_repository_char_types, &typelib_load_spec_gobject);
|
||||||
|
@ -106,6 +106,21 @@ test_is_pointer_for_struct_method_arg (RepositoryFixture *fx,
|
|||||||
g_clear_pointer (&variant_info, gi_base_info_unref);
|
g_clear_pointer (&variant_info, gi_base_info_unref);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_boxed (RepositoryFixture *fx,
|
||||||
|
const void *unused)
|
||||||
|
{
|
||||||
|
GIStructInfo *struct_info = NULL;
|
||||||
|
|
||||||
|
g_test_summary ("Test that a boxed struct is recognised as such");
|
||||||
|
|
||||||
|
struct_info = GI_STRUCT_INFO (gi_repository_find_by_name (fx->repository, "GObject", "BookmarkFile"));
|
||||||
|
g_assert_nonnull (struct_info);
|
||||||
|
g_assert_true (gi_registered_type_info_is_boxed (GI_REGISTERED_TYPE_INFO (struct_info)));
|
||||||
|
|
||||||
|
g_clear_pointer (&struct_info, gi_base_info_unref);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main (int argc,
|
main (int argc,
|
||||||
char *argv[])
|
char *argv[])
|
||||||
@ -115,6 +130,7 @@ main (int argc,
|
|||||||
ADD_REPOSITORY_TEST ("/struct-info/field-iterators", test_field_iterators, &typelib_load_spec_gobject);
|
ADD_REPOSITORY_TEST ("/struct-info/field-iterators", test_field_iterators, &typelib_load_spec_gobject);
|
||||||
ADD_REPOSITORY_TEST ("/struct-info/sizeof-gvalue", test_size_of_gvalue, &typelib_load_spec_gobject);
|
ADD_REPOSITORY_TEST ("/struct-info/sizeof-gvalue", test_size_of_gvalue, &typelib_load_spec_gobject);
|
||||||
ADD_REPOSITORY_TEST ("/struct-info/is-pointer-for-struct-method-arg", test_is_pointer_for_struct_method_arg, &typelib_load_spec_glib);
|
ADD_REPOSITORY_TEST ("/struct-info/is-pointer-for-struct-method-arg", test_is_pointer_for_struct_method_arg, &typelib_load_spec_glib);
|
||||||
|
ADD_REPOSITORY_TEST ("/struct-info/boxed", test_boxed, &typelib_load_spec_gobject);
|
||||||
|
|
||||||
return g_test_run ();
|
return g_test_run ();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user