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