summaryrefslogtreecommitdiff
path: root/src/script/rapidjson/userdata.hpp
blob: 1127bac391dc7b77f2c45ddcc17029ef3e6fd91e (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
#ifndef __LUA_RAPIDJSON_USERDATA_HPP__
#define __LUA_RAPIDJSON_USERDATA_HPP__


#include "qcommon/q3_lauxlib.h"

#include "luax.hpp"

#include "lua.hpp"
#include "rapidjson.h"

template <typename T>
struct Userdata
{
    static int create(lua_State* L)
    {
        push(L, construct(L));
        return 1;
    }

    static T* construct(lua_State* L);

    static void luaopen(lua_State* L)
    {
        luaL_newmetatable(L, metatable);
        lua_pushvalue(L, -1);
        luax::setfuncs(L, methods());
        lua_setfield(L, -2, "__index");
        lua_pop(L, 1);
    }

    static const luaL_Reg* methods();

    static void push(lua_State* L, T* c)
    {
        if (!c)
        {
            lua_pushnil(L);
            return;
        }

        T** ud = reinterpret_cast<T**>(lua_newuserdata(L, sizeof(*ud)));
        if (!ud)
            luaL_error(L, "Out of memory");

        *ud = c;

        luaL_getmetatable(L, metatable);
        lua_setmetatable(L, -2);
    }

    static T** getUserdata(lua_State* L, int idx)
    {
        return reinterpret_cast<T**>(lua_touserdata(L, idx));
    }


    static T* get(lua_State* L, int idx)
    {
        auto p = getUserdata(L, idx);
        if (p && *p )
        {
            if (lua_getmetatable(L, idx))
            {  /* does it have a metatable? */
                luaL_getmetatable(L, metatable);  /* get correct metatable */
                if (lua_rawequal(L, -1, -2))
                {  /* does it have the correct mt? */
                    lua_pop(L, 2);  /* remove both metatables */
                    return *p;
                }
            }
        }
        return nullptr;
    }

    static T* check(lua_State* L, int idx)
    {
        auto ud = reinterpret_cast<T**>(luaL_checkudata(L, idx, metatable));
        if (!*ud)
            luaL_error(L, "%s already closed", metatable);
        return *ud;
    }

    static int metamethod_gc(lua_State* L)
    {
        T** ud = reinterpret_cast<T**>(luaL_checkudata(L, 1, metatable));
        if (*ud)
        {
            delete *ud;
            *ud = nullptr;
        }
        return 0;
    }

    static int metamethod_tostring(lua_State* L)
    {
        auto ud = getUserdata(L, 1);
        if (*ud)
        {
            lua_pushfstring(L, "%s (%p)", metatable, *ud);
        }
        else
        {
            lua_pushfstring(L, "%s (closed)", metatable);
        }
        return 1;
    }

    static const char* const metatable;
};

#endif