aboutsummaryrefslogtreecommitdiff
path: root/apps/systemlib/bson/bcon.h
blob: a4a32faac6f7811d849cef8189c9d9ce5cbe9693 (plain) (blame)
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
/**
 * @file bcon.h
 * @brief BCON (BSON C Object Notation) Declarations
 */

/*    Copyright 2009-2012 10gen Inc.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

#ifndef BCON_H_
#define BCON_H_

#include "bson.h"

#ifndef DOXYGEN_SHOULD_SKIP_THIS

MONGO_EXTERN_C_START

#endif /* DOXYGEN_SHOULD_SKIP_THIS */

/**
 * BCON - BSON C Object Notation.
 *
 * Overview
 * --------
 * BCON provides for JSON-like (or BSON-like) initializers in C.
 * Without this, BSON must be constructed by procedural coding via explicit function calls.
 * With this, you now have concise, readable, and maintainable data-driven definition of BSON documents.
 * Here are a couple of introductory examples.
 *
 *     bcon hello[] = { "hello", "world", "." };
 *     bcon pi[] = { "pi", BF(3.14159), BEND };
 *
 * BCON is an array of bcon union elements with the default type of char* cstring.
 * A BCON document must be terminated with a char* cstring containing a single dot, i.e., ".", or the macro equivalent BEND.
 *
 * Cstring literals in double quotes are used for keys as well as for string values.
 * There is no explicit colon (':') separator between key and value, just a comma,
 * however it must be explicit or C will quietly concatenate the key and value strings for you.
 * Readability may be improved by using multiple lines with a key-value pair per line.
 *
 * Macros are used to enclose specific types, and an internal type-specifier string prefixes a typed value.
 * Macros are also used to specify interpolation of values from references (or pointers to references) of specified types.
 *
 * Sub-documents are framed by "{" "}" string literals, and sub-arrays are framed by "[" "]" literals.
 *
 * All of this is needed because C arrays and initializers are mono-typed unlike dict/array types in modern languages.
 * BCON attempts to be readable and JSON-like within the context and restrictions of the C language.
 *
 * Specification
 * -------------
 * This specification parallels the BSON specification ( http://bsonspec.org/#/specification ).
 * The specific types and their corresponding macros are documented in the bcon (union bcon) structure.
 * The base values use two-character macros starting with "B" for the simple initialization using static values.
 *
 * Examples
 * --------
 *
 *     bcon goodbye[] = { "hello", "world", "goodbye", "world", "." };
 *     bcon awesome[] = { "BSON", "[", "awesome", BF(5.05), BI(1986), "]", "." };
 *     bcon contact_info[] = {
 *         "firstName", "John",
 *         "lastName" , "Smith",
 *         "age"      , BI(25),
 *         "address"  ,
 *         "{",
 *             "streetAddress", "21 2nd Street",
 *             "city"         , "New York",
 *             "state"        , "NY",
 *             "postalCode"   , "10021",
 *         "}",
 *         "phoneNumber",
 *         "[",
 *             "{",
 *                 "type"  , "home",
 *                 "number", "212 555-1234",
 *             "}",
 *             "{",
 *                 "type"  , "fax",
 *                 "number", "646 555-4567",
 *             "}",
 *         "]",
 *         BEND
 *     };
 *
 * Comparison
 * ----------
 *
 *     JSON:
 *         { "BSON" : [ "awesome", 5.05, 1986 ] }
 *
 *     BCON:
 *         bcon awesome[] = { "BSON", "[", "awesome", BF(5.05), BI(1986), "]", BEND };
 *
 *     C driver calls:
 *         bson_init( b );
 *         bson_append_start_array( b, "BSON" );
 *         bson_append_string( b, "0", "awesome" );
 *         bson_append_double( b, "1", 5.05 );
 *         bson_append_int( b, "2", 1986 );
 *         bson_append_finish_array( b );
 *         ret = bson_finish( b );
 *         bson_print( b );
 *         bson_destroy( b );
 *
 * Peformance
 * ----------
 * With compiler optimization -O3, BCON costs about 1.1 to 1.2 times as much
 * as the equivalent bson function calls required to explicitly construct the document.
 * This is significantly less than the cost of parsing JSON and constructing BSON,
 * and BCON allows value interpolation via pointers.
 *
 * Reference Interpolation
 * -----------------------
 * Reference interpolation uses three-character macros starting with "BR" for simple dynamic values.
 * You can change the referenced content and the new values will be interpolated when you generate BSON from BCON.
 *
 *     bson b[1];
 *     char name[] = "pi";
 *     double value = 3.14159;
 *     bcon bc[] = { "name", BRS(name), "value", BRF(&value), BEND };
 *     bson_from_bcon( b, bc ); // generates { name: "pi", "value", 3.14159 }
 *     strcpy(name, "e");
 *     value = 2.71828;
 *     bson_from_bcon( b, bc ); // generates { name: "pi", "value", 3.14159 }
 *
 * Please remember that in C, the array type is anomalous in that an identifier is (already) a reference,
 * therefore there is no ampersand '&' preceding the identifier for reference interpolation.
 * This applies to BRS(cstring), BRD(doc), BRA(array), BRO(oid), and BRX(symbol).
 * An ampersand '&' is needed for value types BRF(&double), BRB(&boolean), BRT(&time), BRI(&int), and BRL(&long).
 * For completeness, BRS, BRD, BRA, BRO, and BRX are defined even though BS, BD, BA, BO, and BX are equivalent.
 *
 * Pointer Interpolation
 * ---------------------
 * Pointer(-to-reference) interpolation uses three-character macros starting with "BP" for _conditional_ dynamic values.
 * You can change the pointer content and the new values will be interpolated when you generate BSON from BCON.
 * If you set the pointer to null, the element will skipped and not inserted into the generated BSON document.
 *
 *     bson b[1];
 *     char name[] = "pi";
 *     char new_name[] = "log(0)";
 *     char **pname = (char**)&name;
 *     double value = 3.14159;
 *     double *pvalue = &value;
 *     bcon bc[] = { "name", BPS(&pname), "value", BPF(&pvalue), BEND };
 *     bson_from_bcon( b, bc ); // generates { name: "pi", "value", 3.14159 }
 *     pname = (char**)&new_name;
 *     pvalue = 0;
 *     bson_from_bcon( b, bc ); // generates { name: "log(0)" }
 *
 * Pointer interpolation necessarily adds an extra level of indirection and complexity.
 * All macro pointer arguments are preceded by '&'.
 * Underlying pointer types are double-indirect (**) for array types and single-indirect (*) for value types.
 * Char name[] is used above to highlight that the array reference is not assignable (in contrast to char *array).
 * Please note the (char**)& cast-address sequence required to silence the "incompatible-pointer-types" warning.
 *
 * Additional Notes
 * ----------------
 * Use the BS macro or the ":_s:" type specifier for string to allow string values that collide with type specifiers, braces, or square brackets.
 *
 *     bson b[1];
 *     bcon bc[] = { "spec", BS(":_s:"), BEND };
 *     bson_from_bcon( b, bc ); // generates { spec: ":_s:" }
 *
 * BCON does not yet support the following BSON types.
 *
 *     05  e_name  binary              Binary data
 *     06  e_name                      undefined - deprecated
 *     0B  e_name  cstring cstring     Regular expression
 *     0C  e_name  string (byte*12)    DBPointer - Deprecated
 *     0D  e_name  string              JavaScript code
 *     0F  e_name  code_w_s            JavaScript code w/ scope
 *     11  e_name  int64               Timestamp
 *     FF  e_name                      Min key
 *     7F  e_name                      Max key
 *
 */

