Initial Release

This commit is contained in:
CJ van den Berg 2024-02-08 22:23:40 +01:00
commit 5a00e06cb9
81 changed files with 12670 additions and 0 deletions

26
include/cbor/c/cbor.h Normal file
View file

@ -0,0 +1,26 @@
#pragma once
#include <thespian/c/string_view.h>
#include <stddef.h> // NOLINT
#include <stdint.h> // NOLINT
#ifdef __cplusplus
extern "C" {
#endif
struct cbor_buffer_t {
const uint8_t *base;
size_t len;
};
typedef struct // NOLINT
cbor_buffer_t cbor_buffer;
typedef // NOLINT
void (*cbor_to_json_callback)(c_string_view);
void cbor_to_json(cbor_buffer, cbor_to_json_callback);
#ifdef __cplusplus
}
#endif

463
include/cbor/cbor.hpp Normal file
View file

@ -0,0 +1,463 @@
#pragma once
#include <cstdint>
#include <functional>
#include <ostream>
#include <string>
#include <string_view>
#include <vector>
namespace cbor {
constexpr auto buffer_reserve = 128;
constexpr auto cbor_magic_null = 0xf6;
constexpr auto cbor_magic_true = 0xf5;
constexpr auto cbor_magic_false = 0xf4;
constexpr auto cbor_magic_type_array = 4;
constexpr auto cbor_magic_type_map = 5;
enum class type {
number,
bytes,
string,
array,
map,
tag,
boolean,
null,
any,
more,
unknown,
};
const auto any = type::any;
const auto more = type::more;
template <typename T> inline auto is_more(const T & /*unused*/) -> bool {
return false;
}
template <> inline auto is_more<type>(const type &t) -> bool {
return t == type::more;
}
using buffer_base = std::vector<uint8_t>;
class buffer : public buffer_base {
private:
using iter = const_iterator;
public:
using extractor = std::function<bool(iter &, const iter &)>;
private:
static auto decode_range_header(iter &, const iter &) -> size_t;
static auto decode_array_header(iter &, const iter &) -> size_t;
static auto decode_map_header(iter &, const iter &) -> size_t;
[[nodiscard]] static auto match_value(iter &, const iter &, const extractor &)
-> bool;
[[nodiscard]] static auto match_value(iter &, const iter &, type) -> bool;
[[nodiscard]] static auto match_value(iter &, const iter &, int64_t) -> bool;
[[nodiscard]] static auto match_value(iter &, const iter &, bool) -> bool;
[[nodiscard]] static auto match_value(iter &, const iter &,
const std::string &) -> bool;
[[nodiscard]] static auto match_value(iter &, const iter &,
const std::string_view) -> bool;
[[nodiscard]] static auto match_value(iter &b, const iter &e, const char *s)
-> bool {
return match_value(b, e, std::string(s));
}
[[nodiscard]] static auto match_value(iter &b, const iter &e, uint64_t v)
-> bool {
return match_value(b, e, static_cast<int64_t>(v));
}
[[nodiscard]] static auto match_value(iter &b, const iter &e, int32_t v)
-> bool {
return match_value(b, e, static_cast<int64_t>(v));
}
[[nodiscard]] static auto match_value(iter &b, const iter &e, uint32_t v)
-> bool {
return match_value(b, e, static_cast<int64_t>(v));
}
[[nodiscard]] static auto match_value(iter &b, const iter &e, int16_t v)
-> bool {
return match_value(b, e, static_cast<int64_t>(v));
}
[[nodiscard]] static auto match_value(iter &b, const iter &e, uint16_t v)
-> bool {
return match_value(b, e, static_cast<int64_t>(v));
}
[[nodiscard]] static auto match_value(iter &b, const iter &e, int8_t v)
-> bool {
return match_value(b, e, static_cast<int64_t>(v));
}
[[nodiscard]] static auto match_value(iter &b, const iter &e, uint8_t v)
-> bool {
return match_value(b, e, static_cast<int64_t>(v));
}
template <typename T>
[[nodiscard]] static auto match_next(size_t n, iter &b, const iter &e, T &&p)
-> bool {
if (is_more(p)) {
while (n) {
if (!match_value(b, e, any))
return false;
--n;
}
return true;
}
if (!n)
return false;
if (!match_value(b, e, p))
return false;
return n == 1;
}
template <typename T, typename... Ts>
[[nodiscard]] static auto match_next(size_t n, iter &b, const iter &e, T &&p,
Ts &&...parms) -> bool {
if (!n)
return false;
if (!match_value(b, e, p))
return false;
return match_next(--n, b, e, std::forward<Ts>(parms)...);
}
auto push_typed_val(int type, uint64_t value) -> void;
auto push_parms() -> buffer & { return *this; }
template <typename T, typename... Ts>
auto push_parms(const T &p, Ts &&...parms) -> buffer & {
push(p);
return push_parms(std::forward<Ts>(parms)...);
}
template <typename... Ts>
[[nodiscard]] static auto match_array(iter &b, const iter &e, Ts &&...parms)
-> bool {
auto n = decode_array_header(b, e);
return match_next(n, b, e, std::forward<Ts>(parms)...);
}
template <typename... Ts>
[[nodiscard]] static auto match_map(iter &b, const iter &e, Ts &&...parms)
-> bool {
auto n = decode_map_header(b, e);
n *= 2;
return match_next(n, b, e, std::forward<Ts>(parms)...);
}
public:
using buffer_base::buffer_base;
auto operator[](size_t) -> value_type & = delete;
static const buffer null_value;
[[nodiscard]] auto raw_cbegin() const -> iter {
return buffer_base::cbegin();
}
[[nodiscard]] auto raw_cend() const -> iter { return buffer_base::cend(); }
template <typename... Ts>
[[nodiscard]] auto operator()(Ts &&...parms) const -> bool {
auto b = raw_cbegin();
auto e = raw_cend();
return match_array(b, e, std::forward<Ts>(parms)...);
}
[[nodiscard]] auto is_null() const -> bool { return *this == null_value; }
auto push_null() -> buffer & {
push_back(cbor_magic_null);
return *this;
}
auto push_bool(bool v) -> buffer & {
if (v)
push_back(cbor_magic_true);
else
push_back(cbor_magic_false);
return *this;
}
auto push_string(const std::string &) -> buffer &;
auto push_string(const std::string_view &s) -> buffer &;
auto push_int(int64_t value) -> buffer & {
if (value < 0) {
push_typed_val(1, -(value + 1));
} else {
push_typed_val(0, value);
}
return *this;
}
auto push(const long long &i) -> buffer & { return push_int(i); }
auto push(const int64_t &i) -> buffer & { return push_int(i); }
auto push(const int32_t &i) -> buffer & { return push_int(i); }
auto push(const int16_t &i) -> buffer & { return push_int(i); }
auto push(const int8_t &i) -> buffer & { return push_int(i); }
auto push(const bool &v) -> buffer & { return push_bool(v); }
auto push(const std::string &s) -> buffer & { return push_string(s); }
auto push(const std::string_view &s) -> buffer & { return push_string(s); }
auto push(char *s) -> buffer & { return push_string(std::string_view(s)); }
auto push(const char *s) -> buffer & {
return push_string(std::string_view(s));
}
auto push_uint(uint64_t value) -> buffer & {
push_typed_val(0, value);
return *this;
}
auto push(const unsigned long long &i) -> buffer & { return push_uint(i); }
auto push(const uint64_t &i) -> buffer & { return push_uint(i); }
auto push(const uint32_t &i) -> buffer & { return push_uint(i); }
auto push(const uint16_t &i) -> buffer & { return push_uint(i); }
auto push(const uint8_t &i) -> buffer & { return push_uint(i); }
template <typename T> auto push(const T &a) -> buffer & {
a.to_cbor(*this);
return *this;
}
auto array_header(size_t sz) -> buffer & {
push_typed_val(cbor_magic_type_array, sz);
return *this;
}
auto map_header(size_t sz) -> buffer & {
push_typed_val(cbor_magic_type_map, sz);
return *this;
}
template <typename T> auto push_array(const T &a) -> buffer & {
if (a.empty())
push_null();
else {
array_header(a.size());
for (auto v : a)
push(v);
}
return *this;
}
auto push_json(const std::string &) -> void;
auto array() -> buffer & { return push_null(); }
template <typename... Ts> auto array(Ts &&...parms) -> buffer & {
array_header(sizeof...(parms));
return push_parms(std::forward<Ts>(parms)...);
}
auto map() -> buffer & { return push_null(); }
template <typename... Ts> auto map(Ts &&...parms) -> buffer & {
constexpr size_t sz = sizeof...(parms);
static_assert(sz % 2 == 0,
"cbor maps must contain an even number of values");
map_header(sz / 2);
return push_parms(std::forward<Ts>(parms)...);
}
auto to_cbor(buffer &b) const -> buffer & {
b.insert(b.raw_cend(), raw_cbegin(), raw_cend());
return b;
}
[[nodiscard]] auto to_json() const -> std::string;
auto to_json(std::ostream &) const -> void;
[[nodiscard]] auto hexdump() const -> std::string;
class range;
struct value_accessor {
iter b;
iter e;
[[nodiscard]] auto type_() const -> type;
operator type() const; // NOLINT
operator int64_t() const; // NOLINT
operator uint64_t() const; // NOLINT
operator int32_t() const; // NOLINT
operator uint32_t() const; // NOLINT
operator int16_t() const; // NOLINT
operator uint16_t() const; // NOLINT
operator int8_t() const; // NOLINT
operator uint8_t() const; // NOLINT
operator bool() const; // NOLINT
operator std::string_view() const; // NOLINT
operator buffer::range() const; // NOLINT
struct unvisitable_type {
cbor::type t;
};
template <typename F> auto visit(F f) const -> decltype(f(true)) {
type t{type_()};
switch (t) {
case type::string:
return f(static_cast<std::string_view>(*this));
case type::number:
return f(static_cast<int64_t>(*this));
case type::boolean:
return f(static_cast<bool>(*this));
case type::array:
case type::map:
return f(static_cast<range>(*this));
case type::null:
case type::bytes:
case type::tag:
case type::any:
case type::more:
case type::unknown:
return f(unvisitable_type{t});
}
return f(unvisitable_type{t});
}
auto to_cbor(buffer &buf) const -> buffer & {
buf.insert(buf.raw_cend(), b, e);
return buf;
}
};
auto push(const value_accessor::unvisitable_type & /*unused*/) -> buffer & {
return push("cbor::value_accessor::unvisitable_type");
}
struct value_iterator {
iter b;
iter e;
size_t n = 0;
auto operator!=(const value_iterator &other) const -> bool {
return b != other.b;
}
auto operator++() -> void {
if (n) {
--n;
[[maybe_unused]] bool _ = match_value(b, e, type::any);
}
}
auto operator*() -> value_accessor {
if (n)
return {b, e};
throw std::out_of_range("cbor iterator out of range");
}
};
[[nodiscard]] auto cbegin() const -> value_iterator = delete;
[[nodiscard]] auto cend() const -> value_iterator = delete;
[[nodiscard]] auto begin() const -> value_iterator {
auto b = raw_cbegin();
auto e = raw_cend();
auto n = decode_range_header(b, e);
return {b, e, n};
}
[[nodiscard]] auto end() const -> value_iterator {
return {raw_cend(), raw_cend()};
}
class range {
iter b_;
iter e_;
friend auto extract(range &) -> extractor;
[[nodiscard]] auto raw_cbegin() const -> iter { return b_; }
[[nodiscard]] auto raw_cend() const -> iter { return e_; }
public:
[[nodiscard]] auto begin() const -> value_iterator {
auto b = raw_cbegin();
auto e = raw_cend();
auto n = decode_range_header(b, e);
return {b, e, n};
}
[[nodiscard]] auto end() const -> value_iterator {
return {raw_cend(), raw_cend()};
}
auto is_null() -> bool {
auto b = raw_cbegin();
return decode_range_header(b, raw_cend()) == 0;
}
template <typename... Ts>
[[nodiscard]] auto operator()(Ts &&...parms) const -> bool {
auto b = raw_cbegin();
return match_array(b, raw_cend(), std::forward<Ts>(parms)...);
}
[[nodiscard]] auto to_json() const -> std::string;
auto to_json(std::ostream &) const -> void;
auto to_cbor(buffer &b) const -> buffer & {
b.insert(b.raw_cend(), raw_cbegin(), raw_cend());
return b;
}
auto operator==(const range &b) const -> bool {
using std::equal;
return equal(b.raw_cbegin(), b.raw_cend(), raw_cbegin(), raw_cend());
}
};
friend class range;
friend struct value_accessor;
friend auto extract(range &) -> extractor;
template <typename... Ts> friend auto A(Ts &&...parms) -> buffer::extractor;
template <typename... Ts> friend auto M(Ts &&...parms) -> buffer::extractor;
};
template <typename... Ts> auto array(Ts &&...parms) -> buffer {
buffer b;
b.reserve(buffer_reserve);
b.array(std::forward<Ts>(parms)...);
return b;
}
template <typename... Ts> auto map(Ts &&...parms) -> buffer {
buffer b;
b.reserve(buffer_reserve);
b.map(std::forward<Ts>(parms)...);
return b;
}
auto extract(type &) -> buffer::extractor;
auto extract(int64_t &) -> buffer::extractor;
auto extract(unsigned long long &) -> buffer::extractor;
auto extract(uint64_t &) -> buffer::extractor;
auto extract(int32_t &) -> buffer::extractor;
auto extract(uint32_t &) -> buffer::extractor;
auto extract(int16_t &) -> buffer::extractor;
auto extract(uint16_t &) -> buffer::extractor;
auto extract(int8_t &) -> buffer::extractor;
auto extract(uint8_t &) -> buffer::extractor;
auto extract(bool &) -> buffer::extractor;
auto extract(std::string &) -> buffer::extractor;
auto extract(std::string_view &) -> buffer::extractor;
auto extract(buffer::range &) -> buffer::extractor;
template <typename... Ts> auto A(Ts &&...parms) -> buffer::extractor {
return [=](buffer::iter &b, const buffer::iter &e) mutable {
return buffer::match_array(b, e, std::forward<Ts>(parms)...);
};
}
template <typename... Ts> auto M(Ts &&...parms) -> buffer::extractor {
return [=](buffer::iter &b, const buffer::iter &e) mutable {
return buffer::match_map(b, e, std::forward<Ts>(parms)...);
};
}
inline auto operator<<(std::ostream &s, const buffer &b) -> std::ostream & {
b.to_json(s);
return s;
}
inline auto operator<<(std::ostream &s, const buffer::range &b)
-> std::ostream & {
b.to_json(s);
return s;
}
} // namespace cbor

