mirror of
https://github.com/ThePhD/sol2.git
synced 2024-03-22 13:10:44 +08:00
update docs a bit, think aobut changes to container_traits and friends...
This commit is contained in:
parent
cf1376cd06
commit
0e321272e6
|
@ -72,6 +72,9 @@ You can use the individual load and function call operator to load, check, and t
|
|||
:linenos:
|
||||
: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
|
||||
---------------------
|
||||
|
||||
|
@ -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:`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
|
||||
.. _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
|
||||
|
|
95
examples/custom_reader.cpp
Normal file
95
examples/custom_reader.cpp
Normal 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;
|
||||
}
|
76
examples/require_override_behavior.cpp
Normal file
76
examples/require_override_behavior.cpp
Normal 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;
|
||||
}
|
|
@ -332,7 +332,7 @@ namespace sol {
|
|||
return;
|
||||
}
|
||||
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_cast_function), "The size of this data pointer is too small to fit the inheritance checking function: Please file a bug report.");
|
||||
|
|
|
@ -220,6 +220,14 @@ namespace sol {
|
|||
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) {
|
||||
detail::typical_chunk_name_t basechunkname = {};
|
||||
const char* chunknametarget = detail::make_chunk_name(code, chunkname, basechunkname);
|
||||
|
|
|
@ -169,7 +169,7 @@ namespace stack {
|
|||
detail::unique_tag* id = nullptr;
|
||||
Real* mem = detail::usertype_unique_allocate<P, Real>(L, pref, fx, id);
|
||||
*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)...);
|
||||
*pref = unique_usertype_traits<T>::get(*mem);
|
||||
if (luaL_newmetatable(L, &usertype_traits<detail::unique_usertype<std::remove_cv_t<P>>>::metatable()[0]) == 1) {
|
||||
|
|
|
@ -217,11 +217,74 @@ namespace sol {
|
|||
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>
|
||||
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 = {};
|
||||
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()));
|
||||
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));
|
||||
}
|
||||
|
@ -230,9 +293,22 @@ namespace sol {
|
|||
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>
|
||||
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()));
|
||||
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) {
|
||||
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) {
|
||||
return protected_function_result(L, absolute_index(L, -1), 0, 1, static_cast<call_status>(x));
|
||||
}
|
||||
|
@ -252,6 +328,17 @@ namespace sol {
|
|||
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) {
|
||||
load_status x = static_cast<load_status>(luaL_loadfilex(L, filename.c_str(), to_string(mode).c_str()));
|
||||
if (x != load_status::ok) {
|
||||
|
@ -261,6 +348,19 @@ namespace sol {
|
|||
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>
|
||||
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);
|
||||
|
@ -315,6 +415,31 @@ namespace sol {
|
|||
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>
|
||||
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 = {};
|
||||
|
@ -392,6 +517,10 @@ namespace sol {
|
|||
}
|
||||
|
||||
#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) {
|
||||
return safe_script(code, chunkname, mode);
|
||||
}
|
||||
|
@ -448,6 +577,12 @@ namespace sol {
|
|||
}
|
||||
|
||||
global_table globals() const {
|
||||
// if we return a reference
|
||||
// we'll be screwed a bit
|
||||
return global;
|
||||
}
|
||||
|
||||
global_table& globals() {
|
||||
return global;
|
||||
}
|
||||
|
||||
|
|
|
@ -147,7 +147,7 @@ TEST_CASE("customization/split struct", "using the newly documented customizatio
|
|||
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;
|
||||
|
||||
// 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(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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user