typedef union bcon {
    char *s;         /**< 02  e_name  string              Macro BS(v)  - UTF-8 string */ /* must be first to be default */
    char *Rs;        /**< 02  e_name  string              Macro BRS(v) - UTF-8 string reference interpolation */
    char **Ps;       /**< 02  e_name  string              Macro BPS(v) - UTF-8 string pointer interpolation */
    double f;        /**< 01  e_name  double              Macro BF(v)  - Floating point */
    double *Rf;      /**< 01  e_name  double              Macro BRF(v) - Floating point reference interpolation */
    double **Pf;     /**< 01  e_name  double              Macro BPF(v) - Floating point pointer interpolation */
    union bcon *D;   /**< 03  e_name  document            Macro BD(v)  - Embedded document interpolation */
    union bcon *RD;  /**< 03  e_name  document            Macro BRD(v) - Embedded document reference interpolation */
    union bcon **PD; /**< 03  e_name  document            Macro BPD(v) - Embedded document pointer interpolation */
    union bcon *A;   /**< 04  e_name  document            Macro BA(v)  - Array interpolation */
    union bcon *RA;  /**< 04  e_name  document            Macro BRA(v) - Array reference interpolation */
    union bcon **PA; /**< 04  e_name  document            Macro BPA(v) - Array pointer interpolation */
    char *o;         /**< 07  e_name  (byte*12)           Macro BO(v)  - ObjectId */
    char *Ro;        /**< 07  e_name  (byte*12)           Macro BRO(v) - ObjectId reference interpolation */
    char **Po;       /**< 07  e_name  (byte*12)           Macro BPO(v) - ObjectId pointer interpolation */
    bson_bool_t b;   /**< 08  e_name  00                  Macro BB(v)  - Boolean "false"
                          08  e_name  01                  Macro BB(v) - Boolean "true" */
    bson_bool_t *Rb; /**< 08  e_name  01                  Macro BRB(v) - Boolean reference interpolation */
    bson_bool_t **Pb;/**< 08  e_name  01                  Macro BPB(v) - Boolean pointer interpolation */
    time_t t;        /**< 09  e_name  int64               Macro BT(v)  - UTC datetime */
    time_t *Rt;      /**< 09  e_name  int64               Macro BRT(v) - UTC datetime reference interpolation */
    time_t **Pt;     /**< 09  e_name  int64               Macro BPT(v) - UTC datetime pointer interpolation */
    char *v;         /**< 0A  e_name                      Macro BNULL  - Null value */
    char *x;         /**< 0E  e_name  string              Macro BX(v)  - Symbol */
    char *Rx;        /**< 0E  e_name  string              Macro BRX(v) - Symbol reference interpolation */
    char **Px;       /**< 0E  e_name  string              Macro BPX(v) - Symbol pointer interpolation */
    int i;           /**< 10  e_name  int32               Macro BI(v)  - 32-bit Integer */
    int *Ri;         /**< 10  e_name  int32               Macro BRI(v) - 32-bit Integer reference interpolation */
    int **Pi;        /**< 10  e_name  int32               Macro BPI(v) - 32-bit Integer pointer interpolation */
    long l;          /**< 12  e_name  int64               Macro BL(v)  - 64-bit Integer */
    long *Rl;        /**< 12  e_name  int64               Macro BRL(v) - 64-bit Integer reference interpolation */
    long **Pl;       /**< 12  e_name  int64               Macro BPL(v) - 64-bit Integer pointer interpolation */
    void **Pv;       /*                                   generic pointer internal */
    /* "{" "}" */    /*   03  e_name  document            Embedded document */
    /* "[" "]" */    /*   04  e_name  document            Array */
                     /*   05  e_name  binary              Binary data */
                     /*   06  e_name                      undefined - deprecated */
                     /*   0B  e_name  cstring cstring     Regular expression */
                     /*   0C  e_name  string (byte*12)    DBPointer - Deprecated */
                     /*   0D  e_name  string              JavaScript code */
                     /*   0F  e_name  code_w_s            JavaScript code w/ scope  */
                     /*   11  e_name  int64               Timestamp */
                     /*   FF  e_name                      Min key */
                     /*   7F  e_name                      Max key */
} bcon;