28
include/cbor/cbor_in.hpp Normal file
View file

@ -0,0 +1,28 @@
#pragma once
#include "cbor.hpp"
#include <cstring>
#include <netinet/in.h>
namespace cbor {
template <> inline auto buffer::push<in6_addr>(const in6_addr &a) -> buffer & {
push(std::string_view(reinterpret_cast<const char *>(&a), // NOLINT
sizeof(a)));
return *this;
}
inline auto extract(in6_addr &a) -> cbor::buffer::extractor {
return [&a](auto &b, const auto &e) {
std::string_view s;
auto ret = cbor::extract(s)(b, e);
if (ret && s.size() == sizeof(in6_addr)) {
std::memcpy(&a, s.data(), sizeof(in6_addr));
return true;
}
return false;
};
}
} // namespace cbor

View file

@ -0,0 +1,13 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
void install_debugger();
void install_backtrace();
void install_jitdebugger();
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,39 @@
#pragma once
#include <thespian/c/env.h>
#include <thespian/c/handle.h>
// NOLINTBEGIN(modernize-use-trailing-return-type, modernize-use-using)
#ifdef __cplusplus
extern "C" {
#endif
typedef void (*thespian_last_exit_handler)();
typedef void (*thespian_context_destroy)(void *);
typedef void *thespian_behaviour_state;
typedef void *thespian_exit_handler_state;
typedef thespian_result (*thespian_behaviour)(thespian_behaviour_state);
typedef void (*thespian_exit_handler)(thespian_exit_handler_state,
const char *msg, size_t len);
struct thespian_context_t;
typedef struct thespian_context_t *thespian_context;
thespian_context thespian_context_create(thespian_context_destroy *);
void thespian_context_run(thespian_context);
void thespian_context_on_last_exit(thespian_context,
thespian_last_exit_handler);
int thespian_context_spawn_link(thespian_context, thespian_behaviour,
thespian_behaviour_state, thespian_exit_handler,
thespian_exit_handler_state, const char *name,
thespian_env, thespian_handle *);
const char *thespian_get_last_error();
void thespian_set_last_error(const char *);
#ifdef __cplusplus
}
#endif
// NOLINTEND(modernize-use-trailing-return-type, modernize-use-using)

