-
Notifications
You must be signed in to change notification settings - Fork 115
/
ExceptionHandler.h
118 lines (97 loc) · 3.17 KB
/
ExceptionHandler.h
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
#pragma once
#include <functional>
#include "primitives.h"
#include <string>
extern "C" {
#include <lua.h>
#include <lauxlib.h>
}
namespace sel {
struct stored_exception {
std::string what;
std::exception_ptr exception;
};
inline std::string const * _stored_exception_metatable_name() {
static std::string const name = "selene_stored_exception";
return &name;
}
inline int _delete_stored_exception(lua_State * l) {
void * user_data = lua_touserdata(l, -1);
static_cast<stored_exception *>(user_data)->~stored_exception();
return 0;
}
inline int _push_stored_exceptions_what(lua_State * l) {
void * user_data = lua_touserdata(l, -1);
std::string const & what = static_cast<stored_exception *>(user_data)->what;
detail::_push(l, what);
return 1;
}
inline void _register_stored_exception_metatable(lua_State * l) {
luaL_newmetatable(l, _stored_exception_metatable_name()->c_str());
lua_pushcfunction(l, _delete_stored_exception);
lua_setfield(l, -2, "__gc");
lua_pushcclosure(l, _push_stored_exceptions_what, 0);
lua_setfield(l, -2, "__tostring");
}
inline void store_current_exception(lua_State * l, char const * what) {
void * user_data = lua_newuserdata(l, sizeof(stored_exception));
new(user_data) stored_exception{what, std::current_exception()};
luaL_getmetatable(l, _stored_exception_metatable_name()->c_str());
if(lua_isnil(l, -1)) {
lua_pop(l, 1);
_register_stored_exception_metatable(l);
}
lua_setmetatable(l, -2);
}
inline stored_exception * test_stored_exception(lua_State *l) {
if(lua_isuserdata(l, -1)) {
void * user_data = luaL_testudata(l, -1, _stored_exception_metatable_name()->c_str());
if(user_data != nullptr) {
return static_cast<stored_exception *>(user_data);
}
}
return nullptr;
}
inline bool push_stored_exceptions_what(lua_State * l) {
stored_exception * stored = test_stored_exception(l);
if(stored != nullptr) {
detail::_push(l, static_cast<const std::string &>(stored->what));
return true;
}
return false;
}
inline std::exception_ptr extract_stored_exception(lua_State *l) {
stored_exception * stored = test_stored_exception(l);
if(stored != nullptr) {
return stored->exception;
}
return nullptr;
}
class ExceptionHandler {
public:
using function = std::function<void(int,std::string,std::exception_ptr)>;
private:
function _handler;
public:
ExceptionHandler() = default;
explicit ExceptionHandler(function && handler) : _handler(handler) {}
void Handle(int luaStatusCode, std::string message, std::exception_ptr exception = nullptr) {
if(_handler) {
_handler(luaStatusCode, std::move(message), std::move(exception));
}
}
void Handle_top_of_stack(int luaStatusCode, lua_State *L) {
stored_exception * stored = test_stored_exception(L);
if(stored) {
Handle(
luaStatusCode,
stored->what,
stored->exception);
} else {
Handle(
luaStatusCode,
detail::_get(detail::_id<std::string>(), L, -1));
}
}
};
}