#pragma once
/*
 *  $Id: serializable.h 29741 2026-04-06 08:37:30Z yeti-dn $
 *  Copyright (C) 2009-2025 David Nečas (Yeti).
 *  E-mail: yeti@gwyddion.net.
 *
 *  This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public
 *  License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any
 *  later version.
 *
 *  This program 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 General Public License for more
 *  details.
 *
 *  You should have received a copy of the GNU General Public License along with this program; if not, write to the
 *  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#ifndef __GWY_SERIALIZABLE_H__
#define __GWY_SERIALIZABLE_H__

#include <glib-object.h>
#include <libgwyddion/error-list.h>
#include <libgwyddion/unit.h>
#include <libgwyddion/rgba.h>

G_BEGIN_DECLS

typedef enum {
    GWY_SERIALIZABLE_CONSUMED      = 0,
    GWY_SERIALIZABLE_INT8          = 'c',
    GWY_SERIALIZABLE_INT8_ARRAY    = 'C',
    GWY_SERIALIZABLE_BOOLEAN       = 'b',
    GWY_SERIALIZABLE_INT16         = 'h',
    GWY_SERIALIZABLE_INT16_ARRAY   = 'H',
    GWY_SERIALIZABLE_INT32         = 'i',
    GWY_SERIALIZABLE_INT32_ARRAY   = 'I',
    GWY_SERIALIZABLE_INT64         = 'q',
    GWY_SERIALIZABLE_INT64_ARRAY   = 'Q',
    GWY_SERIALIZABLE_FLOAT         = 'f',
    GWY_SERIALIZABLE_FLOAT_ARRAY   = 'F',
    GWY_SERIALIZABLE_DOUBLE        = 'd',
    GWY_SERIALIZABLE_DOUBLE_ARRAY  = 'D',
    GWY_SERIALIZABLE_STRING        = 's',
    GWY_SERIALIZABLE_STRING_ARRAY  = 'S',
    GWY_SERIALIZABLE_OBJECT        = 'o',
    GWY_SERIALIZABLE_OBJECT_ARRAY  = 'O',
    GWY_SERIALIZABLE_BOXED         = 'r',
} GwySerializableCType;

typedef enum {
    GWY_SERIALIZE_SIZE_32BIT = 4,
    GWY_SERIALIZE_SIZE_64BIT = 8,
} GwySerializeSizeType;

typedef enum {
    GWY_SERIALIZABLE_BIG_DATA    = (1 << 0),
    GWY_SERIALIZABLE_TRANSFORMED = (1 << 1),
    GWY_SERIALIZABLE_IS_GROUP    = (1 << 6),
} GwySerializableFlags;

typedef union  _GwySerializableValue GwySerializableValue;
typedef struct _GwySerializableItem  GwySerializableItem;
typedef struct _GwySerializableGroup GwySerializableGroup;

typedef struct _GwySerializableInterface GwySerializableInterface;
typedef struct _GwySerializable          GwySerializable;           // dummy

union _GwySerializableValue {
    gboolean v_boolean;
    gint8 v_int8;
    guint8 v_uint8;
    gint16 v_int16;
    guint16 v_uint16;
    gint32 v_int32;
    guint32 v_uint32;
    gint64 v_int64;
    guint64 v_uint64;
    gfloat v_float;
    gdouble v_double;
    gchar *v_string;
    guchar *v_ustring;
    GObject *v_object;
    gpointer v_boxed;
    gsize v_size;
    GType v_type;
    gint8 *v_int8_array;
    guint8 *v_uint8_array;
    gint16 *v_int16_array;
    guint16 *v_uint16_array;
    gint32 *v_int32_array;
    guint32 *v_uint32_array;
    gint64 *v_int64_array;
    guint64 *v_uint64_array;
    gfloat *v_float_array;
    gdouble *v_double_array;
    gchar **v_string_array;
    guchar **v_ustring_array;
    GObject **v_object_array;
    GwySerializableGroup *v_group;
    GwySerializableGroup **v_group_array;
};

typedef union {
    GType object_type;
    GType boxed_type;
    GParamSpec *pspec;
} GwySerializableAux;

struct _GwySerializableItem {
    GwySerializableValue value;
    const gchar *name;
    gsize array_size;
    GwySerializableAux aux;
    GwySerializableFlags flags : 24;
    guchar ctype;
};

#define GWY_DESERIALIZE_ERROR gwy_deserialize_error_quark()

typedef enum {
    GWY_DESERIALIZE_ERROR_PADDING = 1,
    GWY_DESERIALIZE_ERROR_ITEM,
    GWY_DESERIALIZE_ERROR_REPLACED,
    GWY_DESERIALIZE_ERROR_FATAL_MASK = 1024,
    GWY_DESERIALIZE_ERROR_TRUNCATED = GWY_DESERIALIZE_ERROR_FATAL_MASK + 32,
    GWY_DESERIALIZE_ERROR_SIZE_T,
    GWY_DESERIALIZE_ERROR_OBJECT,
    GWY_DESERIALIZE_ERROR_DATA,
    GWY_DESERIALIZE_ERROR_UTF8,
    GWY_DESERIALIZE_ERROR_INVALID,
} GwyDeserializeError;

#define GWY_TYPE_SERIALIZABLE               (gwy_serializable_get_type())
#define GWY_SERIALIZABLE(obj)               (G_TYPE_CHECK_INSTANCE_CAST((obj), GWY_TYPE_SERIALIZABLE, GwySerializable))
#define GWY_IS_SERIALIZABLE(obj)            (G_TYPE_CHECK_INSTANCE_TYPE((obj), GWY_TYPE_SERIALIZABLE))
#define GWY_SERIALIZABLE_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE((obj), GWY_TYPE_SERIALIZABLE, GwySerializableInterface))

struct _GwySerializableInterface {
    /*<private>*/
    GTypeInterface g_interface;

    /* virtual table */
    /*<public>*/
    void             (*itemize)  (GwySerializable *serializable,
                                  GwySerializableGroup *group);
    void             (*done)     (GwySerializable *serializable);

    gboolean         (*construct)(GwySerializable *serializable,
                                  GwySerializableGroup *group,
                                  GwyErrorList **error_list);

    GwySerializable* (*copy)     (GwySerializable *serializable);
    void             (*assign)   (GwySerializable *destination,
                                  GwySerializable *source);
};