43
include/thespian/c/env.h Normal file
View file

@ -0,0 +1,43 @@
#pragma once
#include <thespian/c/handle.h>
#include <thespian/c/string_view.h>
#include <thespian/c/trace.h>
// NOLINTBEGIN(modernize-use-trailing-return-type, modernize-use-using)
#ifdef __cplusplus
extern "C" {
#endif
struct thespian_env_t;
typedef struct
thespian_env_t *thespian_env;
void thespian_env_enable_all_channels(thespian_env);
void thespian_env_disable_all_channels(thespian_env);
void thespian_env_enable(thespian_env, thespian_trace_channel);
void thespian_env_disable(thespian_env, thespian_trace_channel);
bool thespian_env_enabled(thespian_env, thespian_trace_channel);
void thespian_env_on_trace(thespian_env, thespian_trace_handler);
void thespian_env_trace(thespian_env, cbor_buffer);
bool thespian_env_is(thespian_env, c_string_view key);
void thespian_env_set(thespian_env, c_string_view key, bool);
int64_t thespian_env_num(thespian_env, c_string_view key);
void thespian_env_num_set(thespian_env, c_string_view key, int64_t);
c_string_view thespian_env_str(thespian_env, c_string_view key);
void thespian_env_str_set(thespian_env, c_string_view key,
c_string_view);
thespian_handle thespian_env_proc(thespian_env, c_string_view key);
void thespian_env_proc_set(thespian_env, c_string_view key,
thespian_handle);
thespian_env thespian_env_get();
thespian_env thespian_env_new();
thespian_env thespian_env_clone(thespian_env);
void thespian_env_destroy(thespian_env);
#ifdef __cplusplus
}
#endif
// NOLINTEND(modernize-use-trailing-return-type, modernize-use-using)

