#ifndef RUBY_H #define RUBY_H #include "pch.h" #include "utils.h" #define DEF_SYM(name) inline mrb_sym sym_##name = mrb_intern_cstr(Ruby::mrb, #name); #define SYM(name) mrb_symbol_value(sym_##name) #define HASH_GET(h, key) mrb_hash_get(Ruby::mrb, h, SYM(key)) #define HASH_FLOAT(h, key, out) \ do { \ mrb_value v = HASH_GET(h, key); \ if (mrb_fixnum_p(v)) \ out = (float)mrb_fixnum(v); \ } while (0) #define HASH_BOOL(h, key, out) \ do { \ mrb_value v = HASH_GET(h, key); \ if (!mrb_nil_p(v)) \ out = mrb_bool(v); \ } while (0) struct Wrapper { int id; }; #define DEF_RB(NAME, FN_FREE, FN_INIT) \ static void NAME##_free(mrb_state *mrb, void *ptr) { \ int id = ((Wrapper *)ptr)->id; \ FN_FREE; \ delete (Wrapper *)ptr; \ } \ static const struct mrb_data_type NAME##_type = { \ #NAME, \ NAME##_free \ }; \ static mrb_value NAME##_init(mrb_state *mrb, mrb_value self) { \ Wrapper *s = new Wrapper(); \ FN_INIT; \ DATA_PTR(self) = s; \ DATA_TYPE(self) = &NAME##_type; \ return self; \ } inline int get_id(mrb_value self) { return ((Wrapper *)DATA_PTR(self))->id; } namespace Ruby { inline mrb_state *mrb = mrb_open(); struct Block { mrb_value proc; Block(mrb_value proc) : proc(proc) { mrb_gc_register(mrb, proc); } Block() : proc(mrb_nil_value()) {} void set_proc(mrb_value new_proc) { if (!mrb_nil_p(proc)) mrb_gc_unregister(mrb, proc); proc = new_proc; if (!mrb_nil_p(proc)) mrb_gc_register(mrb, proc); } Block(const Block &) = delete; Block &operator=(const Block &) = delete; mrb_value call(int argc = 0, mrb_value *argv = nullptr) const { if (mrb_nil_p(proc)) return mrb_nil_value(); return mrb_funcall(mrb, proc, "call", argc, argv); } ~Block() { mrb_gc_unregister(mrb, proc); } }; inline void run_string(const char *code, size_t length) { int ai = mrb_gc_arena_save(mrb); mrb_load_nstring(mrb, code, length); mrb_gc_arena_restore(mrb, ai); } }; // namespace Ruby DEF_SYM(pixel_art) DEF_SYM(bold) DEF_SYM(italic) DEF_SYM(underline) DEF_SYM(position) DEF_SYM(click_through) DEF_SYM(x) DEF_SYM(y) DEF_SYM(w) DEF_SYM(h) DEF_SYM(z) #endif