update docs a bit, think aobut changes to container_traits and friends...

This commit is contained in:
ThePhD 2018-08-10 11:17:31 -04:00
parent cf1376cd06
commit 0e321272e6
No known key found for this signature in database
GPG Key ID: 1509DB1C0F702BFA
8 changed files with 340 additions and 8 deletions

View File

@ -72,6 +72,9 @@ You can use the individual load and function call operator to load, check, and t
:linenos: :linenos:
:lines: 1-10, 16-40, 47-49 :lines: 1-10, 16-40, 47-49
You can also `develop custom loaders`_ that pull from things that are not strings or files.
set and get variables set and get variables
--------------------- ---------------------
@ -271,6 +274,7 @@ Some more things you can do/read about:
* :doc:`stack references<../api/stack_reference>` to have zero-overhead Sol abstractions while not copying to the Lua registry. * :doc:`stack references<../api/stack_reference>` to have zero-overhead Sol abstractions while not copying to the Lua registry.
* :doc:`resolve<../api/resolve>` overloads in case you have overloaded functions; a cleaner casting utility. You must use this to emulate default parameters. * :doc:`resolve<../api/resolve>` overloads in case you have overloaded functions; a cleaner casting utility. You must use this to emulate default parameters.
.. _develop custom loaders: https://github.com/ThePhD/sol2/blob/develop/examples/custom_reader.cpp
.. _basic example: https://github.com/ThePhD/sol2/blob/develop/examples/usertype.cpp .. _basic example: https://github.com/ThePhD/sol2/blob/develop/examples/usertype.cpp
.. _special functions example: https://github.com/ThePhD/sol2/blob/develop/examples/usertype_special_functions.cpp .. _special functions example: https://github.com/ThePhD/sol2/blob/develop/examples/usertype_special_functions.cpp
.. _initializers example: https://github.com/ThePhD/sol2/blob/develop/examples/usertype_initializers.cpp .. _initializers example: https://github.com/ThePhD/sol2/blob/develop/examples/usertype_initializers.cpp

View File

@ -0,0 +1,95 @@
#define SOL_CHECK_ARGUMENTS 1
#include <sol.hpp>
#include "assert.hpp"
#include <iostream>
#include <exception>
#include <fstream>
struct custom_reader {
FILE* f;
// We use 2 here to demonstrate
// multiple calls to the function to
// parse whole file.
// Please don't use 2.
// PLEASE DO NOT USE A BUFFER
// OF SIZE 2!
char buffer[2];
std::size_t current_size;
std::size_t read_count;
custom_reader(FILE* f_) : f(f_), buffer(), current_size(0), read_count(0) {
}
bool read() {
std::cout << "custom read: read #" << ++read_count << std::endl;
current_size = fread( buffer, 1, 2, f );
return current_size > 0 && ferror(f) == 0;
}
~custom_reader( ) {
std::fclose( f );
}
};
// function must match signature found in type lua_Reader:
// const char* ( lua_State*, void*, size_t* )
const char* custom_reader_function(lua_State*, void* pointer_to_my_object, size_t* data_size) {
custom_reader& cr = *(static_cast<custom_reader*>(pointer_to_my_object));
if ( cr.read( ) ) {
*data_size = cr.current_size;
return cr.buffer;
}
else {
*data_size = 0;
return nullptr;
}
}
int main( ) {
std::cout << "=== custom reader ===" << std::endl;
// make a file to use for the custom reader
{
std::ofstream bjork("bjork.lua", std::ios::binary);
bjork << "print('hello!')\n";
}
struct on_scope_exit {
~on_scope_exit() {
// remove file when done
std::remove("bjork.lua");
}
} remove_on_exit;
sol::state lua;
lua.open_libraries( sol::lib::base );
FILE* bjork_fp;
#ifdef _MSC_VER
if ( fopen_s( &bjork_fp, "bjork.lua", "r" ) != 0 ) {
std::cerr << "failed to open bjork.lua -- exiting" << std::endl;
return -1;
}
#else
bjork_fp = fopen( "bjork.lua", "r" );
#endif
if (bjork_fp == nullptr) {
std::cerr << "failed to open bjork.lua -- exiting" << std::endl;
return -1;
}
custom_reader reader(bjork_fp);
// load the code using our custom reader, then run it
auto result = lua.safe_script( custom_reader_function, &reader, sol::script_pass_on_error );
// make sure we ran loaded and ran the code successfully
c_assert( result.valid( ) );
// note there are lua.load( ... ) variants that take a
// custom reader than JUST run the code, too!
std::cout << std::endl;
return 0;
}