View file

@ -0,0 +1,19 @@
#pragma once
// NOLINTBEGIN(modernize-use-trailing-return-type)
#ifdef __cplusplus
extern "C" {
#endif
struct thespian_file_descriptor_handle;
struct thespian_file_descriptor_handle *
thespian_file_descriptor_create(const char* tag, int fd);
int thespian_file_descriptor_wait_write(struct thespian_file_descriptor_handle *);
int thespian_file_descriptor_wait_read(struct thespian_file_descriptor_handle *);
int thespian_file_descriptor_cancel(struct thespian_file_descriptor_handle *);
void thespian_file_descriptor_destroy(struct thespian_file_descriptor_handle *);
#ifdef __cplusplus
}
#endif
// NOLINTEND(modernize-use-trailing-return-type)

View file

@ -0,0 +1,29 @@
#pragma once
#include "thespian/c/string_view.h"
#include <cbor/c/cbor.h>
// NOLINTBEGIN(modernize-*, hicpp-*)
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef cbor_buffer thespian_error;
typedef thespian_error *thespian_result;
struct thespian_handle_t;
typedef struct thespian_handle_t *thespian_handle;
thespian_handle thespian_handle_clone(thespian_handle);
void thespian_handle_destroy(thespian_handle);
thespian_result thespian_handle_send_raw(thespian_handle, cbor_buffer);
thespian_result thespian_handle_send_exit(thespian_handle, c_string_view);
bool thespian_handle_is_expired(thespian_handle);
#ifdef __cplusplus
}
#endif
// NOLINTEND(modernize-*, hicpp-*)

View file

@ -0,0 +1,29 @@
#pragma once
#include "context.h"
#include "env.h"
#include "handle.h"
// NOLINTBEGIN(modernize-use-trailing-return-type, modernize-use-using)
#ifdef __cplusplus
extern "C" {
#endif
typedef thespian_result (*thespian_receiver)(thespian_behaviour_state,
thespian_handle from, cbor_buffer);
void thespian_receive(thespian_receiver, thespian_behaviour_state);
bool thespian_get_trap();
bool thespian_set_trap(bool);
void thespian_link(thespian_handle);
thespian_handle thespian_self();
int thespian_spawn_link(thespian_behaviour, thespian_behaviour_state,
const char *name, thespian_env, thespian_handle *);
#ifdef __cplusplus
}
#endif
// NOLINTEND(modernize-use-trailing-return-type, modernize-use-using)

