mirror of
https://github.com/ThePhD/sol2.git
synced 2024-03-22 13:10:44 +08:00
We do have a cheap char type now, but figuring out that codecvt is super busted makes me sad
Safety macros are now in place. Usertype ones turned on by default Closes #93 Closes #94
This commit is contained in:
parent
85b4ad54ab
commit
96f231a183
|
@ -44,10 +44,15 @@
|
|||
|
||||
#ifdef _MSC_VER
|
||||
#ifdef _DEBUG
|
||||
#ifndef NDEBUG
|
||||
#ifndef SOL_CHECK_ARGUMENTS
|
||||
// Do not define by default: let user turn it on
|
||||
//#define SOL_CHECK_ARGUMENTS
|
||||
#endif // Check Arguments
|
||||
#ifndef SOL_SAFE_USERTYPE
|
||||
#define SOL_SAFE_USERTYPE
|
||||
#endif // Safe Usertypes
|
||||
#endif // NDEBUG
|
||||
#endif // Debug
|
||||
|
||||
#ifndef _CPPUNWIND
|
||||
|
@ -69,7 +74,11 @@
|
|||
#ifndef SOL_CHECK_ARGUMENTS
|
||||
// Do not define by default: let user choose
|
||||
//#define SOL_CHECK_ARGUMENTS
|
||||
// But do check userdata by default:
|
||||
#endif // Check Arguments
|
||||
#ifndef SOL_SAFE_USERTYPE
|
||||
#define SOL_SAFE_USERTYPE
|
||||
#endif // Safe Usertypes
|
||||
#endif // g++ optimizer flag
|
||||
#endif // Not Debug
|
||||
|
||||
|
@ -87,4 +96,10 @@
|
|||
|
||||
#endif // vc++ || clang++/g++
|
||||
|
||||
#ifndef SOL_SAFE_USERTYPE
|
||||
#ifdef SOL_CHECK_ARGUMENTS
|
||||
#define SOL_SAFE_USERTYPE
|
||||
#endif // Turn on Safety for all
|
||||
#endif // Safe Usertypes
|
||||
|
||||
#endif // SOL_VERSION_HPP
|
||||
|
|
|
@ -119,7 +119,12 @@ struct usertype_overloaded_function : base_function {
|
|||
template <typename Fx, std::size_t I, typename... R, typename... Args, meta::DisableIf<meta::Bool<Fx::is_free>> = 0>
|
||||
int call(types<Fx>, index_value<I>, types<R...> r, types<Args...> a, lua_State* L, int, int start) {
|
||||
auto& func = std::get<I>(overloads);
|
||||
func.item = detail::ptr(stack::get<T>(L, 1));
|
||||
func.item = stack::get<meta::Unwrapped<T>*>(L, 1);
|
||||
#ifdef SOL_SAFE_USERTYPE
|
||||
if (func.item == nullptr) {
|
||||
return luaL_error(L, "sol: received null for 'self' argument (use ':' for accessing member functions)");
|
||||
}
|
||||
#endif // Safety
|
||||
return stack::call_into_lua<0, false>(r, a, L, start, func);
|
||||
}
|
||||
|
||||
|
|
|
@ -60,7 +60,12 @@ struct usertype_function : public usertype_function_core<Tp, Function> {
|
|||
usertype_function(Args&&... args): base_t(std::forward<Args>(args)...) {}
|
||||
|
||||
int prelude(lua_State* L) {
|
||||
this->fx.item = detail::ptr(stack::get<T>(L, 1));
|
||||
this->fx.item = stack::get<meta::Unwrapped<T>*>(L, 1);
|
||||
#ifdef SOL_SAFE_USERTYPE
|
||||
if (this->fx.item == nullptr) {
|
||||
return luaL_error(L, "sol: received null for 'self' argument (use ':' for accessing member functions)");
|
||||
}
|
||||
#endif // Safety
|
||||
return static_cast<base_t&>(*this)(meta::tuple_types<return_type>(), args_type(), index_value<2>(), L);
|
||||
}
|
||||
|
||||
|
@ -122,6 +127,11 @@ struct usertype_variable_function : public usertype_function_core<Tp, Function>
|
|||
int prelude(lua_State* L) {
|
||||
int argcount = lua_gettop(L);
|
||||
this->fx.item = stack::get<T*>(L, 1);
|
||||
#ifdef SOL_SAFE_USERTYPE
|
||||
if (this->fx.item == nullptr) {
|
||||
return luaL_error(L, "sol: received null for 'self' argument (use ':' for accessing member functions)");
|
||||
}
|
||||
#endif // Safety
|
||||
switch(argcount) {
|
||||
case 2:
|
||||
return get_variable(can_read(), L);
|
||||
|
|
|
@ -51,7 +51,7 @@ struct check_getter<optional<T>> {
|
|||
};
|
||||
|
||||
template <typename T>
|
||||
struct check_getter<T, std::enable_if_t<std::is_integral<T>::value && !std::is_same<T, bool>::value>> {
|
||||
struct check_getter<T, std::enable_if_t<std::is_integral<T>::value && !lua_type_of<T>::value == type::number>> {
|
||||
template <typename Handler>
|
||||
static optional<T> get( lua_State* L, int index, Handler&& handler) {
|
||||
int isnum = 0;
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include <memory>
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
#include <codecvt>
|
||||
|
||||
namespace sol {
|
||||
namespace stack {
|
||||
|
@ -113,6 +114,88 @@ struct getter<const char*> {
|
|||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct getter<char> {
|
||||
static char get(lua_State* L, int index = -1) {
|
||||
size_t len;
|
||||
auto str = lua_tolstring(L, index, &len);
|
||||
return len > 0 ? str[0] : '\0';
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct getter<std::wstring> {
|
||||
static std::wstring get(lua_State* L, int index = -1) {
|
||||
size_t len;
|
||||
auto str = lua_tolstring(L, index, &len);
|
||||
typedef std::codecvt_utf8<wchar_t> convert;
|
||||
std::wstring_convert<convert, wchar_t> conv;
|
||||
return conv.from_bytes(str, str + len);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct getter<std::u16string> {
|
||||
static std::u16string get(lua_State* L, int index = -1) {
|
||||
size_t len;
|
||||
auto str = lua_tolstring(L, index, &len);
|
||||
#ifdef _MSC_VER // https://connect.microsoft.com/VisualStudio/feedback/details/1348277/link-error-when-using-std-codecvt-utf8-utf16-char16-t
|
||||
typedef uint16_t T;
|
||||
typedef std::codecvt_utf8<T> convert;
|
||||
std::wstring_convert<convert, T> conv;
|
||||
std::basic_string<T> shitty = conv.from_bytes(str, str + len);
|
||||
return std::u16string(shitty.cbegin(), shitty.cend()); // fuck you VC++
|
||||
#else
|
||||
typedef std::codecvt_utf8<char16_t> convert;
|
||||
std::wstring_convert<convert, char16_t> conv;
|
||||
return conv.from_bytes(str, str + len);
|
||||
#endif // VC++
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct getter<std::u32string> {
|
||||
static std::u32string get(lua_State* L, int index = -1) {
|
||||
size_t len;
|
||||
auto str = lua_tolstring(L, index, &len);
|
||||
#ifdef _MSC_VER // https://connect.microsoft.com/VisualStudio/feedback/details/1348277/link-error-when-using-std-codecvt-utf8-utf16-char16-t
|
||||
typedef int32_t T;
|
||||
typedef std::codecvt_utf8<T> convert;
|
||||
std::wstring_convert<convert, T> conv;
|
||||
std::basic_string<T> shitty = conv.from_bytes(str, str + len);
|
||||
return std::u32string(shitty.cbegin(), shitty.cend()); // fuck you VC++
|
||||
#else
|
||||
typedef std::codecvt_utf8<char32_t> convert;
|
||||
std::wstring_convert<convert, char32_t> conv;
|
||||
return conv.from_bytes(str, str + len);
|
||||
#endif // VC++
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct getter<wchar_t> {
|
||||
static wchar_t get(lua_State* L, int index = -1) {
|
||||
auto str = getter<std::wstring>{}.get(L, index);
|
||||
return str.size() > 0 ? str[0] : '\0';
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct getter<char16_t> {
|
||||
static char get(lua_State* L, int index = -1) {
|
||||
auto str = getter<std::u16string>{}.get(L, index);
|
||||
return str.size() > 0 ? str[0] : '\0';
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct getter<char32_t> {
|
||||
static char32_t get(lua_State* L, int index = -1) {
|
||||
auto str = getter<std::u32string>{}.get(L, index);
|
||||
return str.size() > 0 ? str[0] : '\0';
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct getter<nil_t> {
|
||||
static nil_t get(lua_State*, int = -1) {
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "raii.hpp"
|
||||
#include "optional.hpp"
|
||||
#include <memory>
|
||||
#include <codecvt>
|
||||
|
||||
namespace sol {
|
||||
namespace stack {
|
||||
|
@ -252,6 +253,55 @@ struct pusher<const char*> {
|
|||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct pusher<const wchar_t*> {
|
||||
static int push(lua_State* L, const wchar_t* wstr) {
|
||||
return push(L, wstr, wstr + std::char_traits<wchar_t>::length(wstr));
|
||||
}
|
||||
static int push(lua_State* L, const wchar_t* wstrb, const wchar_t* wstre) {
|
||||
typedef std::codecvt_utf8<wchar_t> convert;
|
||||
std::wstring_convert<convert, wchar_t> conv;
|
||||
std::string str = conv.to_bytes( wstrb, wstre );
|
||||
return stack::push(L, str);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct pusher<const char16_t*> {
|
||||
static int push(lua_State* L, const char16_t* u16str) {
|
||||
return push(L, u16str, u16str + std::char_traits<char16_t>::length(u16str));
|
||||
}
|
||||
static int push(lua_State* L, const char16_t* u16strb, const char16_t* u16stre) {
|
||||
#ifdef _MSC_VER // https://connect.microsoft.com/VisualStudio/feedback/details/1348277/link-error-when-using-std-codecvt-utf8-utf16-char16-t
|
||||
typedef uint16_t T;
|
||||
#else
|
||||
typedef char16_t T;
|
||||
#endif // VC++
|
||||
typedef std::codecvt_utf8<T> convert;
|
||||
std::wstring_convert<convert, T> conv;
|
||||
std::string str = conv.to_bytes( reinterpret_cast<const T*>(u16strb), reinterpret_cast<const T*>(u16stre) );
|
||||
return stack::push(L, str);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct pusher<const char32_t*> {
|
||||
static int push(lua_State* L, const char32_t* u32str) {
|
||||
return push(L, u32str, u32str + std::char_traits<char32_t>::length(u32str));
|
||||
}
|
||||
static int push(lua_State* L, const char32_t* u32strb, const char32_t* u32stre) {
|
||||
#ifdef _MSC_VER // https://connect.microsoft.com/VisualStudio/feedback/details/1348277/link-error-when-using-std-codecvt-utf8-utf16-char16-t
|
||||
typedef uint32_t T;
|
||||
#else
|
||||
typedef char32_t T;
|
||||
#endif // VC++
|
||||
typedef std::codecvt_utf8<T> convert;
|
||||
std::wstring_convert<convert, T> conv;
|
||||
std::string str = conv.to_bytes( reinterpret_cast<const T*>(u32strb), reinterpret_cast<const T*>(u32stre) );
|
||||
return stack::push(L, str);
|
||||
}
|
||||
};
|
||||
|
||||
template<size_t N>
|
||||
struct pusher<char[N]> {
|
||||
static int push(lua_State* L, const char (&str)[N]) {
|
||||
|
@ -260,6 +310,59 @@ struct pusher<char[N]> {
|
|||
}
|
||||
};
|
||||
|
||||
template<size_t N>
|
||||
struct pusher<wchar_t[N]> {
|
||||
static int push(lua_State* L, const wchar_t (&str)[N]) {
|
||||
return stack::push<const wchar_t*>(L, str, str + N - 1);
|
||||
}
|
||||
};
|
||||
|
||||
template<size_t N>
|
||||
struct pusher<char16_t[N]> {
|
||||
static int push(lua_State* L, const char16_t (&str)[N]) {
|
||||
return stack::push<const char16_t*>(L, str, str + N - 1);
|
||||
}
|
||||
};
|
||||
|
||||
template<size_t N>
|
||||
struct pusher<char32_t[N]> {
|
||||
static int push(lua_State* L, const char32_t (&str)[N]) {
|
||||
return stack::push<const char32_t*>(L, str, str + N - 1);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct pusher<char> {
|
||||
static int push(lua_State* L, char c) {
|
||||
const char str[2] = { c, '\0'};
|
||||
return stack::push(L, str);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct pusher<wchar_t> {
|
||||
static int push(lua_State* L, wchar_t c) {
|
||||
const wchar_t str[2] = { c, '\0'};
|
||||
return stack::push(L, str);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct pusher<char16_t> {
|
||||
static int push(lua_State* L, char16_t c) {
|
||||
const char16_t str[2] = { c, '\0'};
|
||||
return stack::push(L, str);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct pusher<char32_t> {
|
||||
static int push(lua_State* L, char32_t c) {
|
||||
const char32_t str[2] = { c, '\0'};
|
||||
return stack::push(L, str);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct pusher<std::string> {
|
||||
static int push(lua_State* L, const std::string& str) {
|
||||
|
@ -268,6 +371,27 @@ struct pusher<std::string> {
|
|||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct pusher<std::wstring> {
|
||||
static int push(lua_State* L, const std::wstring& wstr) {
|
||||
return stack::push(L, wstr.data(), wstr.data() + wstr.size());
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct pusher<std::u16string> {
|
||||
static int push(lua_State* L, const std::u16string& u16str) {
|
||||
return stack::push(L, u16str.data(), u16str.data() + u16str.size());
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct pusher<std::u32string> {
|
||||
static int push(lua_State* L, const std::u32string& u32str) {
|
||||
return stack::push(L, u32str.data(), u32str.data() + u32str.size());
|
||||
}
|
||||
};
|
||||
|
||||
template<typename... Args>
|
||||
struct pusher<std::tuple<Args...>> {
|
||||
template <std::size_t... I, typename T>
|
||||
|
|
|
@ -379,12 +379,48 @@ struct lua_type_of : std::integral_constant<type, type::userdata> {};
|
|||
template <>
|
||||
struct lua_type_of<std::string> : std::integral_constant<type, type::string> {};
|
||||
|
||||
template <>
|
||||
struct lua_type_of<std::wstring> : std::integral_constant<type, type::string> {};
|
||||
|
||||
template <>
|
||||
struct lua_type_of<std::u16string> : std::integral_constant<type, type::string> {};
|
||||
|
||||
template <>
|
||||
struct lua_type_of<std::u32string> : std::integral_constant<type, type::string> {};
|
||||
|
||||
template <std::size_t N>
|
||||
struct lua_type_of<char[N]> : std::integral_constant<type, type::string> {};
|
||||
|
||||
template <std::size_t N>
|
||||
struct lua_type_of<wchar_t[N]> : std::integral_constant<type, type::string> {};
|
||||
|
||||
template <std::size_t N>
|
||||
struct lua_type_of<char16_t[N]> : std::integral_constant<type, type::string> {};
|
||||
|
||||
template <std::size_t N>
|
||||
struct lua_type_of<char32_t[N]> : std::integral_constant<type, type::string> {};
|
||||
|
||||
template <>
|
||||
struct lua_type_of<char> : std::integral_constant<type, type::string> {};
|
||||
|
||||
template <>
|
||||
struct lua_type_of<wchar_t> : std::integral_constant<type, type::string> {};
|
||||
|
||||
template <>
|
||||
struct lua_type_of<char16_t> : std::integral_constant<type, type::string> {};
|
||||
|
||||
template <>
|
||||
struct lua_type_of<char32_t> : std::integral_constant<type, type::string> {};
|
||||
|
||||
template <>
|
||||
struct lua_type_of<const char*> : std::integral_constant<type, type::string> {};
|
||||
|
||||
template <>
|
||||
struct lua_type_of<const char16_t*> : std::integral_constant<type, type::string> {};
|
||||
|
||||
template <>
|
||||
struct lua_type_of<const char32_t*> : std::integral_constant<type, type::string> {};
|
||||
|
||||
template <>
|
||||
struct lua_type_of<bool> : std::integral_constant<type, type::boolean> {};
|
||||
|
||||
|
|
71
test_strings.cpp
Normal file
71
test_strings.cpp
Normal file
|
@ -0,0 +1,71 @@
|
|||
#define SOL_CHECK_ARGUMENTS
|
||||
|
||||
#include <catch.hpp>
|
||||
#include <sol.hpp>
|
||||
|
||||
// There isn't a single library roundtripping with codecvt works on. We'll do the nitty-gritty of it later...
|
||||
#if 0
|
||||
TEST_CASE("stack/strings", "test that strings can be roundtripped") {
|
||||
sol::state lua;
|
||||
|
||||
static const char utf8str[] = "\xF0\x9F\x8D\x8C\x20\xE6\x99\xA5\x20\x46\x6F\x6F\x20\xC2\xA9\x20\x62\x61\x72\x20\xF0\x9D\x8C\x86\x20\x62\x61\x7A\x20\xE2\x98\x83\x20\x71\x75\x78";
|
||||
static const char16_t utf16str[] = { 0xD83C, 0xDF4C, 0x20, 0x6665, 0x20, 0x46, 0x6F, 0x6F, 0x20, 0xA9, 0x20, 0x62, 0x61, 0x72, 0x20, 0xD834, 0xDF06, 0x20, 0x62, 0x61, 0x7A, 0x20, 0x2603, 0x20, 0x71, 0x75, 0x78, 0x00 };
|
||||
static const char32_t utf32str[] = { 0x1F34C, 0x0020, 0x6665, 0x0020, 0x0046, 0x006F, 0x006F, 0x0020, 0x00A9, 0x0020, 0x0062, 0x0061, 0x0072, 0x0020, 0x1D306, 0x0020, 0x0062, 0x0061, 0x007A, 0x0020, 0x2603, 0x0020, 0x0071, 0x0075, 0x0078, 0x00 };
|
||||
static const wchar_t widestr[] = L"Fuck these shitty compilers";
|
||||
|
||||
lua["utf8"] = utf8str;
|
||||
lua["utf16"] = utf16str;
|
||||
lua["utf32"] = utf32str;
|
||||
lua["wide"] = widestr;
|
||||
|
||||
std::string utf8_to_utf8 = lua["utf8"];
|
||||
std::string utf16_to_utf8 = lua["utf16"];
|
||||
std::string utf32_to_utf8 = lua["utf32"];
|
||||
std::string wide_to_utf8 = lua["wide"];
|
||||
|
||||
std::wstring utf8_to_wide = lua["utf8"];
|
||||
std::wstring utf16_to_wide = lua["utf16"];
|
||||
std::wstring utf32_to_wide = lua["utf32"];
|
||||
std::wstring wide_to_wide = lua["wide"];
|
||||
|
||||
std::u16string utf8_to_utf16 = lua["utf8"];
|
||||
std::u16string utf16_to_utf16 = lua["utf16"];
|
||||
std::u16string utf32_to_utf16 = lua["utf32"];
|
||||
std::u16string wide_to_utf16 = lua["wide"];
|
||||
|
||||
std::u32string utf8_to_utf32 = lua["utf8"];
|
||||
std::u32string utf16_to_utf32 = lua["utf16"];
|
||||
std::u32string utf32_to_utf32 = lua["utf32"];
|
||||
std::u32string wide_to_utf32 = lua["wide"];
|
||||
|
||||
REQUIRE(utf8_to_utf8 == utf8str);
|
||||
REQUIRE(utf16_to_utf8 == utf8str);
|
||||
REQUIRE(utf32_to_utf8 == utf8str);
|
||||
REQUIRE(wide_to_utf8 == utf8str);
|
||||
|
||||
REQUIRE(utf8_to_utf16 == utf16str);
|
||||
REQUIRE(utf16_to_utf16 == utf16str);
|
||||
REQUIRE(utf32_to_utf16 == utf16str);
|
||||
REQUIRE(wide_to_utf16 == utf16str);
|
||||
|
||||
REQUIRE(utf8_to_utf32 == utf32str);
|
||||
REQUIRE(utf16_to_utf32 == utf32str);
|
||||
REQUIRE(utf32_to_utf32 == utf32str);
|
||||
REQUIRE(wide_to_utf32 == utf32str);
|
||||
|
||||
REQUIRE(utf8_to_wide == widestr);
|
||||
REQUIRE(utf16_to_wide == widestr);
|
||||
REQUIRE(utf32_to_wide == widestr);
|
||||
REQUIRE(wide_to_wide == widestr);
|
||||
|
||||
char32_t utf8_to_char32 = lua["utf8"];
|
||||
char32_t utf16_to_char32 = lua["utf16"];
|
||||
char32_t utf32_to_char32 = lua["utf32"];
|
||||
char32_t wide_to_char32 = lua["wide"];
|
||||
|
||||
REQUIRE(utf8_to_char32 == utf32str[0]);
|
||||
REQUIRE(utf16_to_char32 == utf32str[0]);
|
||||
REQUIRE(utf32_to_char32 == utf32str[0]);
|
||||
REQUIRE(wide_to_char32 == utf32str[0]);
|
||||
}
|
||||
#endif // Shit C++
|
16
tests.cpp
16
tests.cpp
|
@ -1186,3 +1186,19 @@ TEST_CASE("object/conversions", "make sure all basic reference types can be made
|
|||
REQUIRE(os.get_type() == sol::type::string);
|
||||
REQUIRE(omn.get_type() == sol::type::nil);
|
||||
}
|
||||
|
||||
TEST_CASE("usertype/safety", "crash with an exception -- not a segfault -- on bad userdata calls") {
|
||||
class Test {
|
||||
public:
|
||||
void sayHello() { std::cout << "Hey\n"; }
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
lua.new_usertype<Test>("Test", "sayHello", &Test::sayHello);
|
||||
static const std::string code = R"(
|
||||
local t = Test.new()
|
||||
t:sayHello() --Works fine
|
||||
t.sayHello() --Uh oh.
|
||||
)";
|
||||
REQUIRE_THROWS(lua.script(code));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user