/** BCON document terminator */
#define BEND "."

/** BCON internal 01 double Floating point type-specifier */
#define BTF ":_f:"
/** BCON internal 02 char* string type-specifier */
#define BTS ":_s:"
/** BCON internal 03 union bcon* Embedded document interpolation type-specifier */
#define BTD ":_D:"
/** BCON internal 04 union bcon* Array interpolation type-specifier */
#define BTA ":_A:"
/** BCON internal 07 char* ObjectId type-specifier */
#define BTO ":_o:"
/** BCON internal 08 int Boolean type-specifier */
#define BTB ":_b:"
/** BCON internal 09 int64 UTC datetime type-specifier */
#define BTT ":_t:"
/** BCON internal 0A Null type-specifier */
#define BTN ":_v:"
/** BCON internal 0E char* Symbol type-specifier */
#define BTX ":_x:"
/** BCON internal 10 int32 64-bit Integer type-specifier */
#define BTI ":_i:"
/** BCON internal 12 int64 64-bit Integer type-specifier */
#define BTL ":_l:"

/** BCON internal 01 double* Floating point reference interpolation type-specifier */
#define BTRF ":Rf:"
/** BCON internal 02 char* string reference interpolation type-specifier */
#define BTRS ":Rs:"
/** BCON internal 03 union bcon* Embedded document reference interpolation type-specifier */
#define BTRD ":RD:"
/** BCON internal 04 union bcon* Array reference interpolation type-specifier */
#define BTRA ":RA:"
/** BCON internal 07 char* ObjectId reference interpolation type-specifier */
#define BTRO ":Ro:"
/** BCON internal 08 int* Boolean reference interpolation type-specifier */
#define BTRB ":Rb:"
/** BCON internal 09 int64* UTC datetime reference interpolation type-specifier */
#define BTRT ":Rt:"
/** BCON internal 0E char* Symbol reference interpolation type-specifier */
#define BTRX ":Rx:"
/** BCON internal 10 int32* 23-bit Integer reference interpolation type-specifier */
#define BTRI ":Ri:"
/** BCON internal 12 int64* 64-bit Integer reference interpolation type-specifier */
#define BTRL ":Rl:"