View file

@ -0,0 +1,20 @@
#pragma once
// NOLINTBEGIN(modernize-use-trailing-return-type)
#ifdef __cplusplus
extern "C" {
#endif
struct thespian_metronome_handle;
struct thespian_metronome_handle *
thespian_metronome_create_ms(unsigned long ms);
struct thespian_metronome_handle *
thespian_metronome_create_us(unsigned long us);
int thespian_metronome_start(struct thespian_metronome_handle *);
int thespian_metronome_stop(struct thespian_metronome_handle *);
void thespian_metronome_destroy(struct thespian_metronome_handle *);
#ifdef __cplusplus
}
#endif
// NOLINTEND(modernize-use-trailing-return-type)

View file

@ -0,0 +1,19 @@
#pragma once
#include <cbor/c/cbor.h>
// NOLINTBEGIN(modernize-use-trailing-return-type)
#ifdef __cplusplus
extern "C" {
#endif
struct thespian_signal_handle;
struct thespian_signal_handle *
thespian_signal_create(int signum, cbor_buffer m);
int thespian_signal_cancel(struct thespian_signal_handle *);
void thespian_signal_destroy(struct thespian_signal_handle *);
#ifdef __cplusplus
}
#endif
// NOLINTEND(modernize-use-trailing-return-type)

View file

@ -0,0 +1,19 @@
#pragma once
// NOLINTBEGIN(modernize-*, hicpp-*)
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
struct c_string_view_t {
const char *base;
size_t len;
};
typedef struct c_string_view_t c_string_view;
#ifdef __cplusplus
}
#endif
// NOLINTEND(modernize-*, hicpp-*)

View file

@ -0,0 +1,21 @@
#pragma once
#include <cbor/c/cbor.h>
// NOLINTBEGIN(modernize-use-trailing-return-type)
#ifdef __cplusplus
extern "C" {
#endif
struct thespian_timeout_handle;
struct thespian_timeout_handle *
thespian_timeout_create_ms(unsigned long ms, cbor_buffer m);
struct thespian_timeout_handle *
thespian_timeout_create_us(unsigned long us, cbor_buffer m);
int thespian_timeout_cancel(struct thespian_timeout_handle *);
void thespian_timeout_destroy(struct thespian_timeout_handle *);
#ifdef __cplusplus
}
#endif
// NOLINTEND(modernize-use-trailing-return-type)

View file

@ -0,0 +1,40 @@
#pragma once
#include <cbor/c/cbor.h>
// NOLINTBEGIN(modernize-*, hicpp-*)
#include <limits.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef int thespian_trace_channel_set;
typedef int thespian_trace_channel;
static const thespian_trace_channel thespian_trace_channel_send = 1;
static const thespian_trace_channel thespian_trace_channel_receive = 2;
static const thespian_trace_channel thespian_trace_channel_lifetime = 4;
static const thespian_trace_channel thespian_trace_channel_link = 8;
static const thespian_trace_channel thespian_trace_channel_execute = 16;
static const thespian_trace_channel thespian_trace_channel_udp = 32;
static const thespian_trace_channel thespian_trace_channel_tcp = 64;
static const thespian_trace_channel thespian_trace_channel_timer = 128;
static const thespian_trace_channel thespian_trace_channel_metronome = 256;
static const thespian_trace_channel thespian_trace_channel_endpoint = 512;
static const thespian_trace_channel thespian_trace_channel_signal = 1024;
static const thespian_trace_channel thespian_trace_channel_all = INT_MAX;
typedef void (*thespian_trace_handler)(cbor_buffer);
void thespian_on_trace(thespian_trace_handler);
void thespian_trace_to_json_file(const char *file_name);
void thespian_trace_to_cbor_file(const char *file_name);
void thespian_trace_to_mermaid_file(const char *file_name);
void thespian_trace_to_trace(thespian_trace_channel default_channel);
#ifdef __cplusplus
}
#endif
// NOLINTEND(modernize-*, hicpp-*)

View file

@ -0,0 +1,46 @@
#pragma once
#include "env.hpp"
#include "handle.hpp"
#include <functional>
#include <memory>
namespace thespian {
using behaviour = std::function<auto()->result>;
using exit_handler = std::function<void(std::string_view)>;
struct context {
using dtor = void (*)(context *);
using ref = std::unique_ptr<context, dtor>;
using last_exit_handler = std::function<void()>;
[[nodiscard]] static auto create() -> ref;
[[nodiscard]] static auto create(dtor *) -> context *;
void run();
void on_last_exit(last_exit_handler);
[[nodiscard]] auto spawn(behaviour b, std::string_view name)
-> expected<handle, error>;
[[nodiscard]] auto spawn(behaviour b, std::string_view name, env_t env)
-> expected<handle, error>;
[[nodiscard]] auto spawn_link(behaviour b, exit_handler eh,
std::string_view name)
-> expected<handle, error>;
[[nodiscard]] auto spawn_link(behaviour b, exit_handler eh,
std::string_view name, env_t env)
-> expected<handle, error>;
protected:
context() = default;
~context() = default;
public:
context(const context &) = delete;
context(context &&) = delete;
void operator=(const context &) = delete;
void operator=(context &&) = delete;
};
} // namespace thespian

