Top | ![]() |
![]() |
![]() |
![]() |
GwySerializable * | gwy_serializable_copy () |
void | gwy_serializable_assign () |
gsize | gwy_serializable_n_items () |
void | gwy_serializable_itemize () |
void | gwy_serializable_done () |
#define | GWY_SERIALIZABLE_GET_INTERFACE() |
GwySerializable is an abstract interface for data-like objects that can be serialised and deserialised. You can
serialise any object implementing this interface with functions such as gwy_serialize_gio()
and the restore
(deserialise) it with gwy_deserialize_memory()
.
Gwyddion implements a simple serialisation model: only tree-like structures of objects, formed by ownership, can be serialised and restored. Any inter-object relations other than plain ownership must be stored in some weak form and there is no explicit support for this. Moreover, only object values are preserved, their identities are lost (in particular, signals, user data and similar attributes are not subject to serialisation and deserialisation). This, on the other hand, means that any saved object can be restored individually and independently and still be in a meaningful state.
Beside saving and restoration, all serialisable classes implement a copy-constructor that creates a duplicate of an
existing object. This constructor is invoked with gwy_serializable_copy()
. Furthermore, the value of one
such object can be transferred to another object of the same class (or a superclass), similarly to overriden
assignment operators in OO languages. This assignment is performed with gwy_serializable_assign()
.
Most classes that implement GwySerializable define convenience macros for the copy-constructor and assignment
operator, called
gwy_foo_copy()
and gwy_foo_assign()
, respectively,
where foo
is the lowercase class name.
You can implement serialisation and deserialisation in your classes. Use the G_IMPLEMENT_ITERFACE
macro
to generate the boilerplate interface implementation code. The copy constructor and assignment operators are
usually easy so we focus on serialisation and deserialisation (with public object data for simplicity). There
are a number of helper functions, such as gwy_deserialize_filter()
for getting only the interesting items in
deserialisation or gwy_serialize_item_double()
for handling the itemisation of a single value.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
// Standard object structure definitions typedef struct _MyObject MyObject; typedef struct _MyObjectClass MyObjectClass; struct _MyObject { GObject g_object; gint32 data; }; struct _MyObjectClass { GObjectClass g_object_class; }; // Define the type G_DEFINE_TYPE_WITH_CODE(MyObject, my_object, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE(GWY_TYPE_SERIALIZABLE, serializable_init)); // Serialised data specification, used both in itemize() and construct() static const GwySerializableItem default_items[] = { { .name = "data", .ctype = GWY_SERIALIZABLE_INT32, }, }; // Implement the interface static void serializable_init(GwySerializableInterface *iface) { iface->n_items = serializable_n_items; iface->itemize = serializable_itemize; iface->construct = serializable_construct; iface->copy = serializable_copy; iface->assign = serializable_assign; } // Duplication is easy, create a new object and set data static GwySerializable* serializable_copy(GwySerializable *serializable) { MyObject *myobject = GWY_MY_OBJECT(serializable); MyObject *copy = g_object_newv(MY_TYPE_OBJECT, 0, NULL); copy->data = myobject->data; return GWY_SERIALIZABLE(copy); } // Assigning is even easier, just set data static void serializable_assign(GwySerializable *destination, GwySerializable *source) { MyObject *myobject = GWY_MY_OBJECT(serializable); MyObject *src = GWY_MY_OBJECT(source); src->data = myobject->data; } // Our object needs at most one item and it does not contain any child objects. Thus we can simply return // a constant. static gsize serializable_n_items(G_GNUC_UNUSED GwySerializable *serializable) { return 1; } // Fill the item list with actual object data. This is a bit // overcomplicated for such a simple object as MyObject, of course. static gsize serializable_itemize(GwySerializable *serializable, GwySerializableItems *items) { MyObject *myobject = GWY_MY_OBJECT(serializable); GwySerializableItem it[G_N_ELEMENTS(default_items)]; gsize n_items = 0; memcpy(it, default_items, sizeof(default_items)); // Do not store the data if it has the default value if (myobject->data) { g_return_val_if_fail(items->len - items->n, 0); items->items[items->n].value.v_int32 = myobject->data; items->n++; n_items++; } return n_items; } // Construct the object from item list. The data item does not need to be present, in this case the default zero // value is used. Also, for more complicated objects the deserialisation can fail or resources need to be released; // see GwySerializableInterface for the clean-up rules. static gboolean serializable_construct(GwySerializable *serializable, GwySerializableItems *items, GwyErrorList **error_list) { GwySerializableItem it[G_N_ELEMENTS(default_items)]; memcpy(it, default_items, sizeof(default_items)); gwy_deserialize_filter_items(it, G_N_ELEMENTS(it), items, "MyObject", error_list); MyObject *myobject = GWY_MY_OBJECT(serializable); myobject->data = it[0].value.v_int32; return TRUE; } |
GwySerializable *
gwy_serializable_copy (GwySerializable *serializable
);
Creates an object with identical value.
This is a copy-constructor creating a deep copy.
You can duplicate a NULL
, too, but you are discouraged from doing it.
GwySerializable implementations are encouraged to provide my_object_copy()
convenience wrappers with argument and
return value of the specific type and the corresponding type checking.
void gwy_serializable_assign (GwySerializable *destination
,GwySerializable *source
);
Copies the value of an object to another object.
If destination
is the same object as source
the function is no-op.
What constitutes ‘object value’ depends on the class. The general rule is that destination
will look as the result
of gwy_serializable_copy()
. However, it will keep its identity (address, connected signal handlers, references,
object data, etc.). The operation may be more efficient than constructing a new object but it may be not.
GwySerializable implementations are encouraged to provide my_object_assign()
convenience wrappers with arguments
of the specific type and the corresponding type checking.
gsize
gwy_serializable_n_items (GwySerializable *serializable
);
Provides an upper bound of the number of items the flattened representation of an object will take.
This function wraps the virtual table method n_items()
. It increases the returned value by the number of item
used to represent the object header (which is 1).
void gwy_serializable_itemize (GwySerializable *serializable
,GwySerializableItems *items
);
Creates the flattened representation of a serializable object.
This function wraps the virtual table method itemize()
. It deals with recording of the object header item. Method
itemize()
then only serialises the actual data of the object.
void
gwy_serializable_done (GwySerializable *serializable
);
Frees temporary storage allocated by object itemization.
This function calls the virtual table method done()
, if the class has any.
Type of serialisable value.
The type is a single byte, i.e. a value smaller than 256. It is equal to the character used in GWY files to denote the corresponding type.
Signed and usinged types are not distinguished here as their byte order is handled the same way.
Reserved type value which does not appear in files and denotes object header items
internally. The serialiser/deserialised sets |
||
Reserved type value which does not appear in files and denotes already consumed items internally. |
||
Denotes a character (8bit integer). |
||
Denotes a character (8bit integer) array. |
||
Denotes a one-byte boolean. |
||
Denotes a 16bit integer. |
||
Denotes an array of 16bit integers. |
||
Denotes a 32bit integer. |
||
Denotes an array of 32bit integers. |
||
Denotes a 64bit integer. |
||
Denotes an array of 64bit integers. |
||
Denotes a IEEE double. |
||
Denotes an array of IEEE doubles. |
||
Denotes a UTF-8-encoded C string. If you need a raw sequence of bytes, use
|
||
Denotes an array of UTF-8 encoded C strings. |
||
Denotes an object. |
||
Denotes an array of objects. |
||
Denotes a serialisable boxed type. |
Representation of individual values of object serialisable data.
See GwySerializableCType for corresponding type specifiers.
Member v_size
has no use in implementations (it corresponds to GWY_SERIALIZABLE_HEADER
), it is used only in
object header items in the flattened object tree.
All string values must be valid UTF-8. If you need raw byte sequences use arrays of guint8.
Signed and unsigned integer members are provided for convenience, the serialisation does not distinguish between signed and unsigned integers.
The value as a gboolean. |
||
The value as a gint8. |
||
The value as a guint8. |
||
The value as a gint16. |
||
The value as a guint16. |
||
The value as a gint32. |
||
The value as a guint32. |
||
The value as a gint64. |
||
The value as a guint64. |
||
The value as a gdouble. |
||
The value as a gchar pointer. |
||
The value as a guchar pointer. |
||
The value as an object. |
||
The value as a boxed type. |
||
The value as a gsize. |
||
The value as a GType. |
||
The value as an array of gint8s. |
||
The value as an array of guint8s. |
||
The value as an array of gint16s. |
||
The value as an array of guint16s. |
||
The value as an array of gint32s. |
||
The value as an array of guint32s. |
||
The value as an array of gint64s. |
||
The value as an array of guint64s. |
||
The value as an array of gdoubles. |
||
The value as an array of gchar pointers. |
||
The value as an array of guchar pointers. |
||
The value as an array of objects. |
typedef struct { GwySerializableValue value; const gchar *name; gsize array_size; GwySerializableAux aux; guchar ctype; guint8 array_flags; } GwySerializableItem;
Information about one object component that is subject to serialisation or deserialisation.
GwySerializableValue |
Item value, the interpreration depends on the |
|
Component name. |
||
Array size of the component if of an array type. For boxed types that do not carry type information, deserialisation sets is to the GType of the boxed type. Unused otherwise. |
||
GwySerializableAux |
||
Item type, one of the GwySerializableCType enum. |
||
typedef struct { gsize len; gsize n; GwySerializableItem *items; } GwySerializableItems;
Flattened tree structure of object data used during serialisation and deserialisation.
Allocated number of items. |
||
Number of items present. |
||
GwySerializableItem * |
Array of items of total size |
typedef struct _GwySerializable GwySerializable;
Formal type of serialisable objects.
struct GwySerializableInterface { gsize (*n_items) (GwySerializable *serializable); gsize (*itemize) (GwySerializable *serializable, GwySerializableItems *items); void (*done) (GwySerializable *serializable); gboolean (*construct)(GwySerializable *serializable, GwySerializableItems *items, GwyErrorList **error_list); GwySerializable* (*copy) (GwySerializable *serializable); void (*assign) (GwySerializable *destination, GwySerializable *source); };
Interface implemented by serialisable objects.
The object class must implement all the methods, except GwySerializableInterface.done()
which is optional.
Returns the number of items the object will flatten to, including items of all contained objects
(but excluding the object header items of self). It should use This method may return a reasonable upper estimate instead of the exact number; for instance, if
objects of some class are known to need 5 to 7 items, |
||
Appends flattened representation of the object data to the The number of items corresponding to this object is returned, not including items of contained objects: every contained object counts only as one item. |
||
Frees all temporary data created by |
||
Deserialises an object from array of flattened data items. The first argument is the object of the final class (i.e. it may be a derived class), constructed with the default parameterless constructor. All strings, objects and arrays in the item list are newly allocated. The method can (and,
generally, should) take ownership by filling corresponding item values with This method must make any assumptions about the contents of It is possible to chain this method to the parent class and pass it the the item list or a part of it, if you are careful. |
||
Creates a new object with all data identical to this object. This method is expected to create a deep copy. Classes may provide other methods for shallow copies. |
||
Makes all data of this object identical to the data of another object of the same class. Implementations may assume that the is-a relation is satisfied for the source object. This method is expected to perform a deep copy. Classes may provide other methods for shallow copies. |