#ifndef DIPLOMAT_RUNTIME_CPP_H #define DIPLOMAT_RUNTIME_CPP_H #include #include #include #include #include #if __cplusplus >= 202002L #include #endif #include "diplomat_runtime.h" namespace diplomat { extern "C" inline void Flush(capi::DiplomatWriteable* w) { std::string* string = reinterpret_cast(w->context); string->resize(w->len); }; extern "C" inline bool Grow(capi::DiplomatWriteable* w, uintptr_t requested) { std::string* string = reinterpret_cast(w->context); string->resize(requested); w->cap = string->length(); w->buf = &(*string)[0]; return true; }; inline capi::DiplomatWriteable WriteableFromString(std::string& string) { capi::DiplomatWriteable w; w.context = &string; w.buf = &string[0]; w.len = string.length(); // Same as length, since C++ strings are not supposed // to be written to past their len; you resize *first* w.cap = string.length(); w.flush = Flush; w.grow = Grow; return w; }; template struct WriteableTrait { // static inline capi::DiplomatWriteable Construct(T& t); }; template<> struct WriteableTrait { static inline capi::DiplomatWriteable Construct(std::string& t) { return diplomat::WriteableFromString(t); } }; template struct Ok { T inner; explicit Ok(T&& i): inner(std::move(i)) {} // We don't want to expose an lvalue-capable constructor in general // however there is no problem doing this for trivially copyable types template::value>::type> explicit Ok(const T& i): inner(i) {} Ok() = default; Ok(Ok&&) noexcept = default; Ok(const Ok &) = default; Ok& operator=(const Ok&) = default; Ok& operator=(Ok&&) noexcept = default; }; template struct Err { T inner; explicit Err(T&& i): inner(std::move(i)) {} // We don't want to expose an lvalue-capable constructor in general // however there is no problem doing this for trivially copyable types template::value>::type> explicit Err(const T& i): inner(i) {} Err() = default; Err(Err&&) noexcept = default; Err(const Err &) = default; Err& operator=(const Err&) = default; Err& operator=(Err&&) noexcept = default; }; template class result { private: std::variant, Err> val; public: explicit result(Ok&& v): val(std::move(v)) {} explicit result(Err&& v): val(std::move(v)) {} result() = default; result(const result &) = default; result& operator=(const result&) = default; result& operator=(Ok&& t) { this->val = Ok(std::move(t)); return *this; } result& operator=(Err&& e) { this->val = Err(std::move(e)); return *this; } result& operator=(result&&) noexcept = default; result(result &&) noexcept = default; ~result() = default; bool is_ok() const { return std::holds_alternative>(this->val); }; bool is_err() const { return std::holds_alternative>(this->val); }; std::optional ok() && { if (!this->is_ok()) { return std::nullopt; } return std::make_optional(std::move(std::get>(std::move(this->val)).inner)); }; std::optional err() && { if (!this->is_err()) { return std::nullopt; } return std::make_optional(std::move(std::get>(std::move(this->val)).inner)); } void set_ok(T&& t) { this->val = Ok(std::move(t)); } void set_err(E&& e) { this->val = Err(std::move(e)); } template result replace_ok(T2&& t) { if (this->is_err()) { return result(Err(std::get>(std::move(this->val)))); } else { return result(Ok(std::move(t))); } } }; // Use custom std::span on C++17, otherwise use std::span #if __cplusplus >= 202002L template using span = std::span; #else // __cplusplus >= 202002L // C++-17-compatible std::span template class span { public: constexpr span(T* data, size_t size) : data_(data), size_(size) {} template explicit constexpr span(std::array::type, N>& arr) : data_(const_cast(arr.data())), size_(N) {} constexpr T* data() const noexcept { return this->data_; } constexpr size_t size() const noexcept { return this->size_; } private: T* data_; size_t size_; }; #endif // __cplusplus >= 202002L } #endif