View file

@ -0,0 +1,22 @@
#pragma once
#include "context.hpp"
#include "handle.hpp"
#include <string>
using port_t = unsigned short;
namespace thespian::debug {
auto enable(context &) -> void;
auto disable(context &) -> void;
auto isenabled(context &) -> bool;
namespace tcp {
auto create(context &, port_t port, const std::string &prompt)
-> expected<handle, error>;
} // namespace tcp
} // namespace thespian::debug

View file

@ -0,0 +1,33 @@
#pragma once
#include "handle.hpp"
#include "tcp.hpp"
#include "unx.hpp"
#include <chrono>
#include <string>
using port_t = unsigned short;
namespace thespian::endpoint {
using namespace std::chrono_literals;
namespace tcp {
auto listen(in6_addr, port_t) -> expected<handle, error>;
auto connect(in6_addr, port_t, std::chrono::milliseconds retry_time = 50ms,
size_t retry_count = 5) -> expected<handle, error>;
} // namespace tcp
namespace unx {
using thespian::unx::mode;
auto listen(std::string_view, mode = mode::abstract) -> expected<handle, error>;
auto connect(std::string_view, mode = mode::abstract,
std::chrono::milliseconds retry_time = 50ms,
size_t retry_count = 5) -> expected<handle, error>;
} // namespace unx
} // namespace thespian::endpoint

51
include/thespian/env.hpp Normal file
View file

@ -0,0 +1,51 @@
#pragma once
#include "handle.hpp"
#include "trace.hpp"
#include <any>
#include <cstddef>
#include <map>
namespace thespian {
struct env_t {
void enable_all_channels() {
trace_channels = static_cast<channel_set>(channel::all);
}
void disable_all_channels() { trace_channels = 0; }
void enable(channel c) { trace_channels |= static_cast<channel_set>(c); }
void disable(channel c) { trace_channels ^= static_cast<channel_set>(c); }
auto enabled(channel c) -> bool {
return trace_channels & static_cast<channel_set>(c);
}
auto on_trace(trace_handler h) {
std::swap(h, trace_handler);
return h;
}
auto trace(const cbor::buffer &msg) const {
if (trace_handler)
trace_handler(msg);
}
auto is(std::string_view k) -> bool & { return b[std::string(k)]; }
auto num(std::string_view k) -> int64_t & { return i[std::string(k)]; }
auto str(std::string_view k) -> std::string & { return s[std::string(k)]; }
auto proc(std::string_view k) -> handle & { return h[std::string(k)]; }
[[nodiscard]] auto proc(std::string_view k) const -> const handle & {
return h.at(std::string(k));
}
private:
std::map<std::string, std::string> s;
std::map<std::string, bool> b;
std::map<std::string, int64_t> i;
std::map<std::string, handle> h;
channel_set trace_channels{0};
trace_handler trace_handler;
};
auto env() -> env_t &;
} // namespace thespian

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,32 @@
#pragma once
#include <memory>
#include <string_view>
#include <vector>
namespace thespian {
struct file_descriptor_impl;
using file_descriptor_dtor = void (*)(file_descriptor_impl *);
using file_descriptor_ref =
std::unique_ptr<file_descriptor_impl, file_descriptor_dtor>;
struct file_descriptor {
static auto create(std::string_view tag, int fd) -> file_descriptor;
auto wait_write() -> void;
auto wait_read() -> void;
auto cancel() -> void;
static void wait_write(file_descriptor_impl *);
static void wait_read(file_descriptor_impl *);
static void cancel(file_descriptor_impl *);
static void destroy(file_descriptor_impl *);
//->("fd", tag, "write_ready")
//->("fd", tag, "write_error", int err, string message)
//->("fd", tag, "read_ready")
//->("fd", tag, "read_error", int err, string message)
file_descriptor_ref ref;
};
} // namespace thespian

View file

@ -0,0 +1,49 @@
#pragma once
#include <cbor/cbor.hpp>
#include "expected.hpp"
#include <memory>
#include <utility>
namespace thespian {
template <typename T, typename E>
using expected = std::experimental::expected<T, E>;
using error = cbor::buffer;
using result = expected<void, error>;
using to_error = std::experimental::unexpected<error>;
[[nodiscard]] inline auto ok() -> result { return result{}; }
template <typename T> [[nodiscard]] auto ok(T v) { return result{v}; }
template <typename T> [[nodiscard]] auto to_result(T ret) -> result {
if (ret)
return ok();
return to_error(ret.error());
}
struct instance;
using ref = std::weak_ptr<instance>;
struct handle {
[[nodiscard]] auto send_raw(cbor::buffer) const -> result;
template <typename... Ts> [[nodiscard]] auto send(Ts &&...parms) const {
return send_raw(cbor::array(std::forward<Ts>(parms)...));
}
template <typename... Ts>
auto exit(const std::string &error, Ts &&...details) const {
return send_raw(cbor::array("exit", error, std::forward<Ts>(details)...));
}
[[nodiscard]] inline auto expired() const { return ref_.expired(); }
private:
ref ref_;
friend auto handle_ref(handle &) -> ref &;
friend auto handle_ref(const handle &) -> const ref &;
friend auto operator==(const handle &, const handle &) -> bool;
};
auto operator==(const handle &, const handle &) -> bool;
} // namespace thespian

