]> git.lizzy.rs Git - protogen.git/blob - typegen.lua
Initial implementation
[protogen.git] / typegen.lua
1 #! /usr/bin/env lua
2 require "luax"
3
4 local h   = io.open("types.h",   "w")
5 local c   = io.open("types.c",   "w")
6 local def = io.open("types.def", "r")
7
8 local function emit_h(str)
9         h:write(str)
10 end
11
12 local function emit_c(str)
13         c:write(str)
14 end
15
16 local function emit(fun, code)
17         emit_h(fun .. ";\n")
18         emit_c(fun ..  "\n" .. code)
19 end
20
21 -- fn prefixes
22 local export_prefix = ""
23 local local_prefix = "__attribute__((unused)) static inline "
24
25 -- head
26
27 local disclaimer = [[
28 /*
29         This file was automatically generated by Dragontype.
30         DO NOT EDIT it manually. Instead, edit types.def and re-run dragontype typegen.
31 */
32
33 ]]
34
35 emit_h(disclaimer)
36 emit_h([[
37 #ifndef _DRAGONTYPE_TYPES_H_
38 #define _DRAGONTYPE_TYPES_H_
39
40 #ifdef USE_DRAGONNET
41 #include <dragonnet/peer.h>
42 #endif
43
44 #include <stdbool.h>
45 #include <stddef.h>
46 #include <stdint.h>
47
48 typedef char *String;
49
50 typedef struct {
51         size_t siz;
52         unsigned char *data;
53 } Blob;
54
55 ]]
56 )
57
58 emit_c(disclaimer)
59 emit_c([[
60 #ifdef USE_DRAGONNET
61 #include <dragonnet/send.h>
62 #include <dragonnet/recv.h>
63 #endif
64
65 #include <endian.h/endian.h>
66 #include <stdio.h>
67 #include <stdlib.h>
68 #include <stdlib.h>
69 #include <string.h>
70 #include <zlib.h>
71
72 #define htobe8(x) (x)
73 #define be8toh(x) (x)
74
75 #include "types.h"
76
77 ]] .. local_prefix ..  [[void raw_write(Blob *buffer, const void *data, size_t len)
78 {
79         buffer->data = realloc(buffer->data, len + buffer->siz);
80         memcpy(&buffer->data[buffer->siz], data, len);
81         buffer->siz += len;
82 }
83
84 ]] .. local_prefix ..  [[bool raw_read(Blob *buffer, void *data, size_t len)
85 {
86         if (buffer->siz < len) {
87                 fprintf(stderr, "warning: buffer exhausted (requested bytes: %lu, remaining bytes: %lu)\n", len, buffer->siz);
88                 return false;
89         }
90
91         memcpy(data, buffer->data, len);
92         buffer->data += len;
93         buffer->siz -= len;
94         return true;
95 }
96
97 ]]
98 )
99
100 -- existing types
101 local existing_types = {}
102 local has_deallocator = {}
103
104 -- vector components
105
106 local base_vector_components = {"x", "y", "z", "w"}
107 local vector_components = {}
108
109 for i = 2, 4 do
110         local components = {}
111
112         for j = 1, i do
113                 table.insert(components, base_vector_components[j])
114         end
115
116         vector_components[i] = components
117 end
118
119 -- numeric types
120
121 local function emit_vector(type, l)
122         local name = "v" .. l .. type
123         local box = "aabb" .. l .. type
124
125         existing_types[name] = true
126         has_deallocator[name] = false
127
128         local typedef, equals, add, clamp, mix, write, read, send, recv =
129                    "",     "",  "",    "",  "",    "",   "",   "",   ""
130
131         typedef = typedef .. "\t" .. type .. " "
132         equals  = equals  .. "\treturn "
133         add     = add     .. "\treturn (" .. name .. ") {"
134         clamp   = clamp   .. "\treturn (" .. name .. ") {"
135         mix     = mix     .. "\treturn (" .. name .. ") {"
136
137         for i, c in ipairs(vector_components[l]) do
138                 local last = i == l
139
140                 typedef = typedef
141                         .. c ..
142                         (last
143                                 and ";\n"
144                                 or ", "
145                         )
146
147                 equals = equals
148                         .. "a." .. c .. " == "
149                         .. "b." .. c ..
150                         (last
151                                 and ";\n"
152                                 or " && "
153                         )
154
155                 add = add
156                         .. "a." .. c .. " + "
157                         .. "b." .. c ..
158                         (last
159                                 and "};\n"
160                                 or ", "
161                         )
162
163                 clamp = clamp
164                         .. type .. "_clamp("
165                         .. "val." .. c .. ", "
166                         .. "min." .. c .. ", "
167                         .. "max." .. c .. ")" ..
168                         (last
169                                 and "};\n"
170                                 or ", "
171                         )
172
173                 mix = mix
174                         .. type .. "_mix("
175                         .. "a." .. c .. ", "
176                         .. "b." .. c .. ", "
177                         .. "f" .. ")" ..
178                         (last
179                                 and "};\n"
180                                 or ", "
181                         )
182
183                 write = write
184                         .. "\t" .. type .. "_write(buffer, &val->" .. c .. ");\n"
185
186                 read = read
187                         .. "\tif (! " .. type .. "_read(buffer, &val->" .. c .. "))\n\t\treturn false;\n"
188
189                 send = send
190                         .. "\tif (! " .. type .. "_send(peer, " .. (last and "submit" or "false") .. ", &val->" .. c .. "))\n\t\treturn false;\n"
191
192                 recv = recv
193                         .. "\tif (! " .. type .. "_recv(peer, &val->" .. c .. "))\n\t\treturn false;\n"
194         end
195
196         emit_h("typedef struct {\n" .. typedef ..  "} " .. name .. ";\n")
197
198         emit(export_prefix .. "bool " .. name .. "_equals(" .. name .. " a, " .. name .. " b)", "{\n" .. equals .. "}\n\n")
199         emit(export_prefix .. name .. " " .. name .. "_add(" .. name .. " a, " .. name .. " b)", "{\n" .. add .. "}\n\n")
200         emit(export_prefix .. name .. " " .. name .. "_clamp(" .. name .. " val, " .. name .. " min, " .. name .. " max)", "{\n" .. clamp .. "}\n\n")
201
202         if type:sub(1, 1) == "f" then
203                 emit(export_prefix .. name .. " " .. name .. "_mix(" .. name .. " a, " .. name .. " b, " .. type .. " f)", "{\n" .. mix .. "}\n\n")
204         end
205
206         emit(export_prefix .. "void " .. name .. "_write(Blob *buffer, " .. name .. " *val)", "{\n" .. write .. "}\n\n")
207         emit(export_prefix .. "bool " .. name .. "_read(Blob *buffer, " .. name .. " *val)", "{\n" .. read .. "\treturn true;\n}\n\n")
208
209         emit_c("#ifdef USE_DRAGONNET\n")
210         emit_c(local_prefix .. "bool " .. name .. "_send(DragonnetPeer *peer, bool submit, " .. name .. " *val)\n{\n" .. send .. "\treturn true;\n}\n\n")
211         emit_c(local_prefix .. "bool " .. name .. "_recv(DragonnetPeer *peer, " .. name .. " *val)\n{\n" .. recv .. "\treturn true;\n}\n")
212         emit_c("#endif\n\n")
213
214         emit_h("\n")
215
216         emit_h("typedef struct {\n\t" .. name .. " min, max;\n} " .. box .. ";\n")
217
218         emit(export_prefix .. "void " .. box .. "_write(Blob *buffer, " .. box .. " *val)", "{\n\t" .. name .. "_write(buffer, &val->min);\n\t" .. name .. "_write(buffer, &val->max);\n}\n\n")
219         emit(export_prefix .. "bool " .. box .. "_read(Blob *buffer, " .. box .. " *val)", "{\n\tif (! " .. name .. "_read(buffer, &val->min))\n\t\treturn false;\n\tif (! " .. name .. "_read(buffer, &val->max))\n\t\treturn false;\n\treturn true;\n}\n\n")
220
221         emit_c("#ifdef USE_DRAGONNET\n")
222         emit_c(local_prefix .. "bool " .. box .. "_send(DragonnetPeer *peer, bool submit, " .. box .. " *val)\n{\n\tif (! " .. name .. "_send(peer, false, &val->min))\n\t\treturn false;\n\tif (! " .. name .. "_send(peer, submit, &val->max))\n\t\treturn false;\n\treturn true;\n}\n\n")
223         emit_c(local_prefix .. "bool " .. box .. "_recv(DragonnetPeer *peer, " .. box .. " *val)\n{\n\tif (! " .. name .. "_recv(peer, &val->min))\n\t\treturn false;\n\t if (! " .. name .. "_recv(peer, &val->max))\n\t\treturn false;\n\treturn true;\n}\n")
224         emit_c("#endif\n\n")
225
226         emit_h("\n")
227 end
228
229 local function emit_numeric(class, bits, alias)
230         local name = class .. bits
231
232         existing_types[name] = true
233         has_deallocator[name] = false
234
235         emit_h("typedef " .. alias .. " " .. name .. ";\n")
236
237         emit(export_prefix .. name .. " " .. name .. "_min(" .. name .. " a, " .. name .. " b)", "{\n\treturn a < b ? a : b;\n}\n\n")
238         emit(export_prefix .. name .. " " .. name .. "_max(" .. name .. " a, " .. name .. " b)", "{\n\treturn a > b ? a : b;\n}\n\n")
239         emit(export_prefix .. name .. " " .. name .. "_clamp(" .. name .. " val, " .. name .. " min, " .. name .. " max)", "{\n\treturn val < min ? min : val > max ? max : val;\n}\n\n")
240
241         if class == "f" then
242                 emit(export_prefix .. name .. " " .. name .. "_mix(" .. name .. " a, " .. name .. " b, " .. name .. " f)", "{\n\treturn (1.0 - f) * a + b * f;\n}\n\n")
243         end
244
245         emit(export_prefix .. "void " .. name .. "_write(Blob *buffer, " .. name .. " *val)", "{\n" .. (class == "u"
246                 and "\t" .. name .. " be = htobe" .. bits .. "(*val);\n\traw_write(buffer, &be, sizeof be);\n"
247                 or  "\tu" .. bits .. "_write(buffer, (u" .. bits .. " *) val);\n"
248         ) .. "}\n\n")
249         emit(export_prefix .. "bool " .. name .. "_read(Blob *buffer, " .. name .. " *val)", "{\n" .. (class == "u"
250                 and "\t" .. name .. " be;\n\tif (! raw_read(buffer, &be, sizeof be))\n\t\treturn false;\n\t*val = be" .. bits .. "toh(be);\n\treturn true;\n"
251                 or  "\treturn u" .. bits .. "_read(buffer, (u" .. bits .. " *) val);\n"
252         ) .. "}\n\n")
253
254         emit_c("#ifdef USE_DRAGONNET\n")
255         emit_c(local_prefix .. "bool " .. name .. "_send(DragonnetPeer *peer, bool submit, " .. name .. " *val)\n{\n" .. (class == "u"
256                 and "\t" .. name .. " be = htobe" .. bits .. "(*val);\n\treturn dragonnet_send_raw(peer, submit, &be, sizeof be);\n"
257                 or  "\treturn u" .. bits .. "_send(peer, submit, (u" .. bits .. " *) val);\n"
258         ) .. "}\n\n")
259         emit_c(local_prefix .. "bool " .. name .. "_recv(DragonnetPeer *peer, " .. name .. " *val)\n{\n" .. (class == "u"
260                 and "\t" .. name .. " be;\n\tif (! dragonnet_recv_raw(peer, &be, sizeof be))\n\t\treturn false;\n\t*val = be" .. bits .. "toh(be);\n\treturn true;\n"
261                 or  "\treturn u" .. bits .. "_recv(peer, (u" .. bits .. " *) val);\n"
262         ) .. "}\n")
263         emit_c("#endif\n\n")
264
265         emit_h("\n")
266
267         for i = 2, 4 do
268                 emit_vector(name, i)
269         end
270 end
271
272 for i = 0, 3 do
273         local bytes = math.floor(2 ^ i)
274         local bits = 8 * bytes
275
276         emit_numeric("u", bits, "uint" .. bits .. "_t")
277         emit_numeric("s", bits,  "int" .. bits .. "_t")
278
279         if i >= 2 then
280                 emit_numeric("f", bits, ({"float", "double"})[i - 1])
281         end
282 end
283
284 -- string
285
286 existing_types.String = true
287 has_deallocator.String = true
288
289 emit(
290 export_prefix .. "void String_free(String *val)", [[
291 {
292         if (*val)
293                 free(*val);
294 }
295
296 ]]
297 )
298
299 emit(
300 export_prefix .. "void String_write(Blob *buffer, String *val)", [[
301 {
302         raw_write(buffer, *val, strlen(*val) + 1);
303 }
304
305 ]]
306 )
307
308 emit(
309 export_prefix .. "bool String_read(Blob *buffer, String *val)", [[
310 {
311         String v = malloc(1 + (1 << 16));
312
313         char c;
314         for (u16 i = 0;; i++) {
315                 if (! raw_read(buffer, &c, 1)) {
316                         free(v);
317                         return false;
318                 }
319
320                 v[i] = c;
321                 if (c == '\0')
322                         break;
323         }
324
325         *val = realloc(v, strlen(v) + 1);
326
327         return true;
328 }
329
330 ]]
331 )
332
333 emit_c(
334 [[
335 #ifdef USE_DRAGONNET
336 ]] .. local_prefix .. [[bool String_send(DragonnetPeer *peer, bool submit, String *val)
337 {
338         return dragonnet_send_raw(peer, submit, *val, strlen(*val) + 1);
339 }
340
341 ]] .. local_prefix .. [[bool String_recv(DragonnetPeer *peer, String *val)
342 {
343         String v = malloc(1 + (1 << 16));
344
345         char c;
346         for (u16 i = 0;; i++) {
347                 if (! dragonnet_recv_raw(peer, &c, 1)) {
348                         free(v);
349                         return false;
350                 }
351
352                 v[i] = c;
353                 if (c == '\0')
354                         break;
355         }
356
357         *val = realloc(v, strlen(v) + 1);
358
359         return true;
360 }
361 #endif
362
363 ]]
364 )
365
366 emit_h("\n")
367
368 -- blob
369
370 existing_types.Blob = true
371 has_deallocator.Blob = true
372
373 emit(
374 export_prefix .. "void Blob_compress(Blob *buffer, Blob *val)", [[
375 {
376         buffer->siz = 8 + 2 + val->siz;
377         buffer->data = malloc(buffer->siz);
378
379         *(u64 *) buffer->data = val->siz;
380
381         z_stream s;
382         s.zalloc = Z_NULL;
383         s.zfree = Z_NULL;
384         s.opaque = Z_NULL;
385
386         s.avail_in = val->siz;
387         s.next_in = (Bytef *) val->data;
388         s.avail_out = buffer->siz - 8 + 1;
389         s.next_out = (Bytef *) buffer->data + 8;
390
391         deflateInit(&s, Z_BEST_COMPRESSION);
392         deflate(&s, Z_FINISH);
393         deflateEnd(&s);
394
395         buffer->siz = s.total_out + 8;
396 }
397
398 ]]
399 )
400
401 emit(
402 export_prefix .. "void Blob_decompress(Blob *buffer, Blob *val)", [[
403 {
404         buffer->siz = *(u64 *) val->data;
405         buffer->data = malloc(buffer->siz);
406
407         z_stream s;
408         s.zalloc = Z_NULL;
409         s.zfree = Z_NULL;
410         s.opaque = Z_NULL;
411
412         s.avail_in = val->siz - 8;
413         s.next_in = val->data + 8;
414         s.avail_out = buffer->siz;
415         s.next_out = (Bytef *) buffer->data;
416
417         inflateInit(&s);
418         inflate(&s, Z_NO_FLUSH);
419         inflateEnd(&s);
420
421         buffer->siz = s.total_out;
422 }
423
424 ]]
425 )
426
427 emit(
428 export_prefix .. "void Blob_shrink(Blob *val)", [[
429 {
430         val->data = realloc(val->data, val->siz);
431 }
432
433 ]]
434 )
435
436 emit(
437 export_prefix .. "void Blob_free(Blob *val)", [[
438 {
439         if (val->data)
440                 free(val->data);
441 }
442
443 ]]
444 )
445
446 emit(
447 export_prefix .. "void Blob_write(Blob *buffer, Blob *val)", [[
448 {
449         u64_write(buffer, &val->siz);
450         raw_write(buffer, val->data, val->siz);
451 }
452
453 ]]
454 )
455
456 emit(
457 export_prefix .. "bool Blob_read(Blob *buffer, Blob *val)", [[
458 {
459         if (! u64_read(buffer, &val->siz))
460                 return false;
461
462         if (! raw_read(buffer, val->data = malloc(val->siz), val->siz)) {
463                 free(val->data);
464                 val->data = NULL;
465                 return false;
466         }
467
468         return true;
469 }
470
471 ]]
472 )
473
474 emit_c(
475 [[
476 #ifdef USE_DRAGONNET
477 ]] .. local_prefix .. [[bool Blob_send(DragonnetPeer *peer, bool submit, Blob *val)
478 {
479         if (! u64_send(peer, false, &val->siz))
480                 return false;
481         return dragonnet_send_raw(peer, submit, val->data, val->siz);
482 }
483
484 ]] .. local_prefix .. [[bool Blob_recv(DragonnetPeer *peer, Blob *val)
485 {
486         if (! u64_recv(peer, &val->siz))
487                 return false;
488
489         if (! dragonnet_recv_raw(peer, val->data = malloc(val->siz), val->siz)) {
490                 free(val->data);
491                 val->data = NULL;
492                 return false;
493         }
494
495         return true;
496 }
497 #endif
498
499 ]]
500 )
501
502 emit_h("\n")
503
504
505 emit_c(
506 [[
507 ]] .. local_prefix .. [[void raw_write_compressed(Blob *buffer, void *val, void (*val_write)(Blob *, void *))
508 {
509         Blob compressed, raw = {0};
510         val_write(&raw, val);
511         Blob_compress(&compressed, &raw);
512         Blob_write(buffer, &compressed);
513
514         Blob_free(&compressed);
515         Blob_free(&raw);
516 }
517
518 ]] .. local_prefix .. [[bool raw_read_compressed(Blob *buffer, void *val, bool (*val_read)(Blob *, void *))
519 {
520         Blob compressed, raw = {0};
521         bool success = Blob_read(buffer, &compressed);
522
523         if (success) {
524                 Blob_decompress(&raw, &compressed);
525                 Blob raw_buffer = raw;
526                 success = success && val_read(&raw_buffer, val);
527         }
528
529         Blob_free(&compressed);
530         Blob_free(&raw);
531
532         return success;
533 }
534
535 #ifdef USE_DRAGONNET
536 ]] .. local_prefix .. [[bool raw_send_compressed(DragonnetPeer *peer, bool submit, void *val, void (*val_write)(Blob *, void *))
537 {
538         Blob compressed, raw = {0};
539         val_write(&raw, val);
540         Blob_compress(&compressed, &raw);
541         bool success = Blob_send(peer, submit, &compressed);
542
543         Blob_free(&compressed);
544         Blob_free(&raw);
545
546         return success;
547 }
548
549 ]] .. local_prefix .. [[bool raw_recv_compressed(DragonnetPeer *peer, void *val, bool (*val_read)(Blob *, void *))
550 {
551         Blob compressed, raw = {0};
552         bool success = Blob_recv(peer, &compressed);
553
554         if (success) {
555                 Blob_decompress(&raw, &compressed);
556                 Blob raw_buffer = raw;
557                 success = success && val_read(&raw_buffer, val);
558         }
559
560         Blob_free(&compressed);
561         Blob_free(&raw);
562
563         return success;
564 }
565 #endif
566
567 ]]
568 )
569
570 local custom_types = {}
571 local current_type
572
573 local function consume_name(name)
574         if current_type then
575                 table.insert(custom_types, current_type)
576         end
577
578         if name == "" then
579                 current_type = nil
580         else
581                 current_type = {components = {}, component_names = {}}
582
583                 current_type.flags = name:split(" ")
584                 current_type.name = table.remove(current_type.flags, #current_type.flags)
585
586                 if existing_types[current_type.name] then
587                         error("redeclaration of type " .. current_type.name)
588                 end
589
590                 existing_types[current_type.name] = true
591                 has_deallocator[current_type.name] = false
592         end
593 end
594
595 local function consume_comp(comp)
596         if not current_type then
597                 error("component without a type: " .. comp)
598         end
599
600         local component = {}
601
602         component.flags = comp:split(" ")
603         component.name = table.remove(component.flags, #component.flags)
604         component.type = table.remove(component.flags, #component.flags)
605
606         component.full_name = current_type.name .. "." .. component.name
607
608         local base_type = ""
609         local met_brace = false
610         local brace_level = 0
611
612         for i = 1, #component.type do
613                 local c = component.type:sub(i, i)
614                 local append = false
615
616                 if c == "[" then
617                         if not met_brace then
618                                 component.array = {}
619                         end
620
621                         met_brace = true
622                         brace_level = brace_level + 1
623
624                         if brace_level == 1 then
625                                 table.insert(component.array, "")
626                         else
627                                 append = true
628                         end
629                 elseif c == "]" then
630                         brace_level = brace_level - 1
631
632                         if brace_level < 0 then
633                                 error("missing [ in " .. component.full_name)
634                         elseif brace_level > 0 then
635                                 append = true
636                         end
637                 elseif not met_brace then
638                         base_type = base_type .. c
639                 elseif brace_level == 1 then
640                         append = true
641                 elseif brace_level == 0 then
642                         error("invalid character " .. c .. " outside of braces in " .. component.full_name)
643                 end
644
645                 if append then
646                         component.array[#component.array] = component.array[#component.array] .. c
647                 end
648         end
649
650         component.type = base_type
651
652         if brace_level > 0 then
653                 error("missing ] in " .. component.full_name)
654         end
655
656         if not existing_types[component.type] then
657                 error("type " .. component.type .. " of " .. component.full_name .. " does not exist ")
658         end
659
660         has_deallocator[current_type.name] = has_deallocator[current_type.name] or has_deallocator[component.type]
661
662         if current_type.component_names[component.name] then
663                 error("component " .. component.full_name .. " redeclared")
664         end
665
666         current_type.component_names[component.name] = true
667
668         table.insert(current_type.components, component)
669 end
670
671 if def then
672         for l in def:lines() do
673                 local f = l:sub(1, 1)
674
675                 if f == "\t" then
676                         consume_comp(l:sub(2, #l))
677                 elseif f == "#" then
678                         emit_h(l .. "\n\n")
679                 elseif f ~= ";" then
680                         consume_name(l)
681                 end
682         end
683 end
684
685 consume_name("")
686
687 local dragonnet_types_h = ""
688 local dragonnet_types_c = ""
689
690 for _, t in ipairs(custom_types) do
691         local pkt
692
693         for _, f in pairs(t.flags) do
694                 if f == "pkt" then
695                         pkt = true
696                 else
697                         error("invalid flag " .. f .. " for " .. t.name)
698                 end
699         end
700
701         local typedef, free, write, read, send, recv =
702                    "",   "",    "",   "",   "",   ""
703
704         for ic, c in ipairs(t.components) do
705                 typedef = typedef
706                         .. "\t" .. c.type .. " " .. c.name
707
708                 if c.array then
709                         typedef = typedef
710                                 .. "[" .. table.concat(c.array, "][") .. "]"
711                 end
712
713                 typedef = typedef
714                         .. ";\n"
715
716                 local compressed = false
717
718                 for _, f in pairs(c.flags) do
719                         if f == "compressed" then
720                                 compressed = true
721                         else
722                                 error("invalid flag " .. f .. " for " .. c.full_name)
723                         end
724                 end
725
726                 local indent = "\t"
727                 local loop = ""
728                 local index = ""
729                 local array_submit = ""
730
731                 if c.array then
732                         for ia, a in ipairs(c.array) do
733                                 local it = "i" .. ia
734
735                                 loop = loop .. indent .. "for (int " .. it .. " = 0; " .. it .. " < " .. a .. "; " .. it .. "++)\n"
736                                 indent = indent .. "\t"
737
738                                 index = index .. "[" .. it .. "]"
739
740                                 array_submit = array_submit .. " && " .. it .. " == " .. a
741                         end
742                 end
743
744                 local addr = "&val->" .. c.name .. index
745
746                 if has_deallocator[c.type] then
747                         free = free
748                                 .. loop .. indent .. c.type .. "_free(" .. addr .. ");\n"
749                 end
750
751                 write = write
752                         .. loop .. indent .. (compressed
753                                 and "raw_write_compressed(buffer, " .. addr .. ", (void *) &" .. c.type .. "_write);\n"
754                                 or      c.type .. "_write(buffer, " .. addr .. ");\n"
755                         )
756
757                 read = read
758                         .. loop .. indent .. "if (! " .. (compressed
759                                 and "raw_read_compressed(buffer, " .. addr .. ", (void *) &" .. c.type .. "_read)"
760                                 or      c.type .. "_read(buffer, " .. addr .. ")"
761                         ) .. ")\n" .. indent .. "\treturn false;\n"
762
763                 local submit = ic == #t.components and "submit" .. array_submit or "false"
764                 send = send
765                         .. loop .. indent .. "if (! " .. (compressed
766                                 and "raw_send_compressed(peer, " .. submit .. ", " .. addr .. ", (void *) &" .. c.type .. "_write)"
767                                 or      c.type .. "_send(peer, " .. submit .. ", " .. addr .. ")"
768                         ) .. ")\n" .. indent .. "\treturn false;\n"
769
770                 recv = recv
771                         .. loop .. indent .. "if (! " .. (compressed
772                                 and "raw_recv_compressed(peer, " .. addr .. ", (void *) &" .. c.type .. "_read)"
773                                 or      c.type .. "_recv(peer, " .. addr .. ")"
774                         ) .. ")\n" .. indent .. "\treturn false;\n"
775         end
776
777         emit_h("typedef struct {\n" .. typedef .. "} " .. t.name .. ";\n")
778
779         if has_deallocator[t.name] then
780                 emit(export_prefix .. "void " .. t.name .. "_free(" .. t.name .. " *val)", "{\n" .. free .. "}\n\n")
781         end
782
783         emit(export_prefix .. "void " .. t.name .. "_write(Blob *buffer, " .. t.name .. " *val)", "{\n" .. write .. "}\n\n")
784         emit(export_prefix .. "bool " .. t.name .. "_read(Blob *buffer, " .. t.name .. " *val)", "{\n" .. read .. "\treturn true;\n}\n\n")
785
786         if pkt then
787                 emit_h("#ifdef USE_DRAGONNET\n")
788         end
789
790         emit_c("#ifdef USE_DRAGONNET\n")
791
792         emit_c(local_prefix .. "bool " .. t.name .. "_send(DragonnetPeer *peer, bool submit, " .. t.name .. " *val)\n{\n" .. send .. "\treturn true;\n}\n\n")
793         emit_c(local_prefix .. "bool " .. t.name .. "_recv(DragonnetPeer *peer, " .. t.name .. " *val)\n{\n" .. recv .. "\treturn true;\n}\n")
794
795         if pkt then
796                 emit_c("\n")
797                 emit_c("static DragonnetTypeId " .. t.name .. "_type_id = DRAGONNET_TYPE_" .. t.name .. ";\n")
798
799                 emit("bool dragonnet_peer_send_" .. t.name .. "(DragonnetPeer *peer, " .. t.name .. " *val)", "{\n\tpthread_mutex_lock(&peer->mtx);\n\tif (! u16_send(peer, false, &" .. t.name .. "_type_id))\n\t\treturn false;\n\tif (! " .. t.name .. "_send(peer, true, val))\n\t\treturn false;\n\treturn true;\n}\n")
800                 emit_h("#endif\n")
801
802                 dragonnet_types_h = dragonnet_types_h
803                         .. "\tDRAGONNET_TYPE_" .. t.name .. ",\n"
804
805                 dragonnet_types_c = dragonnet_types_c
806                         .. "\t{\n\t\t.siz = sizeof(" .. t.name .. "),\n\t\t.deserialize = (void *) &" .. t.name .. "_recv,\n\t\t.free = " .. (has_deallocator[t.name] and "(void *) &" .. t.name .. "_free" or "NULL") .. ",\n\t},\n"
807         end
808
809         emit_c("#endif\n\n")
810
811         emit_h("\n")
812 end
813
814 emit_h("#ifdef USE_DRAGONNET\n")
815 emit_h("typedef enum {\n" .. dragonnet_types_h .. "\tDRAGONNET_NUM_TYPES\n} DragonnetTypeNum;\n")
816 emit_h("#endif\n\n")
817
818 emit_c("#ifdef USE_DRAGONNET\n")
819 emit_c("DragonnetTypeId dragonnet_num_types = DRAGONNET_NUM_TYPES;\nDragonnetType dragonnet_types[] = {\n" .. dragonnet_types_c .. "};\n")
820 emit_c("#endif\n")
821
822 emit_h("#endif\n")
823
824 h:close()
825 c:close()
826 def:close()