summaryrefslogtreecommitdiff
path: root/src/script/common/c_packer.h
blob: 8bccca98dae487ba301a6f54ef89013728c37b8b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
/*
Minetest
Copyright (C) 2022 sfan5 <sfan5@live.de>

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#pragma once

#include <string>
#include <vector>
#include "irrlichttypes.h"
#include "util/basic_macros.h"

extern "C" {
#include <lua.h>
}

/*
	This file defines an in-memory representation of Lua objects including
	support for functions and userdata. It it used to move data between Lua
	states and cannot be used for persistence or network transfer.
*/

#define INSTR_SETTABLE (-10)
#define INSTR_POP      (-11)

/**
 * Represents a single instruction that pushes a new value or works with existing ones.
 */
struct PackedInstr
{
	s16 type; // LUA_T* or INSTR_*
	u16 set_into; // set into table on stack
	bool pop; // remove from stack?
	union {
		bool bdata; // boolean: value
		lua_Number ndata; // number: value
		struct {
			u16 uidata1, uidata2; // table: narr, nrec
		};
		struct {
			/*
				SETTABLE: key index, value index
				POP: indices to remove
				otherwise w/ set_into: numeric key, -
			*/
			s32 sidata1, sidata2;
		};
		void *ptrdata; // userdata: implementation defined
	};
	/*
		- string: value
		- function: buffer
		- w/ set_into: string key (no null bytes!)
		- userdata: name in registry
	*/
	std::string sdata;

	PackedInstr() : type(0), set_into(0), pop(false) {}
};

/**
 * A packed value can be a primitive like a string or number but also a table
 * including all of its contents. It is made up of a linear stream of
 * 'instructions' that build the final value when executed.
 */
struct PackedValue
{
	std::vector<PackedInstr> i;
	// Indicates whether there are any userdata pointers that need to be deallocated
	bool contains_userdata = false;

	PackedValue() = default;
	~PackedValue();

	DISABLE_CLASS_COPY(PackedValue)

	ALLOW_CLASS_MOVE(PackedValue)
};

/*
 * Packing callback: Turns a Lua value at given index into a void*
 */
typedef void *(*PackInFunc)(lua_State *L, int idx);
/*
 * Unpacking callback: Turns a void* back into the Lua value (left on top of stack)
 *
 * Note that this function must take ownership of the pointer, so make sure
 * to free or keep the memory.
 * `L` can be nullptr to indicate that data should just be discarded.
 */
typedef void (*PackOutFunc)(lua_State *L, void *ptr);
/*
 * Register a packable type with the name of its metatable.
 *
 * Even though the callbacks are global this must be called for every Lua state
 * that supports objects of this type.
 * This function is thread-safe.
 */
void script_register_packer(lua_State *L, const char *regname,
		PackInFunc fin, PackOutFunc fout);

// Pack a Lua value
PackedValue *script_pack(lua_State *L, int idx);
// Unpack a Lua value (left on top of stack)
// Note that this may modify the PackedValue, you can't reuse it!
void script_unpack(lua_State *L, PackedValue *val);

// Dump contents of PackedValue to stdout for debugging
void script_dump_packed(const PackedValue *val);