46
include/thespian/hub.hpp Normal file
View file

@ -0,0 +1,46 @@
#pragma once
#include "handle.hpp"
#include <functional>
#include <memory>
namespace thespian {
struct hub : private handle {
using filter = std::function<bool(const cbor::buffer &)>;
hub() = default;
auto expired() -> bool { return handle::expired(); }
template <typename... Ts> auto broadcast(Ts &&...parms) const {
return send("broadcast", cbor::array(std::forward<Ts>(parms)...));
}
[[nodiscard]] auto subscribe() const -> result;
[[nodiscard]] auto subscribe(filter) const -> result;
[[nodiscard]] auto listen(std::string_view unix_socket_descriptor) const
-> result;
[[nodiscard]] auto shutdown() const { return send("shutdown"); }
[[nodiscard]] static auto create(std::string_view name)
-> expected<hub, error>;
struct pipe {
pipe();
pipe(const pipe &) = delete;
pipe(pipe &&) = delete;
auto operator=(const pipe &) -> pipe & = delete;
auto operator=(pipe &&) -> pipe & = delete;
virtual ~pipe();
};
private:
hub(const handle &, std::shared_ptr<pipe>);
std::shared_ptr<pipe> pipe_;
friend auto operator==(const handle &, const hub &) -> bool;
friend auto operator==(const hub &, const handle &) -> bool;
};
auto operator==(const handle &, const hub &) -> bool;
auto operator==(const hub &, const handle &) -> bool;
} // namespace thespian

View file

@ -0,0 +1,51 @@
#pragma once
#include "context.hpp"
#include "env.hpp"
#include "handle.hpp"
#include "trace.hpp"
#include <functional>
#include <map>
#include <string>
#include <string_view>
namespace thespian {
using receiver = std::function<result(handle from, cbor::buffer)>;
using sync_receiver = std::function<cbor::buffer(handle from, cbor::buffer)>;
[[nodiscard]] auto send_raw(cbor::buffer) -> result;
template <typename... Ts> [[nodiscard]] auto send(Ts &&...parms) -> result {
return send_raw(cbor::array(std::forward<Ts>(parms)...));
}
auto receive(receiver) -> void;
auto receive_sync(sync_receiver) -> void;
auto trap() -> bool;
auto trap(bool) -> bool;
auto link(const handle &) -> void;
auto self() -> handle;
auto self_ref() -> handle&;
[[nodiscard]] auto spawn(behaviour, std::string_view name)
-> expected<handle, error>;
[[nodiscard]] auto spawn_link(behaviour, std::string_view name)
-> expected<handle, error>;
[[nodiscard]] auto spawn(behaviour, std::string_view name, env_t)
-> expected<handle, error>;
[[nodiscard]] auto spawn_link(behaviour, std::string_view name, env_t)
-> expected<handle, error>;
[[nodiscard]] auto ok() -> result;
[[nodiscard]] auto exit() -> result;
[[nodiscard]] auto exit(std::string_view e) -> result;
[[nodiscard]] auto exit(std::string_view e, std::string_view m) -> result;
[[nodiscard]] auto exit(std::string_view e, int err) -> result;
[[nodiscard]] auto exit(std::string_view e, size_t n) -> result;
[[nodiscard]] auto unexpected(const cbor::buffer & /*b*/) -> result;
} // namespace thespian

View file

@ -0,0 +1,25 @@
#pragma once
#include <chrono>
#include <functional>
#include <memory>
namespace thespian {
struct metronome_impl;
using metronome_dtor = void (*)(metronome_impl *);
using metronome_ref = std::unique_ptr<metronome_impl, metronome_dtor>;
struct metronome {
auto start() -> void;
auto stop() -> void;
metronome_ref ref;
};
[[nodiscard]] auto create_metronome(std::chrono::microseconds us) -> metronome;
void start_metronome(metronome_impl *);
void stop_metronome(metronome_impl *);
void destroy_metronome(metronome_impl *);
} // namespace thespian

View file

@ -0,0 +1,25 @@
#pragma once
#include <cbor/cbor.hpp>
#include <chrono>
#include <functional>
#include <memory>
namespace thespian {
struct signal_impl;
using signal_dtor = void (*)(signal_impl *);
using signal_ref = std::unique_ptr<signal_impl, signal_dtor>;
struct signal {
auto cancel() -> void;
signal_ref ref;
};
[[nodiscard]] auto create_signal(int signum, cbor::buffer m) -> signal;
void cancel_signal(signal_impl *);
void destroy_signal(signal_impl *);
} // namespace thespian

View file

@ -0,0 +1,29 @@
#pragma once
#include <memory>
#include <string_view>
#include <vector>
namespace thespian {
struct socket_impl;
using socket_dtor = void (*)(socket_impl *);
using socket_ref = std::unique_ptr<socket_impl, socket_dtor>;
struct socket {
static auto create(std::string_view tag, int fd) -> socket;
auto write(std::string_view) -> void;
auto write(const std::vector<uint8_t> &) -> void;
auto read() -> void;
auto close() -> void;
//->("socket", tag, "write_complete", int written)
//->("socket", tag, "write_error", int err, string message)
//->("socket", tag, "read_complete", string buf)
//->("socket", tag, "read_error", int err, string message)
//->("socket", tag, "closed")
socket_ref ref;
};
} // namespace thespian