/** BCON internal 01 double** Floating point pointer interpolation type-specifier */
#define BTPF ":Pf:"
/** BCON internal 02 char** string pointer interpolation type-specifier */
#define BTPS ":Ps:"
/** BCON internal 03 union bcon** Embedded document pointer interpolation type-specifier */
#define BTPD ":PD:"
/** BCON internal 04 union bcon** Array pointer interpolation type-specifier */
#define BTPA ":PA:"
/** BCON internal 07 char** ObjectId pointer interpolation type-specifier */
#define BTPO ":Po:"
/** BCON internal 08 int** Boolean pointer interpolation type-specifier */
#define BTPB ":Pb:"
/** BCON internal 09 int64** UTC datetime pointer interpolation type-specifier */
#define BTPT ":Pt:"
/** BCON internal 0E char** Symbol pointer interpolation type-specifier */
#define BTPX ":Px:"
/** BCON internal 10 int32** 23-bit Integer pointer interpolation type-specifier */
#define BTPI ":Pi:"
/** BCON internal 12 int64** 64-bit Integer pointer interpolation type-specifier */
#define BTPL ":Pl:"

/** BCON 01 double Floating point value */
#define BF(v) BTF, { .f = (v) }
/** BCON 02 char* string value */
#define BS(v) BTS, { .s = (v) }
/** BCON 03 union bcon* Embedded document interpolation value */
#define BD(v) BTD, { .D = (v) }
/** BCON 04 union bcon* Array interpolation value */
#define BA(v) BTA, { .A = (v) }
/** BCON 07 char* ObjectId value */
#define BO(v) BTO, { .o = (v) }
/** BCON 08 int Boolean value */
#define BB(v) BTB, { .b = (v) }
/** BCON 09 int64 UTC datetime value */
#define BT(v) BTT, { .t = (v) }
/** BCON 0A Null value */
#define BNULL BTN, { .v = ("") }
/** BCON 0E char* Symbol value */
#define BX(v) BTX, { .x = (v) }
/** BCON 10 int32 32-bit Integer value */
#define BI(v) BTI, { .i = (v) }
/** BCON 12 int64 64-bit Integer value */
#define BL(v) BTL, { .l = (v) }

