Actors may be destroyed without ever calling their receivers. This is regular behavior when an actor is killed by an exit message. C++ actors cleanup automatically via their destructors. Up to now zig actor had to enable trapping and cleanup on the exit message. This was a big foot gun and cumbersome. Now all zig actors are required to pass a deinit function to thespian.receive. This simplifies clean up and prevents the foot gun entirely.
73 lines
2.3 KiB
C++
73 lines
2.3 KiB
C++
#include "cbor/c/cbor.h"
|
|
#include "thespian/c/handle.h"
|
|
#include <thespian/c/instance.h>
|
|
#include <thespian/instance.hpp>
|
|
|
|
using std::string_view;
|
|
|
|
extern "C" {
|
|
|
|
void thespian_receive(thespian_receiver r, thespian_behaviour_state s,
|
|
thespian_receiver_dtor dtor) {
|
|
struct receiver_wrapper {
|
|
thespian_receiver r;
|
|
thespian_behaviour_state s;
|
|
thespian_receiver_dtor dtor;
|
|
~receiver_wrapper() { dtor(s); }
|
|
};
|
|
auto wrapper = std::make_shared<receiver_wrapper>(r, s, dtor);
|
|
thespian::receive([wrapper](auto from, cbor::buffer msg) -> thespian::result {
|
|
thespian_handle from_handle = reinterpret_cast<thespian_handle>( // NOLINT
|
|
&from);
|
|
auto *ret = wrapper->r(wrapper->s, from_handle, {msg.data(), msg.size()});
|
|
if (ret) {
|
|
auto err = cbor::buffer();
|
|
const uint8_t *data = ret->base;
|
|
std::copy(data, data + ret->len, back_inserter(err)); // NOLINT
|
|
return thespian::to_error(err);
|
|
}
|
|
return thespian::ok();
|
|
});
|
|
}
|
|
|
|
auto thespian_get_trap() -> bool { return thespian::trap(); }
|
|
auto thespian_set_trap(bool on) -> bool { return thespian::trap(on); }
|
|
|
|
void thespian_link(thespian_handle h) {
|
|
thespian::handle *h_{
|
|
reinterpret_cast<thespian::handle *>( // NOLINT(*-reinterpret-cast)
|
|
h)};
|
|
thespian::link(*h_);
|
|
}
|
|
|
|
auto thespian_self() -> thespian_handle {
|
|
auto &self = thespian::self_ref();
|
|
return reinterpret_cast<thespian_handle>(&self); // NOLINT(*-reinterpret-cast)
|
|
}
|
|
|
|
auto thespian_spawn_link(thespian_behaviour b, thespian_behaviour_state s,
|
|
const char *name, thespian_env env,
|
|
thespian_handle *handle) -> int {
|
|
const thespian::env_t empty_env_{};
|
|
thespian::env_t env_ =
|
|
env ? *reinterpret_cast<thespian::env_t *>(env) : empty_env_; // NOLINT
|
|
|
|
auto ret = spawn_link(
|
|
[b, s]() -> thespian::result {
|
|
auto *ret = b(s);
|
|
if (ret) {
|
|
auto err = cbor::buffer();
|
|
const uint8_t *data = ret->base; // NOLINT
|
|
std::copy(data, data + ret->len, back_inserter(err)); // NOLINT
|
|
return thespian::to_error(err);
|
|
}
|
|
return thespian::ok();
|
|
},
|
|
string_view(name), std::move(env_));
|
|
if (!ret)
|
|
return -1;
|
|
*handle = reinterpret_cast<thespian_handle>( // NOLINT
|
|
new thespian::handle{ret.value()});
|
|
return 0;
|
|
}
|
|
}
|