47
include/thespian/tcp.hpp Normal file
View file

@ -0,0 +1,47 @@
#pragma once
#include <memory>
#include <netinet/in.h>
#include <string_view>
#include <vector>
using port_t = unsigned short;
namespace thespian::tcp {
struct acceptor_impl;
using acceptor_dtor = void (*)(acceptor_impl *);
using acceptor_ref = std::unique_ptr<acceptor_impl, acceptor_dtor>;
struct acceptor {
static auto create(std::string_view tag) -> acceptor;
auto listen(in6_addr ip, port_t port) -> port_t;
auto close() -> void;
//->("acceptor", tag, "accept", int fd, in6_addr ip, port_t port)
//->("acceptor", tag, "error", int err, string message)
//->("acceptor", tag, "closed")
acceptor_ref ref;
};
struct connector_impl;
using connector_dtor = void (*)(connector_impl *);
using connector_ref = std::unique_ptr<connector_impl, connector_dtor>;
struct connector {
static auto create(std::string_view tag) -> connector;
auto connect(in6_addr ip, port_t port) -> void;
auto connect(in6_addr ip, port_t port, in6_addr lip) -> void;
auto connect(in6_addr ip, port_t port, port_t lport) -> void;
auto connect(in6_addr ip, port_t port, in6_addr lip, port_t lport) -> void;
auto cancel() -> void;
//->("connector", tag, "connected", int fd)
//->("connector", tag, "error", int err, string message)
//->("connector", tag, "cancelled")
connector_ref ref;
};
} // namespace thespian::tcp

View file

@ -0,0 +1,28 @@
#pragma once
#include <cbor/cbor.hpp>
#include <chrono>
#include <functional>
#include <memory>
namespace thespian {
struct timeout_impl;
using timeout_dtor = void (*)(timeout_impl *);
using timeout_ref = std::unique_ptr<timeout_impl, timeout_dtor>;
struct timeout {
auto cancel() -> void;
timeout_ref ref;
};
[[nodiscard]] auto create_timeout(std::chrono::microseconds us, cbor::buffer m)
-> timeout;
[[nodiscard]] auto never() -> timeout;
void cancel_timeout(timeout_impl *);
void destroy_timeout(timeout_impl *);
} // namespace thespian

View file

@ -0,0 +1,37 @@
#pragma once
#include "thespian/handle.hpp"
#include <cbor/cbor.hpp>
#include <functional>
#include <limits>
#include <string>
#include <vector>
namespace thespian {
using channel_set = int;
enum class channel {
send = 1,
receive = 2,
lifetime = 4,
link = 8,
execute = 16,
udp = 32,
tcp = 64,
timer = 128,
metronome = 256,
endpoint = 512,
signal = 1024,
all = std::numeric_limits<channel_set>::max(),
};
using trace_handler = std::function<void(const cbor::buffer &)>;
auto on_trace(trace_handler) -> trace_handler;
auto trace_to_json_file(const std::string &file_name) -> void;
auto trace_to_cbor_file(const std::string &file_name) -> void;
auto trace_to_mermaid_file(const std::string &file_name) -> void;
auto trace_to_trace(int default_channel) -> void;
} // namespace thespian

33
include/thespian/udp.hpp Normal file
View file

@ -0,0 +1,33 @@
#pragma once
#include <cbor/cbor_in.hpp>
#include <cstddef>
#include <functional>
#include <memory>
using port_t = unsigned short;
namespace thespian {
struct udp_impl;
using udp_dtor = void (*)(udp_impl *);
using udp_ref = std::unique_ptr<udp_impl, udp_dtor>;
struct udp {
static auto create(std::string tag) -> udp;
auto open(const in6_addr &, port_t port) -> port_t;
[[nodiscard]] auto sendto(std::string_view, in6_addr ip, port_t port)
-> size_t;
auto close() -> void;
//->("udp", tag, "open_error", int err, string message);
//->("udp", tag, "read_error", int err, string message);
//->("udp", tag, "receive", string data, in6_addr remote_ip, int port);
//->("udp", tag, "closed");
udp_ref ref;
};
} // namespace thespian

43
include/thespian/unx.hpp Normal file
View file

@ -0,0 +1,43 @@
#pragma once
#include <memory>
#include <string_view>
#include <vector>
namespace thespian::unx {
enum class mode { file, abstract };
struct acceptor_impl;
using acceptor_dtor = void (*)(acceptor_impl *);
using acceptor_ref = std::unique_ptr<acceptor_impl, acceptor_dtor>;
struct acceptor {
static auto create(std::string_view tag) -> acceptor;
auto listen(std::string_view, mode) -> void;
auto close() -> void;
//->("acceptor", tag, "accept", int fd)
//->("acceptor", tag, "error", int err, string message)
//->("acceptor",tag, "closed")
acceptor_ref ref;
};
struct connector_impl;
using connector_dtor = void (*)(connector_impl *);
using connector_ref = std::unique_ptr<connector_impl, connector_dtor>;
struct connector {
static auto create(std::string_view tag) -> connector;
auto connect(std::string_view, mode) -> void;
auto cancel() -> void;
//->("connector", tag, "connected", int fd)
//->("connector", tag, "error", int err, string message)
//->("connector", tag, "cancelled")
connector_ref ref;
};
} // namespace thespian::unx