]> git.lizzy.rs Git - dragonfireclient.git/blob - src/script/common/c_packer.h
Support packing arbitrary graphs (#12289)
[dragonfireclient.git] / src / script / common / c_packer.h
1 /*
2 Minetest
3 Copyright (C) 2022 sfan5 <sfan5@live.de>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #pragma once
21
22 #include <string>
23 #include <vector>
24 #include "irrlichttypes.h"
25 #include "util/basic_macros.h"
26
27 extern "C" {
28 #include <lua.h>
29 }
30
31 /*
32         This file defines an in-memory representation of Lua objects including
33         support for functions and userdata. It it used to move data between Lua
34         states and cannot be used for persistence or network transfer.
35 */
36
37 #define INSTR_SETTABLE (-10)
38 #define INSTR_POP      (-11)
39 #define INSTR_PUSHREF  (-12)
40
41 /**
42  * Represents a single instruction that pushes a new value or works with existing ones.
43  */
44 struct PackedInstr
45 {
46         s16 type; // LUA_T* or INSTR_*
47         u16 set_into; // set into table on stack
48         bool keep_ref; // is referenced later by INSTR_PUSHREF?
49         bool pop; // remove from stack?
50         union {
51                 bool bdata; // boolean: value
52                 lua_Number ndata; // number: value
53                 struct {
54                         u16 uidata1, uidata2; // table: narr, nrec
55                 };
56                 struct {
57                         /*
58                                 SETTABLE: key index, value index
59                                 POP: indices to remove
60                                 otherwise w/ set_into: numeric key, -
61                         */
62                         s32 sidata1, sidata2;
63                 };
64                 void *ptrdata; // userdata: implementation defined
65                 s32 ref; // PUSHREF: index of referenced instr
66         };
67         /*
68                 - string: value
69                 - function: buffer
70                 - w/ set_into: string key (no null bytes!)
71                 - userdata: name in registry
72         */
73         std::string sdata;
74
75         PackedInstr() : type(0), set_into(0), keep_ref(false), pop(false) {}
76 };
77
78 /**
79  * A packed value can be a primitive like a string or number but also a table
80  * including all of its contents. It is made up of a linear stream of
81  * 'instructions' that build the final value when executed.
82  */
83 struct PackedValue
84 {
85         std::vector<PackedInstr> i;
86         // Indicates whether there are any userdata pointers that need to be deallocated
87         bool contains_userdata = false;
88
89         PackedValue() = default;
90         ~PackedValue();
91
92         DISABLE_CLASS_COPY(PackedValue)
93
94         ALLOW_CLASS_MOVE(PackedValue)
95 };
96
97 /*
98  * Packing callback: Turns a Lua value at given index into a void*
99  */
100 typedef void *(*PackInFunc)(lua_State *L, int idx);
101 /*
102  * Unpacking callback: Turns a void* back into the Lua value (left on top of stack)
103  *
104  * Note that this function must take ownership of the pointer, so make sure
105  * to free or keep the memory.
106  * `L` can be nullptr to indicate that data should just be discarded.
107  */
108 typedef void (*PackOutFunc)(lua_State *L, void *ptr);
109 /*
110  * Register a packable type with the name of its metatable.
111  *
112  * Even though the callbacks are global this must be called for every Lua state
113  * that supports objects of this type.
114  * This function is thread-safe.
115  */
116 void script_register_packer(lua_State *L, const char *regname,
117                 PackInFunc fin, PackOutFunc fout);
118
119 // Pack a Lua value
120 PackedValue *script_pack(lua_State *L, int idx);
121 // Unpack a Lua value (left on top of stack)
122 // Note that this may modify the PackedValue, you can't reuse it!
123 void script_unpack(lua_State *L, PackedValue *val);
124
125 // Dump contents of PackedValue to stdout for debugging
126 void script_dump_packed(const PackedValue *val);