GType                 gwy_serializable_get_type                 (void)                             G_GNUC_CONST;
GwySerializable*      gwy_serializable_copy                     (GwySerializable *serializable)    G_GNUC_MALLOC;
void                  gwy_serializable_assign                   (GwySerializable *destination,
                                                                 GwySerializable *source);
GwySerializableGroup* gwy_serializable_itemize                  (GwySerializable *serializable);
GQuark                gwy_deserialize_error_quark               (void)                             G_GNUC_CONST;
void                  gwy_serializable_done                     (GwySerializable *serializable);
GwySerializableGroup* gwy_serializable_group_new                (const gchar *name,
                                                                 gsize nitems)                     G_GNUC_MALLOC;
void                  gwy_serializable_group_alloc_size         (GwySerializableGroup *group,
                                                                 gsize nitems);
void                  gwy_serializable_group_free               (GwySerializableGroup *group,
                                                                 gboolean free_data,
                                                                 GwyErrorList **error_list);
const gchar*          gwy_serializable_group_name               (GwySerializableGroup *group);
void                  gwy_serializable_group_rename             (GwySerializableGroup *group,
                                                                 const gchar *name);
gsize                 gwy_serializable_group_size               (GwySerializableGroup *group);
GwySerializableItem*  gwy_serializable_group_items              (GwySerializableGroup *group,
                                                                 gsize *nitems);
void                  gwy_serializable_group_discard            (GwySerializableGroup *group,
                                                                 const gsize *indices,
                                                                 gsize nitems,
                                                                 gboolean free_data);
