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