diff --git a/README.md b/README.md index 2d02e0c..ef6b209 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,8 @@ library. It aims to package all the features accessible through the C API in a modern C++ interface that is easy to use, while keeping the overhead to a minimum. +* [Current state](#current-state) +* [Philosophy](#philosophy) * [Building](#building) * [Wrenpp](#wrenpp) * [Wren only](#wren-only) @@ -13,6 +15,29 @@ minimum. * [C++](#c) * [Header files](#header-files) * [Initialisation](#initialisation) + * [Foreign functions](#foreign-functions) +* [Implementation](#implementation) + +## Current state ## + +The library is functional and provides access to most of the features of Wren. +Some are better tested than others. There are no known memory leaks. Please +keep in mind this is an early version and more testing and work will be needed. + +## Philosophy ## + +The overall principle behind this wrapper is to be feature rich while also +being lightweight and allowing fine-grained control for users who need it. + +By design, wrenpp hides the Wren C API entirely, but all functions (considered +"low level" relative to this wrapper) are still accessible through the `VM` +class. If the function you need is not available there it's probably just +missing and adding it should be a trivial task. + +Wrenpp provides you with convenience functions in `vm_fun.hpp` that are built +on top of the `VM` class and make basic use of Wren simpler. You're still free +to "mix & match" higher level functions with lower level ones, and you can +decide to not use portions of the wrapper entirely. ## Building ## @@ -39,6 +64,12 @@ The build scripts understand the following options (double check in [random](http://wren.io/modules/random/) support 5. `wren_with_meta` set to true to compile Wren with [meta](http://wren.io/modules/meta/) support +6. `wrenpp_with_name_guessing` enable class name guessing in c++ code. It + currently affects only example code and header files, not the library + itself. It controls the `WRENPP_WITH_NAME_GUESSING` preprocessor symbol. + When it's defined, you will have access to better error reporting and extra + functions, such as a `make_wren_object()` overload that doesn't require you + to specify a string class name. Note that some example projects require random support in Wren, without which they will crash. If you want to run examples or you are getting "Address @@ -112,6 +143,8 @@ meson wrap promote subprojects/wrenpp/subprojects/wren ### C++ ### For working examples refer to the source files in the `examples/` directory. +"Greet" is the simplest example, while "math_vector" is showing off more +features. #### Header files #### @@ -155,4 +188,87 @@ int main() { } ``` +#### Foreign functions #### + +You have two options to register foreign functions with wrenpp: the easiest one +is to just use the callback manager available through the `VM` object: + +``` +#include +#include +#include //necessary if you want to use the callback manager + +int main() { + wren::DefConfiguration config; + wren::VM vm(&config, nullptr); + + vm.callback_manager() + .add_callback(true, "your_module", "YourClass", "your_method(_,_)", &your_method); + + vm.interpret("main", your_fun_script_here); + return 0; +} +``` + +The current implementation available in `DefConfiguration` registers a callback +to Wren that looks up a `std::unordered_map` for the correct c++ function and +then forwards the call to it. This should be good enough for most cases, +however you are free to provide your own callback for wren by writing your own +Configuration class. Wrenpp tries to not impose you any particular helper code, +in fact if you don't wish to use the `CallbackManager` returned by +`vm.callback_manager()` then you don't even need to include the relative header +file! There will still be a `std::unordered_map` in memory (because that's +owned by `vm`) but it will never be used. + +The second method requires you to provide the full Wren foreign functions +callback: + +``` +#include +#include + +class MyConf : public wren::DefConfiguration { +public: + //This is the callback that Wren will call, refer to the C API documentation + //for more details. + wren::foreign_method_t foreign_method_fn( + wren::VM* vm, + std::string_view module, + std::string_view class_name, + bool is_static, + std::string_view signature + ) { + if (module == "your_module" and class_name == "YourClass") { + if (is_static and signature == "your_method(_,_)") + return &your_method; + } + return nullptr; + } +} + +int main() { + MyConf config; + wren::VM vm(&config, nullptr); + + vm.interpret("main", your_fun_script_here); + return 0; +} +``` + +The above code is very close to what you'd do with the C API. If you need, you +can even pass a user data pointer to the `VM` constructor (`nullptr` in this +snippet) and retrieve it later from within `foreign_method_fn()` via +`vm.void_user_data()` or `vm.user_data()`. You're unlikely to need it as, as +you can see, `foreign_method_fn()` is not static and so you can have some state +stored in your `MyConf` object, however you still get the chance to use the +C-like user data mechanism if you wish to. + +Note that for the above to work the `foreign_method_fn()` method in `MyConf` +must be named exactly like that, and the signature must match (except for the +`static` and `const` keywords). Ideally the code above should alse be +`noexcept` as there will be C code in the call stack when that method is +invoked. + +## Implementation ## + *Work in progress*