rage-iodine 1.7.58
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 +7 -0
- data/.github/ISSUE_TEMPLATE/bug_report.md +40 -0
- data/.github/workflows/ruby.yml +42 -0
- data/.gitignore +20 -0
- data/.rspec +2 -0
- data/.yardopts +8 -0
- data/CHANGELOG.md +1098 -0
- data/Gemfile +11 -0
- data/LICENSE.txt +21 -0
- data/LIMITS.md +41 -0
- data/README.md +782 -0
- data/Rakefile +23 -0
- data/SPEC-PubSub-Draft.md +159 -0
- data/SPEC-WebSocket-Draft.md +239 -0
- data/bin/console +22 -0
- data/bin/info.md +353 -0
- data/bin/mustache_bench.rb +100 -0
- data/bin/poc/Gemfile.lock +23 -0
- data/bin/poc/README.md +37 -0
- data/bin/poc/config.ru +66 -0
- data/bin/poc/gemfile +1 -0
- data/bin/poc/www/index.html +57 -0
- data/examples/async_task.ru +92 -0
- data/examples/bates/README.md +3 -0
- data/examples/bates/config.ru +342 -0
- data/examples/bates/david+bold.pdf +0 -0
- data/examples/bates/public/drop-pdf.png +0 -0
- data/examples/bates/public/index.html +600 -0
- data/examples/config.ru +59 -0
- data/examples/echo.ru +59 -0
- data/examples/etag.ru +16 -0
- data/examples/hello.ru +29 -0
- data/examples/pubsub_engine.ru +81 -0
- data/examples/rack3.ru +12 -0
- data/examples/redis.ru +70 -0
- data/examples/shootout.ru +73 -0
- data/examples/sub-protocols.ru +90 -0
- data/examples/tcp_client.rb +66 -0
- data/examples/x-sendfile.ru +14 -0
- data/exe/iodine +280 -0
- data/ext/iodine/extconf.rb +110 -0
- data/ext/iodine/fio.c +12096 -0
- data/ext/iodine/fio.h +6390 -0
- data/ext/iodine/fio_cli.c +431 -0
- data/ext/iodine/fio_cli.h +189 -0
- data/ext/iodine/fio_json_parser.h +687 -0
- data/ext/iodine/fio_siphash.c +157 -0
- data/ext/iodine/fio_siphash.h +37 -0
- data/ext/iodine/fio_tls.h +129 -0
- data/ext/iodine/fio_tls_missing.c +649 -0
- data/ext/iodine/fio_tls_openssl.c +1056 -0
- data/ext/iodine/fio_tmpfile.h +50 -0
- data/ext/iodine/fiobj.h +44 -0
- data/ext/iodine/fiobj4fio.h +21 -0
- data/ext/iodine/fiobj_ary.c +333 -0
- data/ext/iodine/fiobj_ary.h +139 -0
- data/ext/iodine/fiobj_data.c +1185 -0
- data/ext/iodine/fiobj_data.h +167 -0
- data/ext/iodine/fiobj_hash.c +409 -0
- data/ext/iodine/fiobj_hash.h +176 -0
- data/ext/iodine/fiobj_json.c +622 -0
- data/ext/iodine/fiobj_json.h +68 -0
- data/ext/iodine/fiobj_mem.h +71 -0
- data/ext/iodine/fiobj_mustache.c +317 -0
- data/ext/iodine/fiobj_mustache.h +62 -0
- data/ext/iodine/fiobj_numbers.c +344 -0
- data/ext/iodine/fiobj_numbers.h +127 -0
- data/ext/iodine/fiobj_str.c +433 -0
- data/ext/iodine/fiobj_str.h +172 -0
- data/ext/iodine/fiobject.c +620 -0
- data/ext/iodine/fiobject.h +654 -0
- data/ext/iodine/hpack.h +1923 -0
- data/ext/iodine/http.c +2736 -0
- data/ext/iodine/http.h +1019 -0
- data/ext/iodine/http1.c +825 -0
- data/ext/iodine/http1.h +29 -0
- data/ext/iodine/http1_parser.h +1835 -0
- data/ext/iodine/http_internal.c +1279 -0
- data/ext/iodine/http_internal.h +248 -0
- data/ext/iodine/http_mime_parser.h +350 -0
- data/ext/iodine/iodine.c +1433 -0
- data/ext/iodine/iodine.h +64 -0
- data/ext/iodine/iodine_caller.c +218 -0
- data/ext/iodine/iodine_caller.h +27 -0
- data/ext/iodine/iodine_connection.c +941 -0
- data/ext/iodine/iodine_connection.h +55 -0
- data/ext/iodine/iodine_defer.c +420 -0
- data/ext/iodine/iodine_defer.h +6 -0
- data/ext/iodine/iodine_fiobj2rb.h +120 -0
- data/ext/iodine/iodine_helpers.c +282 -0
- data/ext/iodine/iodine_helpers.h +12 -0
- data/ext/iodine/iodine_http.c +1280 -0
- data/ext/iodine/iodine_http.h +23 -0
- data/ext/iodine/iodine_json.c +302 -0
- data/ext/iodine/iodine_json.h +6 -0
- data/ext/iodine/iodine_mustache.c +567 -0
- data/ext/iodine/iodine_mustache.h +6 -0
- data/ext/iodine/iodine_pubsub.c +580 -0
- data/ext/iodine/iodine_pubsub.h +26 -0
- data/ext/iodine/iodine_rack_io.c +273 -0
- data/ext/iodine/iodine_rack_io.h +20 -0
- data/ext/iodine/iodine_store.c +142 -0
- data/ext/iodine/iodine_store.h +20 -0
- data/ext/iodine/iodine_tcp.c +346 -0
- data/ext/iodine/iodine_tcp.h +13 -0
- data/ext/iodine/iodine_tls.c +261 -0
- data/ext/iodine/iodine_tls.h +13 -0
- data/ext/iodine/mustache_parser.h +1546 -0
- data/ext/iodine/redis_engine.c +957 -0
- data/ext/iodine/redis_engine.h +79 -0
- data/ext/iodine/resp_parser.h +317 -0
- data/ext/iodine/scheduler.c +173 -0
- data/ext/iodine/scheduler.h +6 -0
- data/ext/iodine/websocket_parser.h +506 -0
- data/ext/iodine/websockets.c +752 -0
- data/ext/iodine/websockets.h +185 -0
- data/iodine.gemspec +50 -0
- data/lib/iodine/connection.rb +61 -0
- data/lib/iodine/json.rb +42 -0
- data/lib/iodine/mustache.rb +113 -0
- data/lib/iodine/pubsub.rb +55 -0
- data/lib/iodine/rack_utils.rb +43 -0
- data/lib/iodine/tls.rb +16 -0
- data/lib/iodine/version.rb +3 -0
- data/lib/iodine.rb +274 -0
- data/lib/rack/handler/iodine.rb +33 -0
- data/logo.png +0 -0
- metadata +284 -0
@@ -0,0 +1,71 @@
|
|
1
|
+
/*
|
2
|
+
Copyright: Boaz Segev, 2018
|
3
|
+
License: MIT
|
4
|
+
|
5
|
+
Feel free to copy, use and enjoy according to the license provided.
|
6
|
+
*/
|
7
|
+
#ifndef H_FIOBJ_MEM_H
|
8
|
+
|
9
|
+
/**
|
10
|
+
* This is a placeholder for facil.io memory allocator functions in fio.h.
|
11
|
+
*
|
12
|
+
* In cases where the FIOBJ library is extracted from facil.io, these functions
|
13
|
+
* will call the system's memory allocator (`malloc`, `free`, etc').
|
14
|
+
*/
|
15
|
+
#define H_FIOBJ_MEM_H
|
16
|
+
|
17
|
+
#include <stdlib.h>
|
18
|
+
|
19
|
+
/**
|
20
|
+
* Allocates memory using a per-CPU core block memory pool.
|
21
|
+
* Memory is zeroed out.
|
22
|
+
*
|
23
|
+
* Allocations above FIO_MEMORY_BLOCK_ALLOC_LIMIT (12,288 bytes when using 32Kb
|
24
|
+
* blocks) will be redirected to `mmap`, as if `fio_mmap` was called.
|
25
|
+
*/
|
26
|
+
void *fio_malloc(size_t size);
|
27
|
+
|
28
|
+
/**
|
29
|
+
* same as calling `fio_malloc(size_per_unit * unit_count)`;
|
30
|
+
*
|
31
|
+
* Allocations above FIO_MEMORY_BLOCK_ALLOC_LIMIT (12,288 bytes when using 32Kb
|
32
|
+
* blocks) will be redirected to `mmap`, as if `fio_mmap` was called.
|
33
|
+
*/
|
34
|
+
void *fio_calloc(size_t size_per_unit, size_t unit_count);
|
35
|
+
|
36
|
+
/** Frees memory that was allocated using this library. */
|
37
|
+
void fio_free(void *ptr);
|
38
|
+
|
39
|
+
/**
|
40
|
+
* Re-allocates memory. An attept to avoid copying the data is made only for big
|
41
|
+
* memory allocations (larger than FIO_MEMORY_BLOCK_ALLOC_LIMIT).
|
42
|
+
*/
|
43
|
+
void *fio_realloc(void *ptr, size_t new_size);
|
44
|
+
|
45
|
+
/**
|
46
|
+
* Re-allocates memory. An attept to avoid copying the data is made only for big
|
47
|
+
* memory allocations (larger than FIO_MEMORY_BLOCK_ALLOC_LIMIT).
|
48
|
+
*
|
49
|
+
* This variation is slightly faster as it might copy less data.
|
50
|
+
*/
|
51
|
+
void *fio_realloc2(void *ptr, size_t new_size, size_t copy_length);
|
52
|
+
|
53
|
+
/**
|
54
|
+
* Allocates memory directly using `mmap`, this is prefered for objects that
|
55
|
+
* both require almost a page of memory (or more) and expect a long lifetime.
|
56
|
+
*
|
57
|
+
* However, since this allocation will invoke the system call (`mmap`), it will
|
58
|
+
* be inherently slower.
|
59
|
+
*
|
60
|
+
* `fio_free` can be used for deallocating the memory.
|
61
|
+
*/
|
62
|
+
void *fio_mmap(size_t size);
|
63
|
+
|
64
|
+
#if FIO_OVERRIDE_MALLOC
|
65
|
+
#define malloc fio_malloc
|
66
|
+
#define free fio_free
|
67
|
+
#define realloc fio_realloc
|
68
|
+
#define calloc fio_calloc
|
69
|
+
#endif
|
70
|
+
|
71
|
+
#endif /* H_FIOBJ_MEM_H */
|
@@ -0,0 +1,317 @@
|
|
1
|
+
/*
|
2
|
+
Copyright: Boaz Segev, 2018-2019
|
3
|
+
License: MIT
|
4
|
+
*/
|
5
|
+
#define INCLUDE_MUSTACHE_IMPLEMENTATION 1
|
6
|
+
#include <mustache_parser.h>
|
7
|
+
|
8
|
+
#include <fiobj_ary.h>
|
9
|
+
#include <fiobj_hash.h>
|
10
|
+
#include <fiobj_mustache.h>
|
11
|
+
#include <fiobj_str.h>
|
12
|
+
|
13
|
+
#ifndef FIO_IGNORE_MACRO
|
14
|
+
/**
|
15
|
+
* This is used internally to ignore macros that shadow functions (avoiding
|
16
|
+
* named arguments when required).
|
17
|
+
*/
|
18
|
+
#define FIO_IGNORE_MACRO
|
19
|
+
#endif
|
20
|
+
|
21
|
+
/**
|
22
|
+
* Loads a mustache template, converting it into an opaque instruction array.
|
23
|
+
*
|
24
|
+
* Returns a pointer to the instruction array.
|
25
|
+
*
|
26
|
+
* The `folder` argument should contain the template's root folder which would
|
27
|
+
* also be used to search for any required partial templates.
|
28
|
+
*
|
29
|
+
* The `filename` argument should contain the template's file name.
|
30
|
+
*/
|
31
|
+
mustache_s *fiobj_mustache_load(fio_str_info_s filename) {
|
32
|
+
return mustache_load(.filename = filename.data, .filename_len = filename.len);
|
33
|
+
}
|
34
|
+
|
35
|
+
/**
|
36
|
+
* Loads a mustache template, converting it into an opaque instruction array.
|
37
|
+
*
|
38
|
+
* Returns a pointer to the instruction array.
|
39
|
+
*
|
40
|
+
* The `folder` argument should contain the template's root folder which would
|
41
|
+
* also be used to search for any required partial templates.
|
42
|
+
*
|
43
|
+
* The `filename` argument should contain the template's file name.
|
44
|
+
*/
|
45
|
+
mustache_s *fiobj_mustache_new FIO_IGNORE_MACRO(mustache_load_args_s args) {
|
46
|
+
return mustache_load FIO_IGNORE_MACRO(args);
|
47
|
+
}
|
48
|
+
|
49
|
+
/** Free the mustache template */
|
50
|
+
void fiobj_mustache_free(mustache_s *mustache) { mustache_free(mustache); }
|
51
|
+
|
52
|
+
/**
|
53
|
+
* Renders a template into an existing FIOBJ String (`dest`'s end), using the
|
54
|
+
* information in the `data` object.
|
55
|
+
*
|
56
|
+
* Returns FIOBJ_INVALID if an error occured and a FIOBJ String on success.
|
57
|
+
*/
|
58
|
+
FIOBJ fiobj_mustache_build2(FIOBJ dest, mustache_s *mustache, FIOBJ data) {
|
59
|
+
mustache_build(mustache, .udata1 = (void *)dest, .udata2 = (void *)data);
|
60
|
+
return dest;
|
61
|
+
}
|
62
|
+
|
63
|
+
/**
|
64
|
+
* Creates a FIOBJ String containing the rendered template using the information
|
65
|
+
* in the `data` object.
|
66
|
+
*
|
67
|
+
* Returns FIOBJ_INVALID if an error occured and a FIOBJ String on success.
|
68
|
+
*/
|
69
|
+
FIOBJ fiobj_mustache_build(mustache_s *mustache, FIOBJ data) {
|
70
|
+
if (!mustache)
|
71
|
+
return FIOBJ_INVALID;
|
72
|
+
return fiobj_mustache_build2(fiobj_str_buf(mustache->u.read_only.data_length),
|
73
|
+
mustache, data);
|
74
|
+
}
|
75
|
+
|
76
|
+
/* *****************************************************************************
|
77
|
+
Mustache Callbacks
|
78
|
+
***************************************************************************** */
|
79
|
+
|
80
|
+
static inline FIOBJ fiobj_mustache_find_obj_absolute(FIOBJ parent, FIOBJ key) {
|
81
|
+
if (!FIOBJ_TYPE_IS(parent, FIOBJ_T_HASH))
|
82
|
+
return FIOBJ_INVALID;
|
83
|
+
FIOBJ o = FIOBJ_INVALID;
|
84
|
+
o = fiobj_hash_get(parent, key);
|
85
|
+
return o;
|
86
|
+
}
|
87
|
+
|
88
|
+
static inline FIOBJ fiobj_mustache_find_obj_tree(mustache_section_s *section,
|
89
|
+
const char *name,
|
90
|
+
uint32_t name_len) {
|
91
|
+
FIOBJ key = fiobj_str_tmp();
|
92
|
+
fiobj_str_write(key, name, name_len);
|
93
|
+
do {
|
94
|
+
FIOBJ tmp = fiobj_mustache_find_obj_absolute((FIOBJ)section->udata2, key);
|
95
|
+
if (tmp != FIOBJ_INVALID) {
|
96
|
+
return tmp;
|
97
|
+
}
|
98
|
+
} while ((section = mustache_section_parent(section)));
|
99
|
+
return FIOBJ_INVALID;
|
100
|
+
}
|
101
|
+
|
102
|
+
static inline FIOBJ fiobj_mustache_find_obj(mustache_section_s *section,
|
103
|
+
const char *name,
|
104
|
+
uint32_t name_len) {
|
105
|
+
FIOBJ tmp = fiobj_mustache_find_obj_tree(section, name, name_len);
|
106
|
+
if (tmp != FIOBJ_INVALID)
|
107
|
+
return tmp;
|
108
|
+
/* interpolate sections... */
|
109
|
+
uint32_t dot = 0;
|
110
|
+
while (dot < name_len && name[dot] != '.')
|
111
|
+
++dot;
|
112
|
+
if (dot == name_len)
|
113
|
+
return FIOBJ_INVALID;
|
114
|
+
tmp = fiobj_mustache_find_obj_tree(section, name, dot);
|
115
|
+
if (!tmp) {
|
116
|
+
return FIOBJ_INVALID;
|
117
|
+
}
|
118
|
+
++dot;
|
119
|
+
for (;;) {
|
120
|
+
FIOBJ key = fiobj_str_tmp();
|
121
|
+
fiobj_str_write(key, name + dot, name_len - dot);
|
122
|
+
FIOBJ obj = fiobj_mustache_find_obj_absolute(tmp, key);
|
123
|
+
if (obj != FIOBJ_INVALID)
|
124
|
+
return obj;
|
125
|
+
name += dot;
|
126
|
+
name_len -= dot;
|
127
|
+
dot = 0;
|
128
|
+
while (dot < name_len && name[dot] != '.')
|
129
|
+
++dot;
|
130
|
+
if (dot == name_len) {
|
131
|
+
return FIOBJ_INVALID;
|
132
|
+
}
|
133
|
+
key = fiobj_str_tmp();
|
134
|
+
fiobj_str_write(key, name, dot);
|
135
|
+
tmp = fiobj_mustache_find_obj_absolute(tmp, key);
|
136
|
+
if (tmp == FIOBJ_INVALID)
|
137
|
+
return FIOBJ_INVALID;
|
138
|
+
++dot;
|
139
|
+
}
|
140
|
+
}
|
141
|
+
|
142
|
+
/**
|
143
|
+
* Called when an argument name was detected in the current section.
|
144
|
+
*
|
145
|
+
* A conforming implementation will search for the named argument both in the
|
146
|
+
* existing section and all of it's parents (walking backwards towards the root)
|
147
|
+
* until a value is detected.
|
148
|
+
*
|
149
|
+
* A missing value should be treated the same as an empty string.
|
150
|
+
*
|
151
|
+
* A conforming implementation will output the named argument's value (either
|
152
|
+
* HTML escaped or not, depending on the `escape` flag) as a string.
|
153
|
+
*/
|
154
|
+
static int mustache_on_arg(mustache_section_s *section, const char *name,
|
155
|
+
uint32_t name_len, unsigned char escape) {
|
156
|
+
FIOBJ o = fiobj_mustache_find_obj(section, name, name_len);
|
157
|
+
if (!o)
|
158
|
+
return 0;
|
159
|
+
fio_str_info_s i = fiobj_obj2cstr(o);
|
160
|
+
if (!i.len)
|
161
|
+
return 0;
|
162
|
+
return mustache_write_text(section, i.data, i.len, escape);
|
163
|
+
}
|
164
|
+
|
165
|
+
/**
|
166
|
+
* Called when simple template text (string) is detected.
|
167
|
+
*
|
168
|
+
* A conforming implementation will output data as a string (no escaping).
|
169
|
+
*/
|
170
|
+
static int mustache_on_text(mustache_section_s *section, const char *data,
|
171
|
+
uint32_t data_len) {
|
172
|
+
FIOBJ dest = (FIOBJ)section->udata1;
|
173
|
+
fiobj_str_write(dest, data, data_len);
|
174
|
+
return 0;
|
175
|
+
}
|
176
|
+
|
177
|
+
/**
|
178
|
+
* Called for nested sections, must return the number of objects in the new
|
179
|
+
* subsection (depending on the argument's name).
|
180
|
+
*
|
181
|
+
* Arrays should return the number of objects in the array.
|
182
|
+
*
|
183
|
+
* `true` values should return 1.
|
184
|
+
*
|
185
|
+
* `false` values should return 0.
|
186
|
+
*
|
187
|
+
* A return value of -1 will stop processing with an error.
|
188
|
+
*
|
189
|
+
* Please note, this will handle both normal and inverted sections.
|
190
|
+
*/
|
191
|
+
static int32_t mustache_on_section_test(mustache_section_s *section,
|
192
|
+
const char *name, uint32_t name_len,
|
193
|
+
uint8_t callable) {
|
194
|
+
FIOBJ o = fiobj_mustache_find_obj(section, name, name_len);
|
195
|
+
if (!o || FIOBJ_TYPE_IS(o, FIOBJ_T_FALSE))
|
196
|
+
return 0;
|
197
|
+
if (FIOBJ_TYPE_IS(o, FIOBJ_T_ARRAY))
|
198
|
+
return fiobj_ary_count(o);
|
199
|
+
return 1;
|
200
|
+
(void)callable; /* FIOBJ doesn't support lambdas */
|
201
|
+
}
|
202
|
+
|
203
|
+
/**
|
204
|
+
* Called when entering a nested section.
|
205
|
+
*
|
206
|
+
* `index` is a zero based index indicating the number of repetitions that
|
207
|
+
* occurred so far (same as the array index for arrays).
|
208
|
+
*
|
209
|
+
* A return value of -1 will stop processing with an error.
|
210
|
+
*
|
211
|
+
* Note: this is a good time to update the subsection's `udata` with the value
|
212
|
+
* of the array index. The `udata` will always contain the value or the parent's
|
213
|
+
* `udata`.
|
214
|
+
*/
|
215
|
+
static int mustache_on_section_start(mustache_section_s *section,
|
216
|
+
char const *name, uint32_t name_len,
|
217
|
+
uint32_t index) {
|
218
|
+
FIOBJ o = fiobj_mustache_find_obj(section, name, name_len);
|
219
|
+
if (!o)
|
220
|
+
return -1;
|
221
|
+
if (FIOBJ_TYPE_IS(o, FIOBJ_T_ARRAY))
|
222
|
+
section->udata2 = (void *)fiobj_ary_index(o, index);
|
223
|
+
else
|
224
|
+
section->udata2 = (void *)o;
|
225
|
+
return 0;
|
226
|
+
}
|
227
|
+
|
228
|
+
/**
|
229
|
+
* Called for cleanup in case of error.
|
230
|
+
*/
|
231
|
+
static void mustache_on_formatting_error(void *udata1, void *udata2) {
|
232
|
+
(void)udata1;
|
233
|
+
(void)udata2;
|
234
|
+
}
|
235
|
+
|
236
|
+
/* *****************************************************************************
|
237
|
+
Testing
|
238
|
+
***************************************************************************** */
|
239
|
+
|
240
|
+
#if DEBUG
|
241
|
+
static inline void mustache_save2file(char const *filename, char const *data,
|
242
|
+
size_t length) {
|
243
|
+
#ifdef __MINGW32__
|
244
|
+
int fd = _open(filename, _O_CREAT | _O_RDWR);
|
245
|
+
#else
|
246
|
+
int fd = open(filename, O_CREAT | O_RDWR, 0);
|
247
|
+
#endif
|
248
|
+
if (fd == -1) {
|
249
|
+
perror("Couldn't open / create file for template testing");
|
250
|
+
exit(-1);
|
251
|
+
}
|
252
|
+
#ifdef __MINGW32__
|
253
|
+
_chmod(filename, _S_IREAD | _S_IWRITE);
|
254
|
+
#else
|
255
|
+
fchmod(fd, 0777);
|
256
|
+
#endif
|
257
|
+
if (pwrite(fd, data, length, 0) != (ssize_t)length) {
|
258
|
+
perror("Mustache template write error");
|
259
|
+
exit(-1);
|
260
|
+
}
|
261
|
+
close(fd);
|
262
|
+
}
|
263
|
+
|
264
|
+
void fiobj_mustache_test(void) {
|
265
|
+
#define TEST_ASSERT(cond, ...) \
|
266
|
+
if (!(cond)) { \
|
267
|
+
fprintf(stderr, "* " __VA_ARGS__); \
|
268
|
+
fprintf(stderr, "\n !!! Testing failed !!!\n"); \
|
269
|
+
exit(-1); \
|
270
|
+
}
|
271
|
+
|
272
|
+
char const *template =
|
273
|
+
"{{=<< >>=}}* Users:\r\n<<#users>><<id>>. <<& name>> "
|
274
|
+
"(<<name>>)\r\n<</users>>\r\nNested: <<& nested.item >>.";
|
275
|
+
char const *template_name = "mustache_test_template.mustache";
|
276
|
+
fprintf(stderr, "mustache test saving template %s\n", template_name);
|
277
|
+
mustache_save2file(template_name, template, strlen(template));
|
278
|
+
mustache_s *m =
|
279
|
+
fiobj_mustache_load((fio_str_info_s){.data = (char *)template_name});
|
280
|
+
unlink(template_name);
|
281
|
+
TEST_ASSERT(m, "fiobj_mustache_load failed.\n");
|
282
|
+
FIOBJ data = fiobj_hash_new();
|
283
|
+
FIOBJ key = fiobj_str_new("users", 5);
|
284
|
+
FIOBJ ary = fiobj_ary_new2(4);
|
285
|
+
fiobj_hash_set(data, key, ary);
|
286
|
+
fiobj_free(key);
|
287
|
+
for (int i = 0; i < 4; ++i) {
|
288
|
+
FIOBJ id = fiobj_str_buf(4);
|
289
|
+
fiobj_str_write_i(id, i);
|
290
|
+
FIOBJ name = fiobj_str_buf(4);
|
291
|
+
fiobj_str_write(name, "User ", 5);
|
292
|
+
fiobj_str_write_i(name, i);
|
293
|
+
FIOBJ usr = fiobj_hash_new2(2);
|
294
|
+
key = fiobj_str_new("id", 2);
|
295
|
+
fiobj_hash_set(usr, key, id);
|
296
|
+
fiobj_free(key);
|
297
|
+
key = fiobj_str_new("name", 4);
|
298
|
+
fiobj_hash_set(usr, key, name);
|
299
|
+
fiobj_free(key);
|
300
|
+
fiobj_ary_push(ary, usr);
|
301
|
+
}
|
302
|
+
key = fiobj_str_new("nested", 6);
|
303
|
+
ary = fiobj_hash_new2(2);
|
304
|
+
fiobj_hash_set(data, key, ary);
|
305
|
+
fiobj_free(key);
|
306
|
+
key = fiobj_str_new("item", 4);
|
307
|
+
fiobj_hash_set(ary, key, fiobj_str_new("dot notation success", 20));
|
308
|
+
fiobj_free(key);
|
309
|
+
key = fiobj_mustache_build(m, data);
|
310
|
+
fiobj_free(data);
|
311
|
+
TEST_ASSERT(key, "fiobj_mustache_build failed!\n");
|
312
|
+
fprintf(stderr, "%s\n", fiobj_obj2cstr(key).data);
|
313
|
+
fiobj_free(key);
|
314
|
+
fiobj_mustache_free(m);
|
315
|
+
}
|
316
|
+
|
317
|
+
#endif
|
@@ -0,0 +1,62 @@
|
|
1
|
+
/*
|
2
|
+
Copyright: Boaz Segev, 2018-2019
|
3
|
+
License: MIT
|
4
|
+
*/
|
5
|
+
#ifndef H_FIOBJ_MUSTACHE_H
|
6
|
+
#define H_FIOBJ_MUSTACHE_H
|
7
|
+
|
8
|
+
#include <fiobject.h>
|
9
|
+
|
10
|
+
#include <mustache_parser.h>
|
11
|
+
|
12
|
+
/**
|
13
|
+
* Loads a mustache template, converting it into an opaque instruction array.
|
14
|
+
*
|
15
|
+
* Returns a pointer to the instruction array or NULL (on error).
|
16
|
+
*
|
17
|
+
* The `filename` argument should contain the template's file name.
|
18
|
+
*/
|
19
|
+
mustache_s *fiobj_mustache_load(fio_str_info_s filename);
|
20
|
+
|
21
|
+
/**
|
22
|
+
* Loads a mustache template, either from memory of a file, converting it into
|
23
|
+
* an opaque instruction array.
|
24
|
+
*
|
25
|
+
* Returns a pointer to the instruction array or NULL (on error).
|
26
|
+
*
|
27
|
+
* Accepts any of the following named arguments:
|
28
|
+
* * `char const *filename` - The root template's file name.
|
29
|
+
* * `size_t filename_len` - The file name's length.
|
30
|
+
* * `char const *data` - If set, will be used as the file's contents.
|
31
|
+
* * `size_t data_len` - If set, `data` will be used as the file's contents.
|
32
|
+
* * `mustache_error_en *err` - A container for any template load errors (see
|
33
|
+
* mustache_parser.h).
|
34
|
+
*/
|
35
|
+
mustache_s *fiobj_mustache_new(mustache_load_args_s args);
|
36
|
+
#define fiobj_mustache_new(...) \
|
37
|
+
fiobj_mustache_new((mustache_load_args_s){__VA_ARGS__})
|
38
|
+
|
39
|
+
/** Free the mustache template */
|
40
|
+
void fiobj_mustache_free(mustache_s *mustache);
|
41
|
+
|
42
|
+
/**
|
43
|
+
* Creates a FIOBJ String containing the rendered template using the information
|
44
|
+
* in the `data` object.
|
45
|
+
*
|
46
|
+
* Returns FIOBJ_INVALID if an error occurred and a FIOBJ String on success.
|
47
|
+
*/
|
48
|
+
FIOBJ fiobj_mustache_build(mustache_s *mustache, FIOBJ data);
|
49
|
+
|
50
|
+
/**
|
51
|
+
* Renders a template into an existing FIOBJ String (`dest`'s end), using the
|
52
|
+
* information in the `data` object.
|
53
|
+
*
|
54
|
+
* Returns FIOBJ_INVALID if an error occurred and a FIOBJ String on success.
|
55
|
+
*/
|
56
|
+
FIOBJ fiobj_mustache_build2(FIOBJ dest, mustache_s *mustache, FIOBJ data);
|
57
|
+
|
58
|
+
#if DEBUG
|
59
|
+
void fiobj_mustache_test(void);
|
60
|
+
#endif
|
61
|
+
|
62
|
+
#endif /* H_FIOBJ_MUSTACHE_H */
|