View File

@ -0,0 +1,76 @@
// Thanks to OrfeasZ for their answer to
// an issue for this example!
#define SOL_CHECK_ARGUMENTS 1
#include <sol.hpp>
#include "assert.hpp"
#include <iostream>
#include <exception>
// Use raw function of form "int(lua_State*)"
// -- this is called a "raw C function",
// and matches the type for lua_CFunction
int LoadFileRequire(lua_State* L) {
// use sol2 stack API to pull
// "first argument"
std::string path = sol::stack::get<std::string>(L, 1);
if (path == "a") {
std::string script = R"(
print("Hello from module land!")
test = 123
return "bananas"
)";
// load "module", but don't run it
luaL_loadbuffer(L, script.data(), script.size(), path.c_str());
// returning 1 object left on Lua stack:
// a function that, when called, executes the script
// (this is what lua_loadX/luaL_loadX functions return
return 1;
}
sol::stack::push(L, "This is not the module you're looking for!");
return 1;
}
int main() {
std::cout << "=== require override behavior ===" << std::endl;
sol::state lua;
// need base for print,
// need package for package/searchers/require
lua.open_libraries(sol::lib::base, sol::lib::package);
lua.clear_package_loaders( );
lua.add_package_loader(LoadFileRequire);
// this will call our function for
// the searcher and it will succeed
auto a_result = lua.safe_script(R"(
local a = require("a")
print(a)
print(test)
)", sol::script_pass_on_error);
c_assert(a_result.valid());
try {
// this will always fail
auto b_result = lua.safe_script(R"(
local b = require("b")
print(b)
)", sol::script_throw_on_error);
// this will not be executed because of the throw,
// but it better be true regardless!
c_assert(!b_result.valid());
}
catch (const std::exception& ex) {
// Whenever sol2 throws an exception from panic,
// catch
std::cout << "Something went wrong, as expected:\n" << ex.what() << std::endl;
// and CRASH / exit the application
return 0;
}
// If we get here something went wrong...!
return -1;
}

View File

@ -332,7 +332,7 @@ namespace sol {
return; return;
} }
mustindex = true; mustindex = true;
(void)detail::swallow{0, ((detail::has_derived<Bases>::value = true), 0)...}; //(void)detail::swallow{0, ((detail::has_derived<Bases>::value = true), 0)...};
static_assert(sizeof(void*) <= sizeof(detail::inheritance_check_function), "The size of this data pointer is too small to fit the inheritance checking function: Please file a bug report."); static_assert(sizeof(void*) <= sizeof(detail::inheritance_check_function), "The size of this data pointer is too small to fit the inheritance checking function: Please file a bug report.");
static_assert(sizeof(void*) <= sizeof(detail::inheritance_cast_function), "The size of this data pointer is too small to fit the inheritance checking function: Please file a bug report."); static_assert(sizeof(void*) <= sizeof(detail::inheritance_cast_function), "The size of this data pointer is too small to fit the inheritance checking function: Please file a bug report.");

View File

