Add support for returning a pre-existing foreign object from a foreign method

This is potentially subject to change in the near
future. This commit adds support for returning
an instance (currently wrapped in ForeignObject<>)
of a foreign object that is already instantiated.
The object returned this way simply gets selected
by handle into slot 0 of C Wren.
Conversely, returning just a naked object causes
wrenpp to make a Wren-accessible copy of it.
This commit is contained in:
King_DuckZ 2024-05-28 08:25:19 +02:00
commit 2c99251b27
13 changed files with 223 additions and 17 deletions

View file

@ -128,7 +128,7 @@ int main() {
vm.interpret("main", g_test_script);
Calendar* const cale = std::get<0>(wren::variables<Calendar>(vm, MN<"main", "cale">));
Calendar* const cale = std::get<0>(wren::variables<Calendar>(vm, MN<"main", "cale">)).data();
cale->print_appointments();
return 0;

View file

@ -52,10 +52,19 @@ foreign class ClassB {
}
foreign greeting_message(first_name, family_name, emoji)
foreign set_obj_c (obj)
foreign get_obj_c()
}
)script";
//This is three examples in one:
constexpr char g_module_c[] =
"foreign class ClassC {" R"script(
construct new (msg) {}
foreign print_message()
}
)script";
//This is several examples in one:
//1. instantiate ClassA in Wren and pass it to do_action() which is a
// non-foreign method in wren
//2. instantiate ClassA in C++, have C++ invoke the non-foreign method
@ -64,14 +73,21 @@ foreign class ClassB {
//3. instantiate ClassB in C++, have C++ invoke the non-foreign method
// do_action() on it and pass the same ClassA instance from the previous
// step to it
//4. show how to return a pre-existing instance of ClassC from ClassB both in
// C++ and Wren
constexpr char g_script[] = ""
R"script(
import "module_a" for ClassA
import "module_b" for ClassB
import "module_c" for ClassC
var obj_b = ClassB.new("TheWren")
obj_b.do_action(ClassA.new("instanciated from script"), 2)
obj_b.greeting_message("Jane", "Doe", "ʕ·͡ᴥ·ʔ")
var obj_c = ClassC.new("Message of ClassC object instantiated in Wren")
obj_b.set_obj_c(obj_c)
obj_b.get_obj_c().print_message()
)script";
class MyWrenConfig : public wren::DefConfiguration {
@ -81,6 +97,8 @@ public:
return copied(g_module_a, sizeof(g_module_a));
else if (module_name == "module_b")
return copied(g_module_b, sizeof(g_module_b));
else if (module_name == "module_c")
return copied(g_module_c, sizeof(g_module_c));
return nullptr;
}
@ -112,6 +130,8 @@ struct ClassA {
std::string m_message;
};
class ClassC;
class ClassB {
public:
explicit ClassB (std::string nickname) : m_nickname(nickname) {
@ -130,8 +150,23 @@ public:
m_nickname << "' " << family_name << "\" " << emoji << '\n';
}
void set_obj_c (wren::ForeignObject<ClassC> obj) {
m_obj_c = std::move(obj);
}
wren::ForeignObject<ClassC>* get_obj_c() { return &m_obj_c; }
private:
std::string m_nickname;
wren::ForeignObject<ClassC> m_obj_c;
};
class ClassC {
public:
ClassC (std::string msg) : m_message(msg) {}
void print_message() const { std::cout << m_message << '\n'; }
private:
std::string m_message;
};
} //unnamed namespace
@ -149,10 +184,14 @@ int main() {
vm.callback_manager()
.add_callback(false, "module_a", "ClassA", "say_hi()", make_function_bindable<&ClassA::say_hi>)
.add_callback(false, "module_b", "ClassB", "greeting_message(_,_,_)", make_function_bindable<&ClassB::greeting_message>)
.add_callback(false, "module_b", "ClassB", "set_obj_c(_)", make_function_bindable<&ClassB::set_obj_c>)
.add_callback(false, "module_b", "ClassB", "get_obj_c()", make_function_bindable<&ClassB::get_obj_c>)
.add_callback(false, "module_c", "ClassC", "print_message()", make_function_bindable<&ClassC::print_message>)
;
vm.class_manager()
.add_class_maker("module_b", "ClassB", make_foreign_class<ClassB, std::string>)
.add_class_maker("module_a", "ClassA", make_foreign_class<ClassA, std::string>)
.add_class_maker("module_c", "ClassC", make_foreign_class<ClassC, std::string>)
;
//Example 1: invoke obj_b.do_action() from Wren passing an obj_a that's
@ -169,6 +208,11 @@ int main() {
auto obj_b = make_wren_object<ClassB>(vm, wren::MN<"module_b", "ClassB">, "TheCpp");
wren::call<void>(vm, obj_b, "do_action", obj_a, 4);
//Example 4: set obj_c on obj_c and query it back
wren::ForeignObject<ClassC> obj_c = make_wren_object<ClassC>(vm, wren::MN<"module_c", "ClassC">, "Message of ClassC object instantiated in C++");
obj_b.object().set_obj_c(std::move(obj_c));
obj_b.object().get_obj_c()->object().print_message();
std::cout << "Quitting in 1 sec" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
return 0;

View file

@ -1,4 +1,4 @@
executable('call_cpp',
executable('cpp_calls',
'main.cpp',
dependencies: wrenpp_dep,
install: false,

View file

@ -2,4 +2,4 @@ subdir('dieroll')
subdir('greet')
subdir('calendar')
subdir('math_vector')
subdir('call_cpp')
subdir('cpp_calls')