init
This commit is contained in:
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
cmake-*/
|
||||||
|
build/
|
||||||
|
.idea/
|
||||||
|
|
||||||
36
CMakeLists.txt
Normal file
36
CMakeLists.txt
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
|
||||||
|
project(mrubypp LANGUAGES CXX)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
|
if (MSVC)
|
||||||
|
add_compile_options("$<$<C_COMPILER_ID:MSVC>:/utf-8>")
|
||||||
|
add_compile_options("$<$<CXX_COMPILER_ID:MSVC>:/utf-8>")
|
||||||
|
add_compile_definitions(NOMINMAX)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
add_executable(mrubypp main.cpp
|
||||||
|
mrubypp.h
|
||||||
|
mrubypp_converters.h
|
||||||
|
mrubypp_arena_guard.h
|
||||||
|
mrubypp_bind_class.h
|
||||||
|
example/Point.cpp
|
||||||
|
example/Point.h)
|
||||||
|
|
||||||
|
|
||||||
|
set(mruby_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/deps/mruby")
|
||||||
|
target_include_directories(mrubypp PUBLIC "${mruby_ROOT}/include")
|
||||||
|
target_link_directories(mrubypp PUBLIC "${mruby_ROOT}/lib")
|
||||||
|
target_link_libraries(mrubypp PUBLIC
|
||||||
|
libmruby
|
||||||
|
ws2_32.lib wsock32.lib ws2_32.lib)
|
||||||
|
|
||||||
|
include_directories(${CMAKE_CURRENT_LIST_DIR})
|
||||||
|
|
||||||
|
include(GNUInstallDirs)
|
||||||
|
install(TARGETS mrubypp
|
||||||
|
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||||
|
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||||
|
)
|
||||||
5
example/Point.cpp
Normal file
5
example/Point.cpp
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
//
|
||||||
|
// Created by ZekeXiao on 2025/10/18.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "Point.h"
|
||||||
58
example/Point.h
Normal file
58
example/Point.h
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
//
|
||||||
|
// Created by ZekeXiao on 2025/10/18.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef MRUBYPP_POINT_H
|
||||||
|
#define MRUBYPP_POINT_H
|
||||||
|
|
||||||
|
#include "mrubypp_converters.h"
|
||||||
|
|
||||||
|
#include "mruby/data.h"
|
||||||
|
|
||||||
|
#include "mrubypp_bind_class.h"
|
||||||
|
|
||||||
|
class Point {
|
||||||
|
public:
|
||||||
|
Point(int x, int y) : x_(x), y_(y) {}
|
||||||
|
|
||||||
|
void set_values(int x, int y) {
|
||||||
|
x_ = x;
|
||||||
|
y_ = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_x() const { return x_; }
|
||||||
|
void set_x(int x) { x_ = x; }
|
||||||
|
|
||||||
|
int get_y() const { return y_; }
|
||||||
|
void set_y(int y) { y_ = y; }
|
||||||
|
|
||||||
|
void add(const Point &other) {
|
||||||
|
this->x_ += other.x_;
|
||||||
|
this->y_ += other.y_;
|
||||||
|
}
|
||||||
|
static int none() { return 1; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
int x_;
|
||||||
|
int y_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <> struct mrubypp_converter<Point> {
|
||||||
|
static mrb_value to_mrb(mrb_state *mrb, const Point &var) {
|
||||||
|
// 创建一个新的 Point 对象数据结构
|
||||||
|
mrb_value obj = mrb_obj_value(
|
||||||
|
mrb_data_object_alloc(mrb, mrb->object_class, new Point(var),
|
||||||
|
&mrubypp_class_builder<Point>::data_type));
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Point from_mrb(mrb_state *mrb, mrb_value value) {
|
||||||
|
// 从 mrb_value 中提取 Point 对象
|
||||||
|
if (mrb_type(value) == MRB_TT_DATA) {
|
||||||
|
Point *point = static_cast<Point *>(DATA_PTR(value));
|
||||||
|
return *point;
|
||||||
|
}
|
||||||
|
return Point(0, 0); // 默认构造
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif // MRUBYPP_POINT_H
|
||||||
60
main.cpp
Normal file
60
main.cpp
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
#include "example/Point.h"
|
||||||
|
#include "mrubypp.h"
|
||||||
|
#include "mrubypp_bind_class.h"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#endif
|
||||||
|
int main() {
|
||||||
|
#ifdef _WIN32
|
||||||
|
SetConsoleOutputCP(CP_UTF8);
|
||||||
|
#endif
|
||||||
|
mrubypp engine;
|
||||||
|
engine.load(R"(
|
||||||
|
def add(a)
|
||||||
|
a.sort!
|
||||||
|
a[0]
|
||||||
|
end)");
|
||||||
|
|
||||||
|
std::vector<int> a{3, 1, 2};
|
||||||
|
static volatile int b = 0;
|
||||||
|
std::chrono::steady_clock::time_point start =
|
||||||
|
std::chrono::steady_clock::now();
|
||||||
|
for (auto i = 0; i < 10000; ++i) {
|
||||||
|
b = engine.call<int>("add", a);
|
||||||
|
assert(b == 1);
|
||||||
|
}
|
||||||
|
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
|
||||||
|
auto duration =
|
||||||
|
std::chrono::duration_cast<std::chrono::milliseconds>(end - start)
|
||||||
|
.count();
|
||||||
|
std::cout << "10000 ruby call duration: " << duration << "ms" << std::endl;
|
||||||
|
|
||||||
|
engine.class_builder<Point>("Point")
|
||||||
|
.def_constructor<int, int>()
|
||||||
|
.def_method("add", &Point::add)
|
||||||
|
.def_class_method("none", &Point::none)
|
||||||
|
.def_property("x", &Point::get_x, &Point::set_x);
|
||||||
|
|
||||||
|
engine.load(R"(
|
||||||
|
def test_point()
|
||||||
|
p = Point.new(3, 4)
|
||||||
|
p.x = 10
|
||||||
|
p.add(p)
|
||||||
|
p.x += Point::none()
|
||||||
|
return p
|
||||||
|
end
|
||||||
|
)");
|
||||||
|
|
||||||
|
// 调用test_point函数
|
||||||
|
auto point_result = engine.call<Point>("test_point");
|
||||||
|
std::cout << "returned point: [" << point_result.get_x() << ", "
|
||||||
|
<< point_result.get_y() << "]" << std::endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
52
mrubypp.h
Normal file
52
mrubypp.h
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
#ifndef MRUBYPP_H
|
||||||
|
#define MRUBYPP_H
|
||||||
|
|
||||||
|
#include "mrubypp_arena_guard.h"
|
||||||
|
#include "mrubypp_bind_class.h"
|
||||||
|
#include "mrubypp_converters.h"
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <mruby.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <mruby/compile.h>
|
||||||
|
|
||||||
|
// 支持自定义类型注册
|
||||||
|
class mrubypp {
|
||||||
|
public:
|
||||||
|
mrubypp() { mrb = mrb_open(); }
|
||||||
|
~mrubypp() { mrb_close(mrb); }
|
||||||
|
void load(const std::string &str) {
|
||||||
|
if (!mrb)
|
||||||
|
return;
|
||||||
|
mrb_load_string(mrb, str.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> T call(const std::string &funcName) {
|
||||||
|
mrubypp_arena_guard guard(mrb);
|
||||||
|
mrb_value result = mrb_funcall(mrb, mrb_top_self(mrb), funcName.data(), 0);
|
||||||
|
return mrubypp_converter<T>::from_mrb(mrb, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename... Args>
|
||||||
|
T call(const std::string &funcName, Args... args) {
|
||||||
|
mrubypp_arena_guard guard(mrb);
|
||||||
|
mrb_value argv[] = {mrubypp_converter<Args>::to_mrb(mrb, args)...};
|
||||||
|
mrb_sym sym = mrb_intern_cstr(mrb, funcName.data());
|
||||||
|
mrb_value result =
|
||||||
|
mrb_funcall_argv(mrb, mrb_top_self(mrb), sym, sizeof...(Args), argv);
|
||||||
|
return mrubypp_converter<T>::from_mrb(mrb, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
mrubypp_class_builder<T> class_builder(const std::string &class_name) {
|
||||||
|
return mrubypp_class_builder<T>(mrb, class_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] mrb_state *get_mrb() const { return mrb; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
mrb_state *mrb;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // MRUBYPP_H
|
||||||
26
mrubypp_arena_guard.h
Normal file
26
mrubypp_arena_guard.h
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
//
|
||||||
|
// Created by ZekeXiao on 2025/10/17.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef MRUBYPP_MRUBYPP_UTILS_H
|
||||||
|
#define MRUBYPP_MRUBYPP_UTILS_H
|
||||||
|
|
||||||
|
#include <mruby.h>
|
||||||
|
|
||||||
|
class mrubypp_arena_guard {
|
||||||
|
public:
|
||||||
|
explicit mrubypp_arena_guard(mrb_state *mrb) : mrb(mrb) {
|
||||||
|
ai = mrb_gc_arena_save(mrb);
|
||||||
|
}
|
||||||
|
mrubypp_arena_guard(mrubypp_arena_guard &&other) = delete;
|
||||||
|
mrubypp_arena_guard(const mrubypp_arena_guard &other) = delete;
|
||||||
|
~mrubypp_arena_guard() { mrb_gc_arena_restore(mrb, ai); }
|
||||||
|
|
||||||
|
// arena_idx
|
||||||
|
[[nodiscard]] int get_ai() const { return ai; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
mrb_state *mrb;
|
||||||
|
int ai;
|
||||||
|
};
|
||||||
|
#endif // MRUBYPP_MRUBYPP_UTILS_H
|
||||||
260
mrubypp_bind_class.h
Normal file
260
mrubypp_bind_class.h
Normal file
@@ -0,0 +1,260 @@
|
|||||||
|
#ifndef MRUBYPP_BIND_CLASS
|
||||||
|
#define MRUBYPP_BIND_CLASS
|
||||||
|
|
||||||
|
#include "mrubypp_arena_guard.h"
|
||||||
|
#include "mrubypp_converters.h"
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <mruby/class.h>
|
||||||
|
#include <mruby/data.h>
|
||||||
|
|
||||||
|
template <typename... Args, size_t... Is>
|
||||||
|
std::tuple<Args...> mrubypp_get_args_helper_impl(mrb_state *mrb,
|
||||||
|
const mrb_value *argv,
|
||||||
|
std::index_sequence<Is...>) {
|
||||||
|
return std::make_tuple(
|
||||||
|
mrubypp_converter<typename std::decay<Args>::type>::from_mrb(
|
||||||
|
mrb, argv[Is])...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
std::tuple<typename std::decay<Args>::type...>
|
||||||
|
mrubypp_get_args_helper(mrb_state *mrb) {
|
||||||
|
mrubypp_arena_guard guard(mrb);
|
||||||
|
auto argc = mrb_get_argc(mrb);
|
||||||
|
auto argv = mrb_get_argv(mrb);
|
||||||
|
|
||||||
|
if (argc != sizeof...(Args)) {
|
||||||
|
mrb_raise(mrb, E_ARGUMENT_ERROR, "argument count mismatch");
|
||||||
|
}
|
||||||
|
|
||||||
|
return mrubypp_get_args_helper_impl<typename std::decay<Args>::type...>(
|
||||||
|
mrb, argv, std::index_sequence_for<Args...>{});
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename Ret, typename... MethodArgs>
|
||||||
|
struct mrubypp_method_wrapper {
|
||||||
|
static Ret (T::*method)(MethodArgs...);
|
||||||
|
|
||||||
|
static mrb_value wrapper(mrb_state *mrb, mrb_value self) {
|
||||||
|
auto args = mrubypp_get_args_helper<MethodArgs...>(mrb);
|
||||||
|
T *instance = static_cast<T *>(DATA_PTR(self));
|
||||||
|
if (!instance) {
|
||||||
|
mrb_raise(mrb, E_RUNTIME_ERROR, "Invalid instance");
|
||||||
|
}
|
||||||
|
|
||||||
|
if constexpr (std::is_same_v<Ret, void>) {
|
||||||
|
std::apply(method, std::tuple_cat(std::make_tuple(instance), args));
|
||||||
|
return mrb_nil_value();
|
||||||
|
} else {
|
||||||
|
Ret result =
|
||||||
|
std::apply(method, std::tuple_cat(std::make_tuple(instance), args));
|
||||||
|
return mrubypp_converter<Ret>::to_mrb(mrb, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename Ret, typename... MethodArgs>
|
||||||
|
struct mrubypp_const_method_wrapper {
|
||||||
|
static Ret (T::*method)(MethodArgs...) const;
|
||||||
|
|
||||||
|
static mrb_value wrapper(mrb_state *mrb, mrb_value self) {
|
||||||
|
auto args = mrubypp_get_args_helper<MethodArgs...>(mrb);
|
||||||
|
T *instance = static_cast<T *>(DATA_PTR(self));
|
||||||
|
if (!instance) {
|
||||||
|
mrb_raise(mrb, E_RUNTIME_ERROR, "Invalid instance");
|
||||||
|
}
|
||||||
|
|
||||||
|
if constexpr (std::is_same_v<Ret, void>) {
|
||||||
|
std::apply(method, std::tuple_cat(std::make_tuple(instance), args));
|
||||||
|
return mrb_nil_value();
|
||||||
|
} else {
|
||||||
|
Ret result =
|
||||||
|
std::apply(method, std::tuple_cat(std::make_tuple(instance), args));
|
||||||
|
return mrubypp_converter<Ret>::to_mrb(mrb, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Ret, typename... FuncArgs> struct mrubypp_function_wrapper {
|
||||||
|
static Ret (*func)(FuncArgs...);
|
||||||
|
|
||||||
|
static mrb_value wrapper(mrb_state *mrb, mrb_value self) {
|
||||||
|
auto args = mrubypp_get_args_helper<FuncArgs...>(mrb);
|
||||||
|
if constexpr (std::is_same_v<Ret, void>) {
|
||||||
|
std::apply(func, args);
|
||||||
|
return mrb_nil_value();
|
||||||
|
} else {
|
||||||
|
Ret result = std::apply(func, args);
|
||||||
|
return mrubypp_converter<Ret>::to_mrb(mrb, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename Ret> struct mrubypp_getter_wrapper {
|
||||||
|
static Ret (T::*getter)() const;
|
||||||
|
|
||||||
|
static mrb_value wrapper(mrb_state *mrb, mrb_value self) {
|
||||||
|
T *instance = static_cast<T *>(DATA_PTR(self));
|
||||||
|
if (!instance) {
|
||||||
|
mrb_raise(mrb, E_RUNTIME_ERROR, "Invalid instance");
|
||||||
|
}
|
||||||
|
|
||||||
|
Ret result = (instance->*getter)();
|
||||||
|
return mrubypp_converter<Ret>::to_mrb(mrb, result);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename Ret> struct mrubypp_setter_wrapper {
|
||||||
|
static void (T::*setter)(Ret);
|
||||||
|
|
||||||
|
static mrb_value wrapper(mrb_state *mrb, mrb_value self) {
|
||||||
|
auto args = mrubypp_get_args_helper<Ret>(mrb);
|
||||||
|
T *instance = static_cast<T *>(DATA_PTR(self));
|
||||||
|
if (!instance) {
|
||||||
|
mrb_raise(mrb, E_RUNTIME_ERROR, "Invalid instance");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::apply(setter, std::tuple_cat(std::make_tuple(instance), args));
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
template <typename T> class mrubypp_class_builder;
|
||||||
|
|
||||||
|
template <typename T, typename... Args> struct mrubypp_constructor_wrapper {
|
||||||
|
static mrb_value wrapper(mrb_state *mrb, mrb_value self) {
|
||||||
|
auto args = mrubypp_get_args_helper<Args...>(mrb);
|
||||||
|
T *instance = std::apply([](Args... args) { return new T(args...); }, args);
|
||||||
|
|
||||||
|
DATA_PTR(self) = instance;
|
||||||
|
DATA_TYPE(self) = &mrubypp_class_builder<T>::data_type;
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T> class mrubypp_class_builder {
|
||||||
|
private:
|
||||||
|
mrb_state *mrb_;
|
||||||
|
struct RClass *rclass_;
|
||||||
|
std::string name_;
|
||||||
|
|
||||||
|
static void free_instance(mrb_state *mrb, void *ptr) {
|
||||||
|
if (ptr) {
|
||||||
|
T *instance = static_cast<T *>(ptr);
|
||||||
|
delete instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
static const struct mrb_data_type data_type;
|
||||||
|
|
||||||
|
mrubypp_class_builder(mrb_state *mrb, std::string name)
|
||||||
|
: mrb_(mrb), name_(std::move(name)) {
|
||||||
|
rclass_ = mrb_define_class(mrb_, name_.c_str(), mrb_->object_class);
|
||||||
|
MRB_SET_INSTANCE_TT(rclass_, MRB_TT_DATA);
|
||||||
|
|
||||||
|
mrb_define_method(
|
||||||
|
mrb_, rclass_, "initialize",
|
||||||
|
[](mrb_state *mrb, mrb_value self) -> mrb_value {
|
||||||
|
mrb_raise(mrb, E_NOTIMP_ERROR,
|
||||||
|
"Initialize must be defined explicitly");
|
||||||
|
return self;
|
||||||
|
},
|
||||||
|
MRB_ARGS_ANY());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args> mrubypp_class_builder &def_constructor() {
|
||||||
|
mrb_define_method(mrb_, rclass_, "initialize",
|
||||||
|
&mrubypp_constructor_wrapper<T, Args...>::wrapper,
|
||||||
|
MRB_ARGS_REQ(sizeof...(Args)));
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Ret, typename... MethodArgs>
|
||||||
|
mrubypp_class_builder &def_method(const std::string &name,
|
||||||
|
Ret (T::*method)(MethodArgs...)) {
|
||||||
|
mrubypp_method_wrapper<T, Ret, MethodArgs...>::method = method;
|
||||||
|
|
||||||
|
mrb_define_method(mrb_, rclass_, name.c_str(),
|
||||||
|
&mrubypp_method_wrapper<T, Ret, MethodArgs...>::wrapper,
|
||||||
|
MRB_ARGS_REQ(sizeof...(MethodArgs)));
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Ret, typename... MethodArgs>
|
||||||
|
mrubypp_class_builder &def_method(const std::string &name,
|
||||||
|
Ret (T::*method)(MethodArgs...) const) {
|
||||||
|
mrubypp_const_method_wrapper<T, Ret, MethodArgs...>::method = method;
|
||||||
|
|
||||||
|
mrb_define_method(
|
||||||
|
mrb_, rclass_, name.c_str(),
|
||||||
|
&mrubypp_const_method_wrapper<T, Ret, MethodArgs...>::wrapper,
|
||||||
|
MRB_ARGS_REQ(sizeof...(MethodArgs)));
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Ret, typename... FuncArgs>
|
||||||
|
mrubypp_class_builder &def_class_method(const std::string &name,
|
||||||
|
Ret (*func)(FuncArgs...)) {
|
||||||
|
mrubypp_function_wrapper<Ret, FuncArgs...>::func = func;
|
||||||
|
|
||||||
|
mrb_define_class_method(
|
||||||
|
mrb_, rclass_, name.c_str(),
|
||||||
|
&mrubypp_function_wrapper<Ret, FuncArgs...>::wrapper,
|
||||||
|
MRB_ARGS_REQ(sizeof...(FuncArgs)));
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Ret, typename... MethodArgs>
|
||||||
|
mrubypp_class_builder &def_property(const std::string &name,
|
||||||
|
Ret (T::*getter)() const,
|
||||||
|
void (T::*setter)(Ret)) {
|
||||||
|
mrubypp_getter_wrapper<T, Ret>::getter = getter;
|
||||||
|
mrb_define_method(mrb_, rclass_, name.c_str(),
|
||||||
|
&mrubypp_getter_wrapper<T, Ret>::wrapper,
|
||||||
|
MRB_ARGS_NONE());
|
||||||
|
|
||||||
|
std::string setter_name = name + "=";
|
||||||
|
mrubypp_setter_wrapper<T, Ret>::setter = setter;
|
||||||
|
mrb_define_method(mrb_, rclass_, setter_name.c_str(),
|
||||||
|
&mrubypp_setter_wrapper<T, Ret>::wrapper,
|
||||||
|
MRB_ARGS_REQ(1));
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] struct RClass *get_rclass() const { return rclass_; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
const struct mrb_data_type mrubypp_class_builder<T>::data_type = {
|
||||||
|
typeid(T).name(), mrubypp_class_builder<T>::free_instance
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename Ret, typename... MethodArgs>
|
||||||
|
Ret (T::*mrubypp_method_wrapper<T, Ret, MethodArgs...>::method)(MethodArgs...);
|
||||||
|
|
||||||
|
template <typename T, typename Ret, typename... MethodArgs>
|
||||||
|
Ret (T::*mrubypp_const_method_wrapper<T, Ret, MethodArgs...>::method)(
|
||||||
|
MethodArgs...) const;
|
||||||
|
|
||||||
|
template <typename Ret, typename... FuncArgs>
|
||||||
|
Ret (*mrubypp_function_wrapper<Ret, FuncArgs...>::func)(FuncArgs...);
|
||||||
|
|
||||||
|
template <typename T, typename Ret>
|
||||||
|
Ret (T::*mrubypp_getter_wrapper<T, Ret>::getter)() const;
|
||||||
|
|
||||||
|
template <typename T, typename Ret>
|
||||||
|
void (T::*mrubypp_setter_wrapper<T, Ret>::setter)(Ret);
|
||||||
|
|
||||||
|
#endif
|
||||||
87
mrubypp_converters.h
Normal file
87
mrubypp_converters.h
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
#ifndef MRUBYPP_STD_CONVERTERS_H
|
||||||
|
#define MRUBYPP_STD_CONVERTERS_H
|
||||||
|
|
||||||
|
#include "mrubypp_arena_guard.h"
|
||||||
|
|
||||||
|
#include <mruby.h>
|
||||||
|
#include <mruby/array.h>
|
||||||
|
#include <mruby/string.h>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
template <typename T> struct mrubypp_converter {
|
||||||
|
static mrb_value to_mrb(mrb_state *mrb, const T &var) {
|
||||||
|
static_assert(sizeof(T) == 0, "Specialization required");
|
||||||
|
return mrb_nil_value();
|
||||||
|
}
|
||||||
|
static T from_mrb(mrb_state *mrb, mrb_value value) {
|
||||||
|
static_assert(sizeof(T) == 0, "Specialization required");
|
||||||
|
return T();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <> struct mrubypp_converter<int> {
|
||||||
|
static mrb_value to_mrb(mrb_state *mrb, int var) {
|
||||||
|
return mrb_fixnum_value(var);
|
||||||
|
}
|
||||||
|
static int from_mrb(mrb_state *mrb, mrb_value value) {
|
||||||
|
return mrb_fixnum(value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <> struct mrubypp_converter<float> {
|
||||||
|
static mrb_value to_mrb(mrb_state *mrb, float var) {
|
||||||
|
return mrb_float_value(mrb, var);
|
||||||
|
}
|
||||||
|
static double from_mrb(mrb_state *mrb, mrb_value value) {
|
||||||
|
return mrb_float(value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <> struct mrubypp_converter<double> {
|
||||||
|
static mrb_value to_mrb(mrb_state *mrb, double var) {
|
||||||
|
return mrb_float_value(mrb, var);
|
||||||
|
}
|
||||||
|
static double from_mrb(mrb_state *mrb, mrb_value value) {
|
||||||
|
return mrb_float(value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <> struct mrubypp_converter<std::string> {
|
||||||
|
static mrb_value to_mrb(mrb_state *mrb, const std::string &var) {
|
||||||
|
return mrb_str_new(mrb, var.data(), (mrb_int)var.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string from_mrb(mrb_state *mrb, mrb_value value) {
|
||||||
|
if (mrb_string_p(value)) {
|
||||||
|
return std::string(RSTRING_PTR(value), RSTRING_LEN(value));
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T> struct mrubypp_converter<std::vector<T>> {
|
||||||
|
static mrb_value to_mrb(mrb_state *mrb, const std::vector<T> &var) {
|
||||||
|
mrb_value ary = mrb_ary_new_capa(mrb, static_cast<mrb_int>(var.size()));
|
||||||
|
for (const T &el : var) {
|
||||||
|
mrubypp_arena_guard guard(mrb);
|
||||||
|
mrb_ary_push(mrb, ary, mrubypp_converter<T>::to_mrb(mrb, el));
|
||||||
|
}
|
||||||
|
return ary;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<T> from_mrb(mrb_state *mrb, mrb_value value) {
|
||||||
|
mrubypp_arena_guard guard(mrb);
|
||||||
|
std::vector<T> result;
|
||||||
|
if (mrb_array_p(value)) {
|
||||||
|
int len = RARRAY_LEN(value);
|
||||||
|
for (int i = 0; i < len; ++i) {
|
||||||
|
result.append(
|
||||||
|
mrubypp_converter<T>::from_mrb(mrb, mrb_ary_ref(mrb, value, i)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // MRUBYPP_STD_CONVERTERS_H
|
||||||
Reference in New Issue
Block a user