Allow for static initialisation.
[libeze] / ez-blob.h
1 /* ez-blob.h: Serialising description.
2
3    Copyright (C) 2019 Michael Zucchi
4
5    This program is free software: you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public License
7    as published by the Free Software Foundation, either version 3 of
8    the License, or (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with this program. If not, see
17    <http://www.gnu.org/licenses/>.
18 */
19
20 #ifndef _EZ_BLOB_H
21 #define _EZ_BLOB_H
22
23 #include <stddef.h>
24
25 /**
26  * This is a C structure annotation for implementing a serialiser.
27  *
28  * It is table driven and can describe most common C data structures,
29  * including nested and linked structures.
30  *
31  * A structure is described by an array of ez_blob_desc.  The first
32  * entry must have bd_offset=sizeof(structure), and bd_length=the
33  * number of field annotats which follow.
34  * 
35  * As an example:
36  * 
37  * typedef struct dbdisk {
38  *      int id;
39  *      char *uuid;
40  *      char *label;
41  *      char *type;
42  * } dbdisk;
43  * 
44  * Has a table such as this, using the init macros.
45  * 
46  * static ez_blob_desc DISK_ENC[] = {
47  *      EZ_BLOB_START(dbdisk, 0, 3),
48  *      EZ_BLOB_STRING(dbdisk, 1, uuid),
49  *      EZ_BLOB_STRING(dbdisk, 2, label),
50  *      EZ_BLOB_STRING(dbdisk, 3, type),
51  * };
52  * 
53  * The 'id' field and it's semantics are serialiser dependent.
54  * 
55  */
56 typedef struct ez_blob_desc {
57         unsigned short bd_type;         // type of field
58         unsigned short bd_id;           // used to tag encoded entries
59         unsigned int bd_offset;         // offset into structure, if type == EZ_BLOB_PK then this is sizeof(struct)
60         union {
61                 const struct ez_blob_desc *bd_table;// embedded structure or pointer
62                 unsigned int bd_length;
63         };
64 } ez_blob_desc;
65
66 /**
67  * Field type
68  */
69 typedef enum ez_blob_desc_type {
70         /* Data type */
71         EZ_BLOB_INT8,                   // (type & 3) = log2(element size)
72         EZ_BLOB_INT16,
73         EZ_BLOB_INT32,
74         EZ_BLOB_INT64,
75         EZ_BLOB_FLOAT32 = 6,
76         EZ_BLOB_FLOAT64,
77         EZ_BLOB_STRUCT = 15,            // bd_table points to another descriptor list
78
79         /* Data Storage */
80         EZ_BLOB_SINGLE = 0x00,          // the value at bd_offset
81         EZ_BLOB_SINGLEP = 0x10,         // pointer to value at bd_offset
82         EZ_BLOB_CSTRING = 0x20,         // 0-terminated string pointer
83         
84         EZ_BLOB_VECTOR = 0x40,          // ez_blob at bd_offset
85         EZ_BLOB_VECTORP = 0x50,         // pointer to ez_blob at bd_offset
86         EZ_BLOB_LIST = 0x60,            // ez_list at bd_offset
87         EZ_BLOB_LISTP = 0x70,           // pointer to ez_list at bd_offset
88
89         /* Options */
90         EZ_BLOB_ISNULLABLE = (1<<8),
91
92         /* meta */
93         EZ_BLOB_SIZE = 0x03,            // size mask for int or float types
94         EZ_BLOB_TYPE = 0x0f,            // Type mask
95         EZ_BLOB_STORAGE = 0xf0,         // Storage mask
96
97         EZ_BLOB_MAGIC = 0x10f5
98 } ez_blob_desc_type;
99
100 /** 
101  * This is compatible with lmdb MDB_val
102  */
103 typedef struct ez_blob {
104         size_t eb_size;
105         union {
106                 void *eb_data;
107                 uint8_t eb_data8;
108                 uint16_t eb_data16;
109                 uint32_t eb_data32;
110                 uint64_t eb_data64;
111                 float *eb_float;
112                 double *eb_double;
113         };
114 } ez_blob;
115
116 #define EZ_BLOB_START(s, id, len) { EZ_BLOB_MAGIC, id, sizeof(s), .bd_length = len }
117
118 #define EZ_BLOB_INT8(s, id, f) { EZ_BLOB_INT8 | EZ_BLOB_SINGLE, id, offsetof(s, f) }
119 #define EZ_BLOB_INT16(s, id, f) { EZ_BLOB_INT16 | EZ_BLOB_SINGLE, id, offsetof(s, f) }
120 #define EZ_BLOB_INT32(s, id, f) { EZ_BLOB_INT32 | EZ_BLOB_SINGLE, id, offsetof(s, f) }
121 #define EZ_BLOB_INT64(s, id, f) { EZ_BLOB_INT64 | EZ_BLOB_SINGLE, id, offsetof(s, f) }
122 #define EZ_BLOB_FLOAT32(s, id, f) { EZ_BLOB_FLOAT32 | EZ_BLOB_SINGLE, id, offsetof(s, f) }
123 #define EZ_BLOB_FLOAT64(s, id, f) { EZ_BLOB_FLOAT64 | EZ_BLOB_SINGLE, id, offsetof(s, f) }
124
125 #define EZ_BLOB_INT8V(s, id, f) { EZ_BLOB_INT8 | EZ_BLOB_VECTOR, id, offsetof(s, f) }
126 #define EZ_BLOB_INT16V(s, id, f) { EZ_BLOB_INT16 | EZ_BLOB_VECTOR, id, offsetof(s, f) }
127 #define EZ_BLOB_INT32V(s, id, f) { EZ_BLOB_INT32 | EZ_BLOB_VECTOR, id, offsetof(s, f) }
128 #define EZ_BLOB_INT64V(s, id, f) { EZ_BLOB_INT64 | EZ_BLOB_VECTOR, id, offsetof(s, f) }
129 #define EZ_BLOB_FLOAT32V(s, id, f) { EZ_BLOB_FLOAT32 | EZ_BLOB_VECTOR, id, offsetof(s, f) }
130 #define EZ_BLOB_FLOAT64V(s, id, f) { EZ_BLOB_FLOAT64 | EZ_BLOB_VECTOR, id, offsetof(s, f) }
131
132 #define EZ_BLOB_STRING(s, id, f) { EZ_BLOB_INT8 | EZ_BLOB_CSTRING, id, offsetof(s, f) }
133 #define EZ_BLOB_STRINGN(s, id, f) { EZ_BLOB_INT8 | EZ_BLOB_CSTRING | EZ_BLOB_ISNULLABLE, id, offsetof(s, f) }
134
135 #define EZ_BLOB_STRUCT(s, id, f, other) {  EZ_BLOB_STRUCT | EZ_BLOB_SINGLE, id, offsetof(s, f), .bd_table = other }
136 #define EZ_BLOB_STRUCTP(s, id, f, other) {  EZ_BLOB_STRUCT | EZ_BLOB_SINGLEP, id, offsetof(s, f), .bd_table = other }
137 #define EZ_BLOB_STRUCTPN(s, id, f, other) {  EZ_BLOB_STRUCT | EZ_BLOB_SINGLEP | EZ_BLOB_ISNULLABLE, id, offsetof(s, f), .bd_table = other }
138
139 #define EZ_BLOB_LIST(s, id, f, other) { EZ_BLOB_STRUCT | EZ_BLOB_LIST, id, offsetof(s, f), .bd_table = other }
140 #define EZ_BLOB_LISTPN(s, id, f, other) { EZ_BLOB_STRUCT | EZ_BLOB_LISTP | EZ_BLOB_ISNULLABLE, id, offsetof(s, f), .bd_table = other }
141
142 /**
143  * Allocate a new structure to hold a blob.
144  *
145  * The structure is initialised by ez_blob_init().
146  *
147  * @param d the descriptor table for the blob.
148  */
149 void *ez_blob_alloc(const ez_blob_desc *d);
150
151 /**
152  * Initialise a struct to the default state.
153  *
154  * This sets all values to zero and lists to empty.
155  *
156  * @param d descriptor table matching struct.
157  * @param p pointer to struct base.
158  */
159 void ez_blob_init(const ez_blob_desc *d, void *p);
160
161 /**
162  * Free struct unmarshalled by ez_blob_decode().
163  *
164  * @param d descriptor table matching struct.
165  * @param p decoded struct from ez_blob_decode().
166  */
167 void ez_blob_free(const ez_blob_desc *d, void *p);
168
169 /**
170  * Free the contents of a structure, but don't free the container.
171  *
172  * Use ez_blob_init() if you want to re-use the object.
173  *
174  * @param p structure to free.  p will not be freed.
175  */
176 void ez_blob_free_raw(const ez_blob_desc *d, void *p);
177
178 /**
179  * Debug function to dump structured blob contents.
180  */
181 void ez_blob_print(const ez_blob_desc *d, const void *a, int depth);
182
183 /**
184  * Debug/utility function to dump hexadeximal+ascii display.
185  */
186 void ez_blob_dump(const ez_blob *blob, const char *prefix);
187
188 #endif