void                  gwy_serializable_group_itemize            (GwySerializableGroup *group);
void                  gwy_serializable_group_done               (GwySerializableGroup *group);
void                  gwy_serializable_group_append             (GwySerializableGroup *group,
                                                                 const GwySerializableItem *items,
                                                                 gsize nitems);
void                  gwy_serializable_group_append_int8        (GwySerializableGroup *group,
                                                                 const GwySerializableItem *model,
                                                                 gint8 value);
void                  gwy_serializable_group_append_int16       (GwySerializableGroup *group,
                                                                 const GwySerializableItem *model,
                                                                 gint16 value);
void                  gwy_serializable_group_append_int32       (GwySerializableGroup *group,
                                                                 const GwySerializableItem *model,
                                                                 gint32 value);
void                  gwy_serializable_group_append_int64       (GwySerializableGroup *group,
                                                                 const GwySerializableItem *model,
                                                                 gint64 value);
void                  gwy_serializable_group_append_boolean     (GwySerializableGroup *group,
                                                                 const GwySerializableItem *model,
                                                                 gboolean value);
void                  gwy_serializable_group_append_float       (GwySerializableGroup *group,
                                                                 const GwySerializableItem *model,
                                                                 gfloat value);
void                  gwy_serializable_group_append_double      (GwySerializableGroup *group,
                                                                 const GwySerializableItem *model,
                                                                 gdouble value);
void                  gwy_serializable_group_append_object      (GwySerializableGroup *group,
                                                                 const GwySerializableItem *model,
                                                                 GObject *object);
void                  gwy_serializable_group_append_unit        (GwySerializableGroup *group,
                                                                 const GwySerializableItem *model,
                                                                 GwyUnit *unit);
void                  gwy_serializable_group_append_boxed       (GwySerializableGroup *group,
                                                                 const GwySerializableItem *model,
                                                                 gconstpointer boxed);
void                  gwy_serializable_group_append_rgba        (GwySerializableGroup *group,
                                                                 const GwySerializableItem *model,
                                                                 const GwyRGBA *rgba);
void                  gwy_serializable_group_append_string      (GwySerializableGroup *group,
                                                                 const GwySerializableItem *model,
                                                                 const gchar *string);
void                  gwy_serializable_group_append_int8_array  (GwySerializableGroup *group,
                                                                 const GwySerializableItem *model,
                                                                 const gint8 *values,
                                                                 gsize len);
void                  gwy_serializable_group_append_int16_array (GwySerializableGroup *group,
                                                                 const GwySerializableItem *model,
                                                                 const gint16 *values,
                                                                 gsize len);
void                  gwy_serializable_group_append_int32_array (GwySerializableGroup *group,
                                                                 const GwySerializableItem *model,
                                                                 const gint32 *values,
                                                                 gsize len);
void                  gwy_serializable_group_append_int64_array (GwySerializableGroup *group,
                                                                 const GwySerializableItem *model,
                                                                 const gint64 *values,
                                                                 gsize len);
void                  gwy_serializable_group_append_float_array (GwySerializableGroup *group,
                                                                 const GwySerializableItem *model,
                                                                 const gfloat *values,
                                                                 gsize len);
void                  gwy_serializable_group_append_double_array(GwySerializableGroup *group,
                                                                 const GwySerializableItem *model,
                                                                 const gdouble *values,
                                                                 gsize len);
void                  gwy_serializable_group_append_string_array(GwySerializableGroup *group,
                                                                 const GwySerializableItem *model,
                                                                 gchar **strings,
                                                                 gsize len);
void                  gwy_serializable_group_append_object_array(GwySerializableGroup *group,
                                                                 const GwySerializableItem *model,
                                                                 GObject **objects,
                                                                 gsize len);

G_END_DECLS

#endif

/* vim: set cin columns=120 tw=118 et ts=4 sw=4 cino=>1s,e0,n0,f0,{0,}0,^0,\:1s,=0,g1s,h0,t0,+1s,c3,(0,u0 : */