/** BCON 01 double* Floating point interpolation value */
#define BRF(v) BTRF, { .Rf = (v) }
/** BCON 02 char* string interpolation value */
#define BRS(v) BTRS, { .Rs = (v) }
/** BCON 03 union bcon* Embedded document interpolation value */
#define BRD(v) BTRD, { .RD = (v) }
/** BCON 04 union bcon* Array interpolation value */
#define BRA(v) BTRA, { .RA = (v) }
/** BCON 07 char* ObjectId interpolation value */
#define BRO(v) BTRO, { .Ro = (v) }
/** BCON 08 int* Boolean interpolation value */
#define BRB(v) BTRB, { .Rb = (v) }
/** BCON 09 int64* UTC datetime  value */
#define BRT(v) BTRT, { .Rt = (v) }
/** BCON 0E char* Symbol interpolation value */
#define BRX(v) BTRX, { .Rx = (v) }
/** BCON 10 int32* 32-bit Integer interpolation value */
#define BRI(v) BTRI, { .Ri = (v) }
/** BCON 12 int64* 64-bit Integer interpolation value */
#define BRL(v) BTRL, { .Rl = (v) }

/** BCON 01 double** Floating point interpolation value */
#define BPF(v) BTPF, { .Pf = (v) }
/** BCON 02 char** string interpolation value */
#define BPS(v) BTPS, { .Ps = ((char**)v) }
/** BCON 03 union bcon** Embedded document interpolation value */
#define BPD(v) BTPD, { .PD = ((union bcon **)v) }
/** BCON 04 union bcon** Array interpolation value */
#define BPA(v) BTPA, { .PA = ((union bcon **)v) }
/** BCON 07 char** ObjectId interpolation value */
#define BPO(v) BTPO, { .Po = ((char**)v) }
/** BCON 08 int** Boolean interpolation value */
#define BPB(v) BTPB, { .Pb = (v) }
/** BCON 09 int64** UTC datetime  value */
#define BPT(v) BTPT, { .Pt = (v) }
/** BCON 0E char** Symbol interpolation value */
#define BPX(v) BTPX, { .Px = ((char**)v) }
/** BCON 10 int32** 32-bit Integer interpolation value */
#define BPI(v) BTPI, { .Pi = (v) }
/** BCON 12 int64** 64-bit Integer interpolation value */
#define BPL(v) BTPL, { .Pl = (v) }

/*
 * References on codes used for types
 *     http://en.wikipedia.org/wiki/Name_mangling
 *     http://www.agner.org/optimize/calling_conventions.pdf (page 25)
 */

typedef enum bcon_error_t {
    BCON_OK = 0, /**< OK return code */
    BCON_ERROR,  /**< ERROR return code */
    BCON_DOCUMENT_INCOMPLETE, /**< bcon document or nesting incomplete */
    BCON_BSON_ERROR /**< bson finish error */
} bcon_error_t;

extern char *bcon_errstr[]; /**< bcon_error_t text messages */

/**
 * Append a BCON object to a BSON object.
 *
 * @param b a BSON object
 * @param bc a BCON object
 */
MONGO_EXPORT bcon_error_t bson_append_bcon(bson *b, const bcon *bc);

/**
 * Generate a BSON object from a BCON object.
 *
 * @param b a BSON object
 * @param bc a BCON object
 */
MONGO_EXPORT bcon_error_t bson_from_bcon( bson *b, const bcon *bc );

/**
 * Print a string representation of a BCON object.
 *
 * @param bc the BCON object to print.
 */
MONGO_EXPORT void bcon_print( const bcon *bc );

#ifndef DOXYGEN_SHOULD_SKIP_THIS

MONGO_EXTERN_C_END

typedef enum bcon_token_t {
    Token_Default, Token_End, Token_Typespec,
    Token_OpenBrace, Token_CloseBrace, Token_OpenBracket, Token_CloseBracket,
    Token_EOD
} bcon_token_t;

#endif /* DOXYGEN_SHOULD_SKIP_THIS */

#endif