@ -220,6 +220,14 @@ namespace sol {
return call_syntax::colon; return call_syntax::colon;
} }
inline void script(lua_State* L, lua_Reader reader, void* data, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {
detail::typical_chunk_name_t basechunkname = {};
const char* chunknametarget = detail::make_chunk_name("lua_Reader", chunkname, basechunkname);
if (lua_load(L, reader, data, chunknametarget, to_string(mode).c_str()) || lua_pcall(L, 0, LUA_MULTRET, 0)) {
lua_error(L);
}
}
inline void script(lua_State* L, const string_view& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { inline void script(lua_State* L, const string_view& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {
detail::typical_chunk_name_t basechunkname = {}; detail::typical_chunk_name_t basechunkname = {};
const char* chunknametarget = detail::make_chunk_name(code, chunkname, basechunkname); const char* chunknametarget = detail::make_chunk_name(code, chunkname, basechunkname);

View File

@ -169,7 +169,7 @@ namespace stack {
detail::unique_tag* id = nullptr; detail::unique_tag* id = nullptr;
Real* mem = detail::usertype_unique_allocate<P, Real>(L, pref, fx, id); Real* mem = detail::usertype_unique_allocate<P, Real>(L, pref, fx, id);
*fx = detail::usertype_unique_alloc_destroy<P, Real>; *fx = detail::usertype_unique_alloc_destroy<P, Real>;
*id = &detail::inheritance<P>::type_unique_cast<Real>; *id = &detail::inheritance<P>::template type_unique_cast<Real>;
detail::default_construct::construct(mem, std::forward<Args>(args)...); detail::default_construct::construct(mem, std::forward<Args>(args)...);
*pref = unique_usertype_traits<T>::get(*mem); *pref = unique_usertype_traits<T>::get(*mem);
if (luaL_newmetatable(L, &usertype_traits<detail::unique_usertype<std::remove_cv_t<P>>>::metatable()[0]) == 1) { if (luaL_newmetatable(L, &usertype_traits<detail::unique_usertype<std::remove_cv_t<P>>>::metatable()[0]) == 1) {

View File

@ -217,11 +217,74 @@ namespace sol {
return require_core(key, action, create_global); return require_core(key, action, create_global);
} }
void clear_package_loaders( ) {
optional<table> maybe_package = this->global["package"];
if (!maybe_package) {
// package lib wasn't opened
// open package lib
return;
}
table& package = *maybe_package;
// yay for version differences...
// one day Lua 5.1 will die a peaceful death
// and its old bones will find blissful rest
auto loaders_proxy = package
#if SOL_LUA_VERSION < 502
["loaders"]
#else
["searchers"]
#endif
;
if (!loaders_proxy.valid()) {
// nothing to clear
return;
}
// we need to create the table for loaders
// table does not exist, so create and move forward
loaders_proxy = new_table(1, 0);
}
template <typename Fx>
void add_package_loader(Fx&& fx, bool clear_all_package_loaders = false) {
optional<table> maybe_package = this->global["package"];
if (!maybe_package) {
// package lib wasn't opened
// open package lib
return;
}
table& package = *maybe_package;
// yay for version differences...
// one day Lua 5.1 will die a peaceful death
// and its old bones will find blissful rest
auto loaders_proxy = package
#if SOL_LUA_VERSION < 502
["loaders"]
#else
["searchers"]
#endif
;
bool make_new_table = clear_all_package_loaders || !loaders_proxy.valid( );
if (make_new_table) {
// we need to create the table for loaders
// table does not exist, so create and move forward
loaders_proxy = new_table(1, 0);
}
optional<table> maybe_loaders = loaders_proxy;
if (!maybe_loaders) {
// loaders/searches
// thing exists in package, but it
// ain't a table or a table-alike...!
return;
}
table loaders = loaders_proxy;
loaders.add(std::forward<Fx>(fx));
}
template <typename E> template <typename E>
protected_function_result do_string(const string_view& code, const basic_environment<E>& env, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { protected_function_result do_reader(lua_Reader reader, void* data, const basic_environment<E>& env, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {
detail::typical_chunk_name_t basechunkname = {}; detail::typical_chunk_name_t basechunkname = {};
const char* chunknametarget = detail::make_chunk_name(code, chunkname, basechunkname); const char* chunknametarget = detail::make_chunk_name("lua_Reader", chunkname, basechunkname);
load_status x = static_cast<load_status>(luaL_loadbufferx(L, code.data(), code.size(), chunknametarget, to_string(mode).c_str())); load_status x = static_cast<load_status>(lua_load(L, reader, data, chunknametarget, to_string(mode).c_str()));
if (x != load_status::ok) { if (x != load_status::ok) {
return protected_function_result(L, absolute_index(L, -1), 0, 1, static_cast<call_status>(x)); return protected_function_result(L, absolute_index(L, -1), 0, 1, static_cast<call_status>(x));
} }
@ -230,9 +293,22 @@ namespace sol {
return pf(); return pf();
} }
protected_function_result do_reader(lua_Reader reader, void* data, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {
detail::typical_chunk_name_t basechunkname = {};
const char* chunknametarget = detail::make_chunk_name("lua_Reader", chunkname, basechunkname);
load_status x = static_cast<load_status>(lua_load(L, reader, data, chunknametarget, to_string(mode).c_str()));
if (x != load_status::ok) {
return protected_function_result(L, absolute_index(L, -1), 0, 1, static_cast<call_status>(x));
}
stack_aligned_protected_function pf(L, -1);
return pf();
}
template <typename E> template <typename E>
protected_function_result do_file(const std::string& filename, const basic_environment<E>& env, load_mode mode = load_mode::any) { protected_function_result do_string(const string_view& code, const basic_environment<E>& env, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {
load_status x = static_cast<load_status>(luaL_loadfilex(L, filename.c_str(), to_string(mode).c_str())); detail::typical_chunk_name_t basechunkname = {};
const char* chunknametarget = detail::make_chunk_name(code, chunkname, basechunkname);
load_status x = static_cast<load_status>(luaL_loadbufferx(L, code.data(), code.size(), chunknametarget, to_string(mode).c_str()));
if (x != load_status::ok) { if (x != load_status::ok) {
return protected_function_result(L, absolute_index(L, -1), 0, 1, static_cast<call_status>(x)); return protected_function_result(L, absolute_index(L, -1), 0, 1, static_cast<call_status>(x));
} }
@ -252,6 +328,17 @@ namespace sol {
return pf(); return pf();
} }
template <typename E>
protected_function_result do_file(const std::string& filename, const basic_environment<E>& env, load_mode mode = load_mode::any) {
load_status x = static_cast<load_status>(luaL_loadfilex(L, filename.c_str(), to_string(mode).c_str()));
if (x != load_status::ok) {
return protected_function_result(L, absolute_index(L, -1), 0, 1, static_cast<call_status>(x));
}
stack_aligned_protected_function pf(L, -1);
set_environment(env, pf);
return pf();
}
protected_function_result do_file(const std::string& filename, load_mode mode = load_mode::any) { protected_function_result do_file(const std::string& filename, load_mode mode = load_mode::any) {
load_status x = static_cast<load_status>(luaL_loadfilex(L, filename.c_str(), to_string(mode).c_str())); load_status x = static_cast<load_status>(luaL_loadfilex(L, filename.c_str(), to_string(mode).c_str()));
if (x != load_status::ok) { if (x != load_status::ok) {
@ -261,6 +348,19 @@ namespace sol {
return pf(); return pf();
} }
template <typename Fx, meta::disable_any<meta::is_string_constructible<meta::unqualified_t<Fx>>, meta::is_specialization_of<meta::unqualified_t<Fx>, basic_environment>> = meta::enabler>
protected_function_result safe_script(lua_Reader reader, void* data, Fx&& on_error, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {
protected_function_result pfr = do_reader(reader, data, chunkname, mode);
if (!pfr.valid()) {
return on_error(L, std::move(pfr));
}
return pfr;
}
protected_function_result safe_script(lua_Reader reader, void* data, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {
return safe_script(reader, data, script_default_on_error, chunkname, mode);
}
template <typename Fx, meta::disable_any<meta::is_string_constructible<meta::unqualified_t<Fx>>, meta::is_specialization_of<meta::unqualified_t<Fx>, basic_environment>> = meta::enabler> template <typename Fx, meta::disable_any<meta::is_string_constructible<meta::unqualified_t<Fx>>, meta::is_specialization_of<meta::unqualified_t<Fx>, basic_environment>> = meta::enabler>
protected_function_result safe_script(const string_view& code, Fx&& on_error, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { protected_function_result safe_script(const string_view& code, Fx&& on_error, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {
protected_function_result pfr = do_string(code, chunkname, mode); protected_function_result pfr = do_string(code, chunkname, mode);
@ -315,6 +415,31 @@ namespace sol {
return safe_script_file(filename, script_default_on_error, mode); return safe_script_file(filename, script_default_on_error, mode);
} }
template <typename E>
unsafe_function_result unsafe_script(lua_Reader reader, void* data, const basic_environment<E>& env, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {
detail::typical_chunk_name_t basechunkname = {};
const char* chunknametarget = detail::make_chunk_name("lua_Reader", chunkname, basechunkname);
int index = lua_gettop(L);
if (lua_load(L, reader, data, chunknametarget, to_string(mode).c_str())) {
lua_error(L);
}
set_environment(env, stack_reference(L, raw_index(index + 1)));
if (lua_pcall(L, 0, LUA_MULTRET, 0)) {
lua_error(L);
}
int postindex = lua_gettop(L);
int returns = postindex - index;
return unsafe_function_result(L, (std::max)(postindex - (returns - 1), 1), returns);
}
unsafe_function_result unsafe_script(lua_Reader reader, void* data, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {
int index = lua_gettop(L);
stack::script(L, reader, data, chunkname, mode);
int postindex = lua_gettop(L);
int returns = postindex - index;
return unsafe_function_result(L, (std::max)(postindex - (returns - 1), 1), returns);
}
template <typename E> template <typename E>
unsafe_function_result unsafe_script(const string_view& code, const basic_environment<E>& env, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { unsafe_function_result unsafe_script(const string_view& code, const basic_environment<E>& env, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {
detail::typical_chunk_name_t basechunkname = {}; detail::typical_chunk_name_t basechunkname = {};
@ -392,6 +517,10 @@ namespace sol {
} }
#if defined(SOL_SAFE_FUNCTION) && SOL_SAFE_FUNCTION #if defined(SOL_SAFE_FUNCTION) && SOL_SAFE_FUNCTION
protected_function_result script(lua_Reader reader, void* data, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {
return safe_script(reader, data, chunkname, mode);
}
protected_function_result script(const string_view& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { protected_function_result script(const string_view& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {
return safe_script(code, chunkname, mode); return safe_script(code, chunkname, mode);
} }
@ -448,6 +577,12 @@ namespace sol {
} }
global_table globals() const { global_table globals() const {
// if we return a reference
// we'll be screwed a bit
return global;
}
global_table& globals() {
return global; return global;
} }

View File

@ -147,7 +147,7 @@ TEST_CASE("customization/split struct", "using the newly documented customizatio
REQUIRE(d == 36.5); REQUIRE(d == 36.5);
} }
TEST_CASE("customization/get_ check_usertype", "using the newly documented customization points to handle different kinds of classes") { TEST_CASE("customization/usertype", "using the newly documented customization points to handle different kinds of classes") {
sol::state lua; sol::state lua;
// Create a pass-through style of function // Create a pass-through style of function
@ -168,3 +168,17 @@ TEST_CASE("customization/get_ check_usertype", "using the newly documented custo
REQUIRE(thingsf.num == 25); REQUIRE(thingsf.num == 25);
REQUIRE(thingsg.num == 35); REQUIRE(thingsg.num == 35);
} }
TEST_CASE("customization/overloading", "using multi-size customized types in an overload") {
bool TwoThingsWorks = false, OverloadWorks = false;
sol::state lua;
lua["test_two_things"] = [&](two_things) { TwoThingsWorks = true; };
lua["test_overload"] = sol::overload([&](two_things) { OverloadWorks = true; }, [] {});
lua.script(
"test_two_things(0, true)\n"
"test_overload(0, true)");
REQUIRE(TwoThingsWorks);
REQUIRE(OverloadWorks);
}