mongory 0.6.3 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +2 -0
- data/CHANGELOG.md +46 -0
- data/README.md +83 -176
- data/Rakefile +77 -0
- data/SUBMODULE_INTEGRATION.md +325 -0
- data/docs/advanced_usage.md +40 -0
- data/docs/clang_bridge.md +69 -0
- data/docs/field_names.md +30 -0
- data/docs/migration.md +30 -0
- data/docs/performance.md +61 -0
- data/examples/benchmark.rb +98 -19
- data/ext/mongory_ext/extconf.rb +91 -0
- data/ext/mongory_ext/mongory-core/LICENSE +3 -0
- data/ext/mongory_ext/mongory-core/include/mongory-core/foundations/array.h +105 -0
- data/ext/mongory_ext/mongory-core/include/mongory-core/foundations/config.h +206 -0
- data/ext/mongory_ext/mongory-core/include/mongory-core/foundations/error.h +82 -0
- data/ext/mongory_ext/mongory-core/include/mongory-core/foundations/memory_pool.h +95 -0
- data/ext/mongory_ext/mongory-core/include/mongory-core/foundations/table.h +108 -0
- data/ext/mongory_ext/mongory-core/include/mongory-core/foundations/value.h +175 -0
- data/ext/mongory_ext/mongory-core/include/mongory-core/matchers/matcher.h +76 -0
- data/ext/mongory_ext/mongory-core/include/mongory-core.h +12 -0
- data/ext/mongory_ext/mongory-core/src/foundations/array.c +246 -0
- data/ext/mongory_ext/mongory-core/src/foundations/array_private.h +18 -0
- data/ext/mongory_ext/mongory-core/src/foundations/config.c +406 -0
- data/ext/mongory_ext/mongory-core/src/foundations/config_private.h +30 -0
- data/ext/mongory_ext/mongory-core/src/foundations/error.c +30 -0
- data/ext/mongory_ext/mongory-core/src/foundations/memory_pool.c +298 -0
- data/ext/mongory_ext/mongory-core/src/foundations/string_buffer.c +65 -0
- data/ext/mongory_ext/mongory-core/src/foundations/string_buffer.h +49 -0
- data/ext/mongory_ext/mongory-core/src/foundations/table.c +458 -0
- data/ext/mongory_ext/mongory-core/src/foundations/value.c +459 -0
- data/ext/mongory_ext/mongory-core/src/matchers/array_record_matcher.c +309 -0
- data/ext/mongory_ext/mongory-core/src/matchers/array_record_matcher.h +47 -0
- data/ext/mongory_ext/mongory-core/src/matchers/base_matcher.c +161 -0
- data/ext/mongory_ext/mongory-core/src/matchers/base_matcher.h +115 -0
- data/ext/mongory_ext/mongory-core/src/matchers/compare_matcher.c +210 -0
- data/ext/mongory_ext/mongory-core/src/matchers/compare_matcher.h +83 -0
- data/ext/mongory_ext/mongory-core/src/matchers/composite_matcher.c +539 -0
- data/ext/mongory_ext/mongory-core/src/matchers/composite_matcher.h +125 -0
- data/ext/mongory_ext/mongory-core/src/matchers/existance_matcher.c +144 -0
- data/ext/mongory_ext/mongory-core/src/matchers/existance_matcher.h +48 -0
- data/ext/mongory_ext/mongory-core/src/matchers/external_matcher.c +121 -0
- data/ext/mongory_ext/mongory-core/src/matchers/external_matcher.h +46 -0
- data/ext/mongory_ext/mongory-core/src/matchers/inclusion_matcher.c +199 -0
- data/ext/mongory_ext/mongory-core/src/matchers/inclusion_matcher.h +46 -0
- data/ext/mongory_ext/mongory-core/src/matchers/literal_matcher.c +334 -0
- data/ext/mongory_ext/mongory-core/src/matchers/literal_matcher.h +97 -0
- data/ext/mongory_ext/mongory-core/src/matchers/matcher.c +198 -0
- data/ext/mongory_ext/mongory-core/src/matchers/matcher_explainable.c +107 -0
- data/ext/mongory_ext/mongory-core/src/matchers/matcher_explainable.h +50 -0
- data/ext/mongory_ext/mongory-core/src/matchers/matcher_traversable.c +55 -0
- data/ext/mongory_ext/mongory-core/src/matchers/matcher_traversable.h +23 -0
- data/ext/mongory_ext/mongory_ext.c +635 -0
- data/lib/mongory/c_query_builder.rb +44 -0
- data/lib/mongory/query_builder.rb +8 -0
- data/lib/mongory/utils/context.rb +7 -0
- data/lib/mongory/version.rb +1 -1
- data/lib/mongory.rb +7 -0
- data/mongory.gemspec +10 -4
- data/scripts/build_with_core.sh +292 -0
- metadata +69 -4
@@ -0,0 +1,459 @@
|
|
1
|
+
/**
|
2
|
+
* @file value.c
|
3
|
+
* @brief Implements the mongory_value generic value type and its operations.
|
4
|
+
*
|
5
|
+
* This file provides functions for creating (`wrap`), comparing, and
|
6
|
+
* converting `mongory_value` instances to strings. Each data type supported by
|
7
|
+
* `mongory_value` has a corresponding comparison function and wrapping
|
8
|
+
* function.
|
9
|
+
*/
|
10
|
+
#include "string_buffer.h"
|
11
|
+
#include <mongory-core/foundations/array.h>
|
12
|
+
#include <mongory-core/foundations/config.h> // For mongory_string_cpy
|
13
|
+
#include <mongory-core/foundations/memory_pool.h>
|
14
|
+
#include <mongory-core/foundations/table.h>
|
15
|
+
#include <mongory-core/foundations/value.h>
|
16
|
+
#include "config_private.h"
|
17
|
+
#include <stddef.h> // For NULL
|
18
|
+
#include <stdio.h> // For snprintf
|
19
|
+
#include <stdlib.h> // For general utilities (not directly used here but common)
|
20
|
+
#include <string.h> // For strcmp
|
21
|
+
|
22
|
+
/**
|
23
|
+
* @brief Returns a string literal representing the type of the mongory_value.
|
24
|
+
* @param value The mongory_value to inspect.
|
25
|
+
* @return A string like "Int", "String", "Array", etc., or "UnknownType".
|
26
|
+
*/
|
27
|
+
char *mongory_type_to_string(mongory_value *value) {
|
28
|
+
if (!value)
|
29
|
+
return "NullValuePtr"; // Handle null pointer to value itself
|
30
|
+
switch (value->type) {
|
31
|
+
// Use X-Macro to generate cases for each defined type.
|
32
|
+
#define CASE_GEN(name, num, str, field) \
|
33
|
+
case name: \
|
34
|
+
return str;
|
35
|
+
MONGORY_TYPE_MACRO(CASE_GEN)
|
36
|
+
#undef CASE_GEN
|
37
|
+
default:
|
38
|
+
return "UnknownType"; // Fallback for unrecognized types.
|
39
|
+
}
|
40
|
+
}
|
41
|
+
|
42
|
+
/**
|
43
|
+
* @brief Extracts a void pointer to the raw data within the mongory_value.
|
44
|
+
* The caller must know the actual type to cast this pointer correctly.
|
45
|
+
* @param value The mongory_value from which to extract data.
|
46
|
+
* @return A void pointer to the data, or NULL for unknown types or MONGORY_TYPE_NULL.
|
47
|
+
*/
|
48
|
+
void *mongory_value_extract(mongory_value *value) {
|
49
|
+
if (!value)
|
50
|
+
return NULL;
|
51
|
+
switch (value->type) {
|
52
|
+
// Use X-Macro to generate cases. For MONGORY_TYPE_NULL, &value->data.i is
|
53
|
+
// returned but is meaningless as data for NULL.
|
54
|
+
#define EXTRACT_CASE(name, num, str, field) \
|
55
|
+
case name: \
|
56
|
+
return (void *)&value->data.field;
|
57
|
+
MONGORY_TYPE_MACRO(EXTRACT_CASE)
|
58
|
+
#undef EXTRACT_CASE
|
59
|
+
default:
|
60
|
+
return NULL; // Unknown type.
|
61
|
+
}
|
62
|
+
}
|
63
|
+
|
64
|
+
static char *mongory_value_null_to_str(mongory_value *value, mongory_memory_pool *pool);
|
65
|
+
static char *mongory_value_bool_to_str(mongory_value *value, mongory_memory_pool *pool);
|
66
|
+
static char *mongory_value_int_to_str(mongory_value *value, mongory_memory_pool *pool);
|
67
|
+
static char *mongory_value_double_to_str(mongory_value *value, mongory_memory_pool *pool);
|
68
|
+
static char *mongory_value_string_to_str(mongory_value *value, mongory_memory_pool *pool);
|
69
|
+
static char *mongory_value_array_to_str(mongory_value *value, mongory_memory_pool *pool);
|
70
|
+
static char *mongory_value_table_to_str(mongory_value *value, mongory_memory_pool *pool);
|
71
|
+
static char *mongory_value_generic_ptr_to_str(mongory_value *value, mongory_memory_pool *pool);
|
72
|
+
|
73
|
+
/**
|
74
|
+
* @brief Internal helper to allocate a new mongory_value structure from a pool.
|
75
|
+
* @param pool The memory pool to allocate from.
|
76
|
+
* @return A pointer to the new mongory_value, or NULL on allocation failure.
|
77
|
+
*/
|
78
|
+
static inline mongory_value *mongory_value_new(mongory_memory_pool *pool) {
|
79
|
+
if (!pool || !pool->alloc)
|
80
|
+
return NULL; // Invalid pool.
|
81
|
+
mongory_value *value = MG_ALLOC_PTR(pool, mongory_value);
|
82
|
+
if (!value) {
|
83
|
+
// TODO: pool->error could be set by pool->alloc itself.
|
84
|
+
return NULL;
|
85
|
+
}
|
86
|
+
value->pool = pool;
|
87
|
+
value->origin = NULL; // Default origin to NULL.
|
88
|
+
return value;
|
89
|
+
}
|
90
|
+
|
91
|
+
// ============================================================================
|
92
|
+
// Comparison Functions
|
93
|
+
//
|
94
|
+
// Each data type has a corresponding comparison function. These functions
|
95
|
+
// are assigned to the `comp` function pointer in the `mongory_value` struct.
|
96
|
+
// They typically handle comparisons with other compatible types (e.g., Int
|
97
|
+
// can be compared with Double).
|
98
|
+
// ============================================================================
|
99
|
+
|
100
|
+
/** Compares two MONGORY_TYPE_NULL values. Always equal. */
|
101
|
+
static inline int mongory_value_null_compare(mongory_value *a, mongory_value *b) {
|
102
|
+
(void)a; // 'a' is implicitly MONGORY_TYPE_NULL by context of call.
|
103
|
+
if (b->type != MONGORY_TYPE_NULL) {
|
104
|
+
return mongory_value_compare_fail; // Cannot compare NULL with non-NULL.
|
105
|
+
}
|
106
|
+
return 0; // NULL is equal to NULL.
|
107
|
+
}
|
108
|
+
|
109
|
+
/** Wraps a NULL value. The `n` parameter is ignored. */
|
110
|
+
mongory_value *mongory_value_wrap_n(mongory_memory_pool *pool, void *n) {
|
111
|
+
(void)n; // Parameter 'n' is unused for wrapping NULL.
|
112
|
+
mongory_value *value = mongory_value_new(pool);
|
113
|
+
if (!value)
|
114
|
+
return NULL;
|
115
|
+
value->type = MONGORY_TYPE_NULL;
|
116
|
+
value->comp = mongory_value_null_compare;
|
117
|
+
value->to_str = mongory_value_null_to_str;
|
118
|
+
// data union is not explicitly set for NULL.
|
119
|
+
return value;
|
120
|
+
}
|
121
|
+
|
122
|
+
// ============================================================================
|
123
|
+
// Wrapper Functions
|
124
|
+
//
|
125
|
+
// These functions create a `mongory_value` and wrap a native C type
|
126
|
+
// (like bool, int, char*). They allocate the value from the memory pool and
|
127
|
+
// set its type, data, and function pointers (`comp`, `to_str`).
|
128
|
+
// ============================================================================
|
129
|
+
|
130
|
+
/** Compares two MONGORY_TYPE_BOOL values. */
|
131
|
+
static inline int mongory_value_bool_compare(mongory_value *a, mongory_value *b) {
|
132
|
+
if (b->type != MONGORY_TYPE_BOOL)
|
133
|
+
return mongory_value_compare_fail;
|
134
|
+
// Standard comparison: (true > false)
|
135
|
+
return (a->data.b > b->data.b) - (a->data.b < b->data.b);
|
136
|
+
}
|
137
|
+
|
138
|
+
/** Wraps a boolean value. */
|
139
|
+
mongory_value *mongory_value_wrap_b(mongory_memory_pool *pool, bool b_val) {
|
140
|
+
mongory_value *value = mongory_value_new(pool);
|
141
|
+
if (!value)
|
142
|
+
return NULL;
|
143
|
+
value->type = MONGORY_TYPE_BOOL;
|
144
|
+
value->data.b = b_val;
|
145
|
+
value->comp = mongory_value_bool_compare;
|
146
|
+
value->to_str = mongory_value_bool_to_str;
|
147
|
+
return value;
|
148
|
+
}
|
149
|
+
|
150
|
+
/** Compares MONGORY_TYPE_INT with INT or DOUBLE. */
|
151
|
+
static inline int mongory_value_int_compare(mongory_value *a, mongory_value *b) {
|
152
|
+
if (b->type == MONGORY_TYPE_DOUBLE) {
|
153
|
+
// Compare int (a) as double with double (b).
|
154
|
+
double a_as_double = (double)a->data.i;
|
155
|
+
double b_value = b->data.d;
|
156
|
+
return (a_as_double > b_value) - (a_as_double < b_value);
|
157
|
+
}
|
158
|
+
if (b->type == MONGORY_TYPE_INT) {
|
159
|
+
// Compare int (a) with int (b).
|
160
|
+
int64_t a_value = a->data.i;
|
161
|
+
int64_t b_value = b->data.i;
|
162
|
+
return (a_value > b_value) - (a_value < b_value);
|
163
|
+
}
|
164
|
+
return mongory_value_compare_fail; // Incompatible type for comparison.
|
165
|
+
}
|
166
|
+
|
167
|
+
/** Wraps an integer (promoted to int64_t). */
|
168
|
+
mongory_value *mongory_value_wrap_i(mongory_memory_pool *pool, int i_val) {
|
169
|
+
mongory_value *value = mongory_value_new(pool);
|
170
|
+
if (!value)
|
171
|
+
return NULL;
|
172
|
+
value->type = MONGORY_TYPE_INT;
|
173
|
+
value->data.i = (int64_t)i_val; // Store as int64_t.
|
174
|
+
value->comp = mongory_value_int_compare;
|
175
|
+
value->to_str = mongory_value_int_to_str;
|
176
|
+
return value;
|
177
|
+
}
|
178
|
+
|
179
|
+
/** Compares MONGORY_TYPE_DOUBLE with DOUBLE or INT. */
|
180
|
+
static inline int mongory_value_double_compare(mongory_value *a, mongory_value *b) {
|
181
|
+
if (b->type == MONGORY_TYPE_DOUBLE) {
|
182
|
+
double a_value = a->data.d;
|
183
|
+
double b_value = b->data.d;
|
184
|
+
return (a_value > b_value) - (a_value < b_value);
|
185
|
+
}
|
186
|
+
if (b->type == MONGORY_TYPE_INT) {
|
187
|
+
// Compare double (a) with int (b) as double.
|
188
|
+
double a_value = a->data.d;
|
189
|
+
double b_as_double = (double)b->data.i;
|
190
|
+
return (a_value > b_as_double) - (a_value < b_as_double);
|
191
|
+
}
|
192
|
+
return mongory_value_compare_fail; // Incompatible type.
|
193
|
+
}
|
194
|
+
|
195
|
+
/** Wraps a double value. */
|
196
|
+
mongory_value *mongory_value_wrap_d(mongory_memory_pool *pool, double d_val) {
|
197
|
+
mongory_value *value = mongory_value_new(pool);
|
198
|
+
if (!value)
|
199
|
+
return NULL;
|
200
|
+
value->type = MONGORY_TYPE_DOUBLE;
|
201
|
+
value->data.d = d_val;
|
202
|
+
value->comp = mongory_value_double_compare;
|
203
|
+
value->to_str = mongory_value_double_to_str;
|
204
|
+
return value;
|
205
|
+
}
|
206
|
+
|
207
|
+
/** Compares two MONGORY_TYPE_STRING values lexicographically. */
|
208
|
+
static inline int mongory_value_string_compare(mongory_value *a, mongory_value *b) {
|
209
|
+
// Ensure both are strings and not NULL pointers.
|
210
|
+
if (b->type != MONGORY_TYPE_STRING || a->data.s == NULL || b->data.s == NULL) {
|
211
|
+
// If one is NULL string and other is not, how to compare?
|
212
|
+
// For now, strict: both must be valid strings.
|
213
|
+
// Or, define NULL string < non-NULL string.
|
214
|
+
// Current: fail if not string or if actual char* is NULL.
|
215
|
+
return mongory_value_compare_fail;
|
216
|
+
}
|
217
|
+
int cmp_result = strcmp(a->data.s, b->data.s);
|
218
|
+
return (cmp_result > 0) - (cmp_result < 0); // Normalize to -1, 0, 1
|
219
|
+
}
|
220
|
+
|
221
|
+
/** Wraps a string. Makes a copy of the string using the pool. */
|
222
|
+
mongory_value *mongory_value_wrap_s(mongory_memory_pool *pool, char *s_val) {
|
223
|
+
mongory_value *value = mongory_value_new(pool);
|
224
|
+
if (!value)
|
225
|
+
return NULL;
|
226
|
+
value->type = MONGORY_TYPE_STRING;
|
227
|
+
// `mongory_string_cpy` handles the allocation and copying of the string.
|
228
|
+
// If `s_val` is NULL, `value->data.s` will be NULL.
|
229
|
+
// If allocation fails, `value->data.s` will also be NULL.
|
230
|
+
// TODO: This function should ideally return NULL if the string copy fails
|
231
|
+
// when `s_val` was not NULL, but this requires a more complex error handling
|
232
|
+
// strategy with the memory pool.
|
233
|
+
value->data.s = mongory_string_cpy(pool, s_val);
|
234
|
+
value->comp = mongory_value_string_compare;
|
235
|
+
value->to_str = mongory_value_string_to_str;
|
236
|
+
return value;
|
237
|
+
}
|
238
|
+
|
239
|
+
/** Compares two MONGORY_TYPE_ARRAY values element by element. */
|
240
|
+
static inline int mongory_value_array_compare(mongory_value *a, mongory_value *b) {
|
241
|
+
if (b->type != MONGORY_TYPE_ARRAY || a->data.a == NULL || b->data.a == NULL) {
|
242
|
+
return mongory_value_compare_fail; // Must be two valid arrays.
|
243
|
+
}
|
244
|
+
struct mongory_array *array_a = a->data.a;
|
245
|
+
struct mongory_array *array_b = b->data.a;
|
246
|
+
|
247
|
+
// First, compare by array size. An array with fewer elements is "less than"
|
248
|
+
// an array with more elements.
|
249
|
+
if (array_a->count != array_b->count) {
|
250
|
+
return (array_a->count > array_b->count) - (array_a->count < array_b->count);
|
251
|
+
}
|
252
|
+
|
253
|
+
// Same count, compare element by element.
|
254
|
+
for (size_t i = 0; i < array_a->count; i++) {
|
255
|
+
mongory_value *item_a = array_a->get(array_a, i);
|
256
|
+
mongory_value *item_b = array_b->get(array_b, i);
|
257
|
+
|
258
|
+
// Handle NULL elements within arrays carefully.
|
259
|
+
bool a_item_is_null = (item_a == NULL || item_a->type == MONGORY_TYPE_NULL);
|
260
|
+
bool b_item_is_null = (item_b == NULL || item_b->type == MONGORY_TYPE_NULL);
|
261
|
+
|
262
|
+
if (a_item_is_null && b_item_is_null)
|
263
|
+
continue; // Both null, considered equal here.
|
264
|
+
if (a_item_is_null)
|
265
|
+
return -1; // Null is less than non-null.
|
266
|
+
if (b_item_is_null)
|
267
|
+
return 1; // Non-null is greater than null.
|
268
|
+
|
269
|
+
// Both items are non-null, compare them using their own comp functions.
|
270
|
+
if (!item_a->comp || !item_b->comp)
|
271
|
+
return mongory_value_compare_fail; // Should not happen for valid values
|
272
|
+
|
273
|
+
int cmp_result = item_a->comp(item_a, item_b);
|
274
|
+
if (cmp_result == mongory_value_compare_fail)
|
275
|
+
return mongory_value_compare_fail; // Incomparable elements
|
276
|
+
if (cmp_result != 0) {
|
277
|
+
return cmp_result; // First differing element determines array order.
|
278
|
+
}
|
279
|
+
}
|
280
|
+
return 0; // All elements are equal.
|
281
|
+
}
|
282
|
+
|
283
|
+
/** Wraps a mongory_array. */
|
284
|
+
mongory_value *mongory_value_wrap_a(mongory_memory_pool *pool, struct mongory_array *a_val) {
|
285
|
+
mongory_value *value = mongory_value_new(pool);
|
286
|
+
if (!value)
|
287
|
+
return NULL;
|
288
|
+
value->type = MONGORY_TYPE_ARRAY;
|
289
|
+
value->data.a = a_val;
|
290
|
+
value->comp = mongory_value_array_compare;
|
291
|
+
value->to_str = mongory_value_array_to_str;
|
292
|
+
return value;
|
293
|
+
}
|
294
|
+
|
295
|
+
/** Compares two MONGORY_TYPE_TABLE values. Currently unsupported (always fails). */
|
296
|
+
static inline int mongory_value_table_compare(mongory_value *a, mongory_value *b) {
|
297
|
+
(void)a; // Unused.
|
298
|
+
(void)b; // Unused.
|
299
|
+
// True table comparison is complex because the order of keys is not
|
300
|
+
// significant. It would require iterating over keys of one table and checking
|
301
|
+
// for their presence and value equality in the other. This is not
|
302
|
+
// implemented. Therefore, tables are considered incomparable.
|
303
|
+
return mongory_value_compare_fail;
|
304
|
+
}
|
305
|
+
|
306
|
+
/** Wraps a mongory_table. */
|
307
|
+
mongory_value *mongory_value_wrap_t(mongory_memory_pool *pool, struct mongory_table *t_val) {
|
308
|
+
mongory_value *value = mongory_value_new(pool);
|
309
|
+
if (!value)
|
310
|
+
return NULL;
|
311
|
+
value->type = MONGORY_TYPE_TABLE;
|
312
|
+
value->data.t = t_val;
|
313
|
+
value->comp = mongory_value_table_compare;
|
314
|
+
value->to_str = mongory_value_table_to_str;
|
315
|
+
return value;
|
316
|
+
}
|
317
|
+
|
318
|
+
/** Generic comparison for types not otherwise handled (e.g. POINTER, REGEX, UNSUPPORTED). Always fails. */
|
319
|
+
static inline int mongory_value_generic_ptr_compare(mongory_value *a, mongory_value *b) {
|
320
|
+
(void)a; // Unused.
|
321
|
+
(void)b; // Unused.
|
322
|
+
// Generic pointers are generally not comparable in a meaningful way beyond identity.
|
323
|
+
return mongory_value_compare_fail;
|
324
|
+
}
|
325
|
+
|
326
|
+
/** Wraps an unsupported/unknown type pointer. */
|
327
|
+
mongory_value *mongory_value_wrap_u(mongory_memory_pool *pool, void *u_val) {
|
328
|
+
mongory_value *value = mongory_value_new(pool);
|
329
|
+
if (!value)
|
330
|
+
return NULL;
|
331
|
+
value->type = MONGORY_TYPE_UNSUPPORTED;
|
332
|
+
value->data.u = u_val;
|
333
|
+
value->comp = mongory_value_generic_ptr_compare; // Unsupported types are not comparable.
|
334
|
+
value->to_str = mongory_value_generic_ptr_to_str;
|
335
|
+
return value;
|
336
|
+
}
|
337
|
+
|
338
|
+
static char *mongory_value_regex_to_str(mongory_value *value, mongory_memory_pool *pool) {
|
339
|
+
char *str = mongory_internal_regex_adapter->stringify_func(pool, value);
|
340
|
+
if (!str)
|
341
|
+
return NULL;
|
342
|
+
return str;
|
343
|
+
}
|
344
|
+
|
345
|
+
/** Wraps a regex type pointer. */
|
346
|
+
mongory_value *mongory_value_wrap_regex(mongory_memory_pool *pool, void *regex_val) {
|
347
|
+
mongory_value *value = mongory_value_new(pool);
|
348
|
+
if (!value)
|
349
|
+
return NULL;
|
350
|
+
value->type = MONGORY_TYPE_REGEX;
|
351
|
+
value->data.regex = regex_val;
|
352
|
+
value->comp = mongory_value_generic_ptr_compare; // Regex values are not directly comparable.
|
353
|
+
value->to_str = mongory_value_regex_to_str;
|
354
|
+
return value;
|
355
|
+
}
|
356
|
+
|
357
|
+
/** Wraps a generic void pointer. */
|
358
|
+
mongory_value *mongory_value_wrap_ptr(mongory_memory_pool *pool, void *ptr_val) {
|
359
|
+
mongory_value *value = mongory_value_new(pool);
|
360
|
+
if (!value)
|
361
|
+
return NULL;
|
362
|
+
value->type = MONGORY_TYPE_POINTER;
|
363
|
+
value->data.ptr = ptr_val;
|
364
|
+
value->comp = mongory_value_generic_ptr_compare; // Generic pointers are not comparable.
|
365
|
+
value->to_str = mongory_value_generic_ptr_to_str;
|
366
|
+
return value;
|
367
|
+
}
|
368
|
+
|
369
|
+
// ============================================================================
|
370
|
+
// Stringify Functions
|
371
|
+
//
|
372
|
+
// Each data type has a corresponding `to_str` function that converts the
|
373
|
+
// value to a string representation (often JSON-like) and appends it to a
|
374
|
+
// `mongory_string_buffer`.
|
375
|
+
// ============================================================================
|
376
|
+
|
377
|
+
static char *mongory_value_null_to_str(mongory_value *value, mongory_memory_pool *pool) {
|
378
|
+
(void)value;
|
379
|
+
return mongory_string_cpy(pool, "null");
|
380
|
+
}
|
381
|
+
|
382
|
+
static char *mongory_value_bool_to_str(mongory_value *value, mongory_memory_pool *pool) {
|
383
|
+
return mongory_string_cpy(pool, value->data.b ? "true" : "false");
|
384
|
+
}
|
385
|
+
|
386
|
+
static char *mongory_value_int_to_str(mongory_value *value, mongory_memory_pool *pool) {
|
387
|
+
return mongory_string_cpyf(pool, "%lld", (long long)value->data.i);
|
388
|
+
}
|
389
|
+
|
390
|
+
static char *mongory_value_double_to_str(mongory_value *value, mongory_memory_pool *pool) {
|
391
|
+
return mongory_string_cpyf(pool, "%f", value->data.d);
|
392
|
+
}
|
393
|
+
|
394
|
+
static char *mongory_value_string_to_str(mongory_value *value, mongory_memory_pool *pool) {
|
395
|
+
return mongory_string_cpyf(pool, "\"%s\"", value->data.s);
|
396
|
+
}
|
397
|
+
|
398
|
+
typedef struct mongory_value_container_to_str_ctx {
|
399
|
+
size_t count;
|
400
|
+
size_t total;
|
401
|
+
mongory_string_buffer *buffer; /**< The string buffer to append to. */
|
402
|
+
} mongory_value_container_to_str_ctx;
|
403
|
+
|
404
|
+
static bool mongory_value_array_to_str_each(mongory_value *value, void *ctx) {
|
405
|
+
mongory_value_container_to_str_ctx *context = (mongory_value_container_to_str_ctx *)ctx;
|
406
|
+
mongory_string_buffer *buffer = context->buffer;
|
407
|
+
char *str = value->to_str(value, buffer->pool);
|
408
|
+
if (!str)
|
409
|
+
return false;
|
410
|
+
mongory_string_buffer_append(buffer, str);
|
411
|
+
context->count++;
|
412
|
+
if (context->count < context->total) {
|
413
|
+
mongory_string_buffer_append(buffer, ",");
|
414
|
+
}
|
415
|
+
return true;
|
416
|
+
}
|
417
|
+
|
418
|
+
static char *mongory_value_array_to_str(mongory_value *value, mongory_memory_pool *pool) {
|
419
|
+
mongory_string_buffer *buffer = mongory_string_buffer_new(pool);
|
420
|
+
if (!buffer)
|
421
|
+
return NULL;
|
422
|
+
mongory_string_buffer_append(buffer, "[");
|
423
|
+
struct mongory_array *array = value->data.a;
|
424
|
+
mongory_value_container_to_str_ctx ctx = {.count = 0, .total = array->count, .buffer = buffer};
|
425
|
+
array->each(array, &ctx, mongory_value_array_to_str_each);
|
426
|
+
mongory_string_buffer_append(buffer, "]");
|
427
|
+
return mongory_string_buffer_cstr(buffer);
|
428
|
+
}
|
429
|
+
|
430
|
+
static bool mongory_value_table_to_str_each(char *key, mongory_value *value, void *ctx) {
|
431
|
+
mongory_value_container_to_str_ctx *context = (mongory_value_container_to_str_ctx *)ctx;
|
432
|
+
mongory_string_buffer *buffer = context->buffer;
|
433
|
+
mongory_string_buffer_appendf(buffer, "\"%s\":", key);
|
434
|
+
char *str = value->to_str(value, buffer->pool);
|
435
|
+
if (!str)
|
436
|
+
return false;
|
437
|
+
mongory_string_buffer_append(buffer, str);
|
438
|
+
context->count++;
|
439
|
+
if (context->count < context->total) {
|
440
|
+
mongory_string_buffer_append(buffer, ",");
|
441
|
+
}
|
442
|
+
return true;
|
443
|
+
}
|
444
|
+
|
445
|
+
static char *mongory_value_table_to_str(mongory_value *value, mongory_memory_pool *pool) {
|
446
|
+
mongory_string_buffer *buffer = mongory_string_buffer_new(pool);
|
447
|
+
if (!buffer)
|
448
|
+
return NULL;
|
449
|
+
mongory_string_buffer_append(buffer, "{");
|
450
|
+
struct mongory_table *table = value->data.t;
|
451
|
+
mongory_value_container_to_str_ctx ctx = {.count = 0, .total = table->count, .buffer = buffer};
|
452
|
+
table->each(table, &ctx, mongory_value_table_to_str_each);
|
453
|
+
mongory_string_buffer_append(buffer, "}");
|
454
|
+
return mongory_string_buffer_cstr(buffer);
|
455
|
+
}
|
456
|
+
|
457
|
+
static char *mongory_value_generic_ptr_to_str(mongory_value *value, mongory_memory_pool *pool) {
|
458
|
+
return mongory_string_cpyf(pool, "%p", value->data.ptr);
|
459
|
+
}
|