mbox series

[0/4] qom: reduce boilerplate required for declaring and defining objects

Message ID 20200723181410.3145233-1-berrange@redhat.com
Headers show
Series qom: reduce boilerplate required for declaring and defining objects | expand

Message

Daniel P. Berrangé July 23, 2020, 6:14 p.m. UTC
To just duplicate the patch 2 message....

When creating new QOM types, there is a lot of boilerplate code that
must be repeated using a standard pattern. This is tedious to write
and liable to suffer from subtle inconsistencies. Thus it would
benefit from some simple automation.

QOM was loosely inspired by GLib's GObject, and indeed GObject suffers
from the same burden of boilerplate code, but has long provided a set of
macros to eliminate this burden in the source implementation. More
recently it has also provided a set of macros to eliminate this burden
in the header declaration.

In GLib there are the G_DECLARE_* and G_DEFINE_* family of macros
for the header declaration and source implementation respectively:

  https://developer.gnome.org/gobject/stable/chapter-gobject.html
  https://developer.gnome.org/gobject/stable/howto-gobject.html

This patch takes inspiration from GObject to provide the equivalent
functionality for QOM.

In the header file, instead of:

    typedef struct MyDevice MyDevice;
    typedef struct MyDeviceClass MyDeviceClass;

    G_DEFINE_AUTOPTR_CLEANUP_FUNC(MyDeviceClass, object_unref)

    #define MY_DEVICE_GET_CLASS(void *obj) \
            OBJECT_GET_CLASS(MyDeviceClass, obj, TYPE_MY_DEVICE)
    #define MY_DEVICE_CLASS(void *klass) \
            OBJECT_CLASS_CHECK(MyDeviceClass, klass, TYPE_MY_DEVICE)
    #define MY_DEVICE(void *obj)
            OBJECT_CHECK(MyDevice, obj, TYPE_MY_DEVICE)

    struct MyDeviceClass {
        DeviceClass parent_class;
    };

We now have

    OBJECT_DECLARE_SIMPLE_TYPE(MyDevice, my_device, MY_DEVICE, DEVICE)

In cases where the class needs some virtual methods, it can be left
to be implemented manually using

    OBJECT_DECLARE_TYPE(MyDevice, my_device, MY_DEVICE)

Note that these macros are including support for g_autoptr() for the
object types, which is something previously only supported for variables
declared as the base Object * type.

Meanwhile in the source file, instead of:

    static void my_device_finalize(Object *obj);
    static void my_device_class_init(ObjectClass *oc, void *data);
    static void my_device_init(Object *obj);

    static const TypeInfo my_device_info = {
        .parent = TYPE_DEVICE,
        .name = TYPE_MY_DEVICE,
        .instance_size = sizeof(MyDevice),
        .instance_init = my_device_init,
        .instance_finalize = my_device_finalize,
        .class_size = sizeof(MyDeviceClass),
        .class_init = my_device_class_init,
    };

    static void
    my_device_register_types(void)
    {
        type_register_static(&my_device_info);
    }
    type_init(my_device_register_types);

We now have

    OBJECT_DEFINE_TYPE(MyDevice, my_device, MY_DEVICE, DEVICE)

Or, if a class needs to implement interfaces:

    OBJECT_DEFINE_TYPE_WITH_INTERFACES(MyDevice, my_device, MY_DEVICE, DEVICE,
                                       { TYPE_USER_CREATABLE }, { NULL })

Or, if a class needs to be abstract

    OBJECT_DEFINE_ABSTRACT_TYPE(MyDevice, my_device, MY_DEVICE, DEVICE)

IOW, in both cases the maintainer now only has to think about the
interesting part of the code which implements useful functionality
and avoids much of the boilerplate.


Patches 3 and 4 illustrate the usage of the new macros, and by excluding
the qom changes, and just looking at the crypto, the diffstat shows the
benefits quite nicely:

 crypto/secret.c                 | 24 ++++--------------------
 crypto/secret_common.c          | 32 +++++++++-----------------------
 crypto/secret_keyring.c         | 28 +++++++++-------------------
 crypto/tlscreds.c               | 25 +++----------------------
 crypto/tlscredsanon.c           | 23 ++++-------------------
 crypto/tlscredspsk.c            | 25 +++++--------------------
 crypto/tlscredsx509.c           | 29 ++++-------------------------
 include/crypto/secret.h         | 11 ++---------
 include/crypto/secret_common.h  | 13 ++-----------
 include/crypto/secret_keyring.h | 18 ++----------------
 include/crypto/tlscreds.h       | 13 ++-----------
 include/crypto/tlscredsanon.h   | 14 ++------------
 include/crypto/tlscredspsk.h    | 13 ++-----------
 include/crypto/tlscredsx509.h   | 13 ++-----------
 14 files changed, 52 insertions(+), 229 deletions(-)

(The 'qom' file diffstat is misled by the large amount of API doc text
 added).

Daniel P. Berrangé (4):
  qom: make object_ref/unref use a void * instead of Object *.
  qom: provide convenient macros for declaring and defining types
  crypto: use QOM macros for declaration/definition of secret types
  crypto: use QOM macros for declaration/definition of TLS creds types

 crypto/secret.c                 |  24 +--
 crypto/secret_common.c          |  32 +---
 crypto/secret_keyring.c         |  28 +---
 crypto/tlscreds.c               |  25 +--
 crypto/tlscredsanon.c           |  23 +--
 crypto/tlscredspsk.c            |  25 +--
 crypto/tlscredsx509.c           |  29 +---
 include/crypto/secret.h         |  11 +-
 include/crypto/secret_common.h  |  13 +-
 include/crypto/secret_keyring.h |  18 +-
 include/crypto/tlscreds.h       |  13 +-
 include/crypto/tlscredsanon.h   |  14 +-
 include/crypto/tlscredspsk.h    |  13 +-
 include/crypto/tlscredsx509.h   |  13 +-
 include/qom/object.h            | 281 +++++++++++++++++++++++++++++++-
 qom/object.c                    |   6 +-
 16 files changed, 335 insertions(+), 233 deletions(-)

-- 
2.26.2