4 local h = io.open("types.h", "w")
5 local c = io.open("types.c", "w")
6 local def = io.open(arg[1] or "types.def", "r")
8 local function emit_h(str)
12 local function emit_c(str)
16 local function emit(fun, code)
18 emit_c(fun .. "\n" .. code)
22 local struct_prefix = "__attribute__((packed)) "
23 local export_prefix = ""
24 local local_prefix = "__attribute__((unused)) static inline "
30 This file was automatically generated by Protogen.
31 DO NOT EDIT it manually. Instead, edit types.def and re-run protogen.
38 #ifndef _PROTOGEN_TYPES_H_
39 #define _PROTOGEN_TYPES_H_
42 #include <dragonnet/peer.h>
54 } ]] .. struct_prefix .. [[Blob;
62 #include <dragonnet/send.h>
63 #include <dragonnet/recv.h>
66 #include <endian.h/endian.h>
78 ]] .. local_prefix .. [[void raw_write(Blob *buffer, const void *data, size_t len)
80 buffer->data = realloc(buffer->data, len + buffer->siz);
81 memcpy(&buffer->data[buffer->siz], data, len);
85 ]] .. local_prefix .. [[bool raw_read(Blob *buffer, void *data, size_t len)
90 if (buffer->siz < len) {
91 fprintf(stderr, "[warning] buffer exhausted (requested bytes: %lu, remaining bytes: %lu)\n", len, buffer->siz);
95 memcpy(data, buffer->data, len);
105 local existing_types = {}
106 local has_deallocator = {}
110 local base_vector_components = {"x", "y", "z", "w"}
111 local vector_components = {}
114 local components = {}
117 table.insert(components, base_vector_components[j])
120 vector_components[i] = components
125 local numeric_types = {}
127 local function emit_vector(type, l)
128 local name = "v" .. l .. type
129 local box = "aabb" .. l .. type
131 existing_types[name] = true
132 has_deallocator[name] = false
134 existing_types[box] = true
135 has_deallocator[box] = false
137 local typedef, equals, add, sub, clamp, cmp, scale, mix, write, read, send, recv =
138 "", "", "", "", "", "", "", "", "", "", "", ""
140 for i, c in ipairs(vector_components[l]) do
151 .. "a." .. c .. " == "
159 .. "a." .. c .. " + "
167 .. "a." .. c .. " - "
176 .. "val." .. c .. ", "
177 .. "min." .. c .. ", "
178 .. "max." .. c .. ")" ..
185 .. "\tif ((i = " .. type .. "_cmp("
186 .. "&((const " .. name .. " *) a)->" .. c .. ", "
187 .. "&((const " .. name .. " *) b)->" .. c .. ")) != 0)"
188 .. "\n\t\treturn i;\n"
191 .. "v." .. c .. " * s" ..
208 .. "\t" .. type .. "_write(buffer, &val->" .. c .. ");\n"
211 .. "\tif (!" .. type .. "_read(buffer, &val->" .. c .. "))\n\t\treturn false;\n"
214 .. "\tif (!" .. type .. "_send(peer, " .. (last and "submit" or "false") .. ", &val->" .. c .. "))\n\t\treturn false;\n"
217 .. "\tif (!" .. type .. "_recv(peer, &val->" .. c .. "))\n\t\treturn false;\n"
220 emit_h("typedef struct {\n\t" .. type .. " " .. typedef .. "} " .. struct_prefix .. name .. ";\n")
222 emit(export_prefix .. "bool " .. name .. "_equals(" .. name .. " a, " .. name .. " b)", "{\n\treturn " .. equals .. "}\n\n")
223 emit(export_prefix .. name .. " " .. name .. "_add(" .. name .. " a, " .. name .. " b)", "{\n\treturn (" .. name .. ") {" .. add .. "}\n\n")
224 emit(export_prefix .. name .. " " .. name .. "_sub(" .. name .. " a, " .. name .. " b)", "{\n\treturn (" .. name .. ") {" .. sub .. "}\n\n")
225 emit(export_prefix .. name .. " " .. name .. "_clamp(" .. name .. " val, " .. name .. " min, " .. name .. " max)", "{\n\treturn (" .. name .. ") {" .. clamp .. "}\n\n")
226 emit(export_prefix .. "int " .. name .. "_cmp(const void *a, const void *b)", "{\n\tint i;\n" .. cmp .. "\treturn 0;\n}\n\n")
227 emit(export_prefix .. name .. " " .. name .. "_scale(" .. name .. " v, " .. type .. " s)", "{\n\treturn (" .. name .. ") {" .. scale .. "}\n\n")
229 if type:sub(1, 1) == "f" then
230 emit(export_prefix .. name .. " " .. name .. "_mix(" .. name .. " a, " .. name .. " b, " .. type .. " f)", "{\n\treturn (" .. name .. ") {" .. mix .. "}\n\n")
233 emit(export_prefix .. "void " .. name .. "_write(Blob *buffer, " .. name .. " *val)", "{\n" .. write .. "}\n\n")
234 emit(export_prefix .. "bool " .. name .. "_read(Blob *buffer, " .. name .. " *val)", "{\n" .. read .. "\treturn true;\n}\n\n")
236 emit_c("#ifdef USE_DRAGONNET\n")
237 emit_c(local_prefix .. "bool " .. name .. "_send(DragonnetPeer *peer, bool submit, " .. name .. " *val)\n{\n" .. send .. "\treturn true;\n}\n\n")
238 emit_c(local_prefix .. "bool " .. name .. "_recv(DragonnetPeer *peer, " .. name .. " *val)\n{\n" .. recv .. "\treturn true;\n}\n")
243 emit_h("typedef struct {\n\t" .. name .. " min, max;\n} " .. struct_prefix .. box .. ";\n")
245 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")
246 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")
248 emit_c("#ifdef USE_DRAGONNET\n")
249 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")
250 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")
256 local function emit_numeric(class, bits, alias)
257 local name = class .. bits
258 table.insert(numeric_types, name)
260 existing_types[name] = true
261 has_deallocator[name] = false
263 emit_h("typedef " .. alias .. " " .. name .. ";\n")
265 emit(export_prefix .. name .. " " .. name .. "_min(" .. name .. " a, " .. name .. " b)", "{\n\treturn a < b ? a : b;\n}\n\n")
266 emit(export_prefix .. name .. " " .. name .. "_max(" .. name .. " a, " .. name .. " b)", "{\n\treturn a > b ? a : b;\n}\n\n")
267 emit(export_prefix .. name .. " " .. name .. "_clamp(" .. name .. " val, " .. name .. " min, " .. name .. " max)", "{\n\treturn val < min ? min : val > max ? max : val;\n}\n\n")
268 emit(export_prefix .. "int " .. name .. "_cmp(const void *a, const void *b)", "{\n\treturn\n\t\t*(const " .. name .. " *) a < *(const " .. name .. " *) b ? -1 :\n\t\t*(const " .. name .. " *) a > *(const " .. name .. " *) b ? +1 :\n\t\t0;\n}\n\n")
271 emit(export_prefix .. name .. " " .. name .. "_mix(" .. name .. " a, " .. name .. " b, " .. name .. " f)", "{\n\treturn (1.0 - f) * a + b * f;\n}\n\n")
274 emit(export_prefix .. "void " .. name .. "_write(Blob *buffer, " .. name .. " *val)", "{\n" .. (class == "u"
275 and "\t" .. name .. " be = htobe" .. bits .. "(*val);\n\traw_write(buffer, &be, sizeof be);\n"
276 or "\tu" .. bits .. "_write(buffer, (u" .. bits .. " *) val);\n"
278 emit(export_prefix .. "bool " .. name .. "_read(Blob *buffer, " .. name .. " *val)", "{\n" .. (class == "u"
279 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"
280 or "\treturn u" .. bits .. "_read(buffer, (u" .. bits .. " *) val);\n"
283 emit_c("#ifdef USE_DRAGONNET\n")
284 emit_c(local_prefix .. "bool " .. name .. "_send(DragonnetPeer *peer, bool submit, " .. name .. " *val)\n{\n" .. (class == "u"
285 and "\t" .. name .. " be = htobe" .. bits .. "(*val);\n\treturn dragonnet_send_raw(peer, submit, &be, sizeof be);\n"
286 or "\treturn u" .. bits .. "_send(peer, submit, (u" .. bits .. " *) val);\n"
288 emit_c(local_prefix .. "bool " .. name .. "_recv(DragonnetPeer *peer, " .. name .. " *val)\n{\n" .. (class == "u"
289 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"
290 or "\treturn u" .. bits .. "_recv(peer, (u" .. bits .. " *) val);\n"
302 local bytes = math.floor(2 ^ i)
303 local bits = 8 * bytes
305 emit_numeric("u", bits, "uint" .. bits .. "_t")
306 emit_numeric("s", bits, "int" .. bits .. "_t")
309 emit_numeric("f", bits, ({"float", "double"})[i - 1])
313 local converters = {}
318 for i, c in ipairs(vector_components[l]) do
319 converters[l] = converters[l]
328 for _, from in ipairs(numeric_types) do
329 for _, to in ipairs(numeric_types) do
332 local v_from = "v" .. i .. from
333 local v_to = "v" .. i .. to
335 emit(export_prefix .. v_to .. " " .. v_from .. "_to_" .. to .. "(" .. v_from .. " v)", "{\n\treturn (" .. v_to .. ") {" .. converters[i] .. "}\n\n")
345 existing_types.String = true
346 has_deallocator.String = true
349 export_prefix .. "void String_free(String *val)", [[
359 export_prefix .. "void String_write(Blob *buffer, String *val)", [[
361 *val ? raw_write(buffer, *val, strlen(*val) + 1) : raw_write(buffer, "", 1);
368 export_prefix .. "bool String_read(Blob *buffer, String *val)", [[
370 String v = malloc(1 + (1 << 16));
373 for (u16 i = 0;; i++) {
374 if (!raw_read(buffer, &c, 1)) {
384 *val = realloc(v, strlen(v) + 1);
395 ]] .. local_prefix .. [[bool String_send(DragonnetPeer *peer, bool submit, String *val)
397 return *val ? dragonnet_send_raw(peer, submit, *val, strlen(*val) + 1) : dragonnet_send_raw(peer, submit, "", 1);
400 ]] .. local_prefix .. [[bool String_recv(DragonnetPeer *peer, String *val)
402 String v = malloc(1 + (1 << 16));
405 for (u16 i = 0;; i++) {
406 if (!dragonnet_recv_raw(peer, &c, 1)) {
416 *val = realloc(v, strlen(v) + 1);
429 existing_types.Blob = true
430 has_deallocator.Blob = true
433 export_prefix .. "void Blob_compress(Blob *buffer, Blob *val)", [[
435 buffer->siz = 8 + 2 + val->siz;
436 buffer->data = malloc(buffer->siz);
438 *(u64 *) buffer->data = val->siz;
445 s.avail_in = val->siz;
446 s.next_in = (Bytef *) val->data;
447 s.avail_out = buffer->siz - 8 + 1;
448 s.next_out = (Bytef *) buffer->data + 8;
450 deflateInit(&s, Z_BEST_COMPRESSION);
451 deflate(&s, Z_FINISH);
454 buffer->siz = s.total_out + 8;
461 export_prefix .. "void Blob_decompress(Blob *buffer, Blob *val)", [[
463 buffer->siz = *(u64 *) val->data;
464 buffer->data = malloc(buffer->siz);
471 s.avail_in = val->siz - 8;
472 s.next_in = val->data + 8;
473 s.avail_out = buffer->siz;
474 s.next_out = (Bytef *) buffer->data;
477 inflate(&s, Z_NO_FLUSH);
480 buffer->siz = s.total_out;
487 export_prefix .. "void Blob_shrink(Blob *val)", [[
489 val->data = realloc(val->data, val->siz);
496 export_prefix .. "void Blob_free(Blob *val)", [[
506 export_prefix .. "void Blob_write(Blob *buffer, Blob *val)", [[
508 u64_write(buffer, &val->siz);
509 raw_write(buffer, val->data, val->siz);
516 export_prefix .. "bool Blob_read(Blob *buffer, Blob *val)", [[
518 if (!u64_read(buffer, &val->siz))
521 if (!raw_read(buffer, val->data = malloc(val->siz), val->siz)) {
536 ]] .. local_prefix .. [[bool Blob_send(DragonnetPeer *peer, bool submit, Blob *val)
538 if (!u64_send(peer, false, &val->siz))
540 return dragonnet_send_raw(peer, submit, val->data, val->siz);
543 ]] .. local_prefix .. [[bool Blob_recv(DragonnetPeer *peer, Blob *val)
545 if (!u64_recv(peer, &val->siz))
548 if (!dragonnet_recv_raw(peer, val->data = malloc(val->siz), val->siz)) {
566 ]] .. local_prefix .. [[void raw_write_compressed(Blob *buffer, void *val, void (*val_write)(Blob *, void *))
568 Blob compressed, raw = {0};
569 val_write(&raw, val);
570 Blob_compress(&compressed, &raw);
571 Blob_write(buffer, &compressed);
573 Blob_free(&compressed);
577 ]] .. local_prefix .. [[bool raw_read_compressed(Blob *buffer, void *val, bool (*val_read)(Blob *, void *))
579 Blob compressed, raw = {0};
580 bool success = Blob_read(buffer, &compressed);
583 Blob_decompress(&raw, &compressed);
584 Blob raw_buffer = raw;
585 success = success && val_read(&raw_buffer, val);
588 Blob_free(&compressed);
595 ]] .. local_prefix .. [[bool raw_send_compressed(DragonnetPeer *peer, bool submit, void *val, void (*val_write)(Blob *, void *))
597 Blob compressed, raw = {0};
598 val_write(&raw, val);
599 Blob_compress(&compressed, &raw);
600 bool success = Blob_send(peer, submit, &compressed);
602 Blob_free(&compressed);
608 ]] .. local_prefix .. [[bool raw_recv_compressed(DragonnetPeer *peer, void *val, bool (*val_read)(Blob *, void *))
610 Blob compressed, raw = {0};
611 bool success = Blob_recv(peer, &compressed);
614 Blob_decompress(&raw, &compressed);
615 Blob raw_buffer = raw;
616 success = success && val_read(&raw_buffer, val);
619 Blob_free(&compressed);
629 local custom_types = {}
632 local function consume_name(name)
634 table.insert(custom_types, current_type)
640 current_type = {components = {}, component_names = {}}
642 current_type.flags = name:split(" ")
643 current_type.name = table.remove(current_type.flags, #current_type.flags)
645 if existing_types[current_type.name] then
646 error("redeclaration of type " .. current_type.name)
649 existing_types[current_type.name] = true
650 has_deallocator[current_type.name] = false
654 local function consume_comp(comp)
655 if not current_type then
656 error("component without a type: " .. comp)
661 component.flags = comp:split(" ")
662 component.name = table.remove(component.flags, #component.flags)
663 component.type = table.remove(component.flags, #component.flags)
665 component.full_name = current_type.name .. "." .. component.name
668 local met_brace = false
669 local brace_level = 0
671 for i = 1, #component.type do
672 local c = component.type:sub(i, i)
676 if not met_brace then
681 brace_level = brace_level + 1
683 if brace_level == 1 then
684 table.insert(component.array, "")
689 brace_level = brace_level - 1
691 if brace_level < 0 then
692 error("missing [ in " .. component.full_name)
693 elseif brace_level > 0 then
696 elseif not met_brace then
697 base_type = base_type .. c
698 elseif brace_level == 1 then
700 elseif brace_level == 0 then
701 error("invalid character " .. c .. " outside of braces in " .. component.full_name)
705 component.array[#component.array] = component.array[#component.array] .. c
709 component.type = base_type
711 if brace_level > 0 then
712 error("missing ] in " .. component.full_name)
715 if not existing_types[component.type] then
716 error("type " .. component.type .. " of " .. component.full_name .. " does not exist ")
719 has_deallocator[current_type.name] = has_deallocator[current_type.name] or has_deallocator[component.type]
721 if current_type.component_names[component.name] then
722 error("component " .. component.full_name .. " redeclared")
725 current_type.component_names[component.name] = true
727 table.insert(current_type.components, component)
731 for l in def:lines() do
732 local f = l:sub(1, 1)
735 consume_comp(l:sub(2, #l))
746 local dragonnet_types_h = ""
747 local dragonnet_types_c = ""
749 for _, t in ipairs(custom_types) do
752 for _, f in pairs(t.flags) do
756 error("invalid flag " .. f .. " for " .. t.name)
760 local typedef, free, write, read, send, recv =
761 "", "", "", "", "", ""
763 for ic, c in ipairs(t.components) do
765 .. "\t" .. c.type .. " " .. c.name
769 .. "[" .. table.concat(c.array, "][") .. "]"
775 local compressed = false
777 for _, f in pairs(c.flags) do
778 if f == "compressed" then
781 error("invalid flag " .. f .. " for " .. c.full_name)
788 local array_submit = ""
791 for ia, a in ipairs(c.array) do
794 loop = loop .. indent .. "for (int " .. it .. " = 0; " .. it .. " < " .. a .. "; " .. it .. "++)\n"
795 indent = indent .. "\t"
797 index = index .. "[" .. it .. "]"
799 array_submit = array_submit .. " && " .. it .. " == " .. a
803 local addr = "&val->" .. c.name .. index
805 if has_deallocator[c.type] then
807 .. loop .. indent .. c.type .. "_free(" .. addr .. ");\n"
811 .. loop .. indent .. (compressed
812 and "raw_write_compressed(buffer, " .. addr .. ", (void *) &" .. c.type .. "_write);\n"
813 or c.type .. "_write(buffer, " .. addr .. ");\n"
817 .. loop .. indent .. "if (!" .. (compressed
818 and "raw_read_compressed(buffer, " .. addr .. ", (void *) &" .. c.type .. "_read)"
819 or c.type .. "_read(buffer, " .. addr .. ")"
820 ) .. ")\n" .. indent .. "\treturn false;\n"
822 local submit = ic == #t.components and "submit" .. array_submit or "false"
824 .. loop .. indent .. "if (!" .. (compressed
825 and "raw_send_compressed(peer, " .. submit .. ", " .. addr .. ", (void *) &" .. c.type .. "_write)"
826 or c.type .. "_send(peer, " .. submit .. ", " .. addr .. ")"
827 ) .. ")\n" .. indent .. "\treturn false;\n"
830 .. loop .. indent .. "if (!" .. (compressed
831 and "raw_recv_compressed(peer, " .. addr .. ", (void *) &" .. c.type .. "_read)"
832 or c.type .. "_recv(peer, " .. addr .. ")"
833 ) .. ")\n" .. indent .. "\treturn false;\n"
836 emit_h("typedef struct {\n" .. typedef .. "} " .. struct_prefix .. t.name .. ";\n")
838 if has_deallocator[t.name] then
839 emit(export_prefix .. "void " .. t.name .. "_free(" .. t.name .. " *val)", "{\n" .. free .. "}\n\n")
842 emit(export_prefix .. "void " .. t.name .. "_write(Blob *buffer, " .. t.name .. " *val)", "{\n" .. write .. "}\n\n")
843 emit(export_prefix .. "bool " .. t.name .. "_read(Blob *buffer, " .. t.name .. " *val)", "{\n" .. read .. "\treturn true;\n}\n\n")
846 emit_h("#ifdef USE_DRAGONNET\n")
849 emit_c("#ifdef USE_DRAGONNET\n")
851 emit_c(local_prefix .. "bool " .. t.name .. "_send(DragonnetPeer *peer, bool submit, " .. t.name .. " *val)\n{\n" .. send .. "\treturn true;\n}\n\n")
852 emit_c(local_prefix .. "bool " .. t.name .. "_recv(DragonnetPeer *peer, " .. t.name .. " *val)\n{\n" .. recv .. "\treturn true;\n}\n")
856 emit_c("static DragonnetTypeId " .. t.name .. "_type_id = DRAGONNET_TYPE_" .. t.name .. ";\n")
858 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")
861 dragonnet_types_h = dragonnet_types_h
862 .. "\tDRAGONNET_TYPE_" .. t.name .. ",\n"
864 dragonnet_types_c = dragonnet_types_c
865 .. "\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"
873 emit_h("#ifdef USE_DRAGONNET\n")
874 emit_h("typedef enum {\n" .. dragonnet_types_h .. "\tDRAGONNET_NUM_TYPES\n} DragonnetTypeNum;\n")
877 emit_c("#ifdef USE_DRAGONNET\n")
878 emit_c("DragonnetTypeId dragonnet_num_types = DRAGONNET_NUM_TYPES;\nDragonnetType dragonnet_types[] = {\n" .. dragonnet_types_c .. "};\n")