mirror of
https://github.com/logos-messaging/nim-ffi.git
synced 2026-06-22 17:29:28 +00:00
Aligns the C++ generators with the C generator and the symbol naming: the native (zero-serialization, same-process) wrapper is the bare `<lib>.hpp` and the CBOR (inter-process) wrapper carries the `_cbor` suffix — mirroring the C headers (`<lib>.h` / `<lib>_cbor.h`) and the `<name>` / `<name>_cbor` exports. Previously native was `<lib>_native.hpp` and CBOR was the bare `<lib>.hpp`, which is backwards from the symbol convention and would collide on the native `<lib>.h` when both ABIs emit into one dir (ffiMode=both). With the flip, a single `genbindings_cpp` run now drops `<lib>.hpp` + `<lib>_cbor.hpp` side by side, exactly like c_bindings holds both `.h` headers. Consumers updated to match: the CBOR cpp_bindings driver and the C++ e2e suite include `*_cbor.hpp`; the native example includes the bare `<lib>.hpp`. Validated: native example runs on `my_timer.hpp`; C++ e2e suite 19/19 on the `_cbor.hpp` headers; check_bindings_cpp regen is deterministic. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
158 lines
4.4 KiB
C++
158 lines
4.4 KiB
C++
// Generated by nim-ffi native C++ codegen. Do not edit by hand.
|
|
//
|
|
// Native (zero-serialization) wrapper over the C ABI in "echo.h". Struct params/returns cross as flat C-POD structs — no CBOR. For the
|
|
// inter-process path use the CBOR header (echo_cbor.hpp).
|
|
#ifndef NIM_FFI_GEN_ECHO_NATIVE_HPP
|
|
#define NIM_FFI_GEN_ECHO_NATIVE_HPP
|
|
|
|
#include "echo.h"
|
|
#include <cstdint>
|
|
#include <functional>
|
|
#include <future>
|
|
#include <map>
|
|
#include <memory>
|
|
#include <optional>
|
|
#include <stdexcept>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
namespace echo {
|
|
|
|
struct EchoConfig {
|
|
std::string prefix{};
|
|
};
|
|
struct EchoConfigC {
|
|
::EchoConfig c{};
|
|
};
|
|
inline EchoConfigC toC(const EchoConfig& v) {
|
|
EchoConfigC h;
|
|
h.c.prefix = v.prefix.c_str();
|
|
return h;
|
|
}
|
|
inline EchoConfig fromC(const ::EchoConfig& c) {
|
|
EchoConfig v{};
|
|
v.prefix = c.prefix ? std::string(c.prefix) : std::string();
|
|
return v;
|
|
}
|
|
|
|
struct ShoutRequest {
|
|
std::string text{};
|
|
};
|
|
struct ShoutRequestC {
|
|
::ShoutRequest c{};
|
|
};
|
|
inline ShoutRequestC toC(const ShoutRequest& v) {
|
|
ShoutRequestC h;
|
|
h.c.text = v.text.c_str();
|
|
return h;
|
|
}
|
|
inline ShoutRequest fromC(const ::ShoutRequest& c) {
|
|
ShoutRequest v{};
|
|
v.text = c.text ? std::string(c.text) : std::string();
|
|
return v;
|
|
}
|
|
|
|
struct ShoutResponse {
|
|
std::string shouted{};
|
|
std::string prefix{};
|
|
};
|
|
struct ShoutResponseC {
|
|
::ShoutResponse c{};
|
|
};
|
|
inline ShoutResponseC toC(const ShoutResponse& v) {
|
|
ShoutResponseC h;
|
|
h.c.shouted = v.shouted.c_str();
|
|
h.c.prefix = v.prefix.c_str();
|
|
return h;
|
|
}
|
|
inline ShoutResponse fromC(const ::ShoutResponse& c) {
|
|
ShoutResponse v{};
|
|
v.shouted = c.shouted ? std::string(c.shouted) : std::string();
|
|
v.prefix = c.prefix ? std::string(c.prefix) : std::string();
|
|
return v;
|
|
}
|
|
|
|
namespace detail {
|
|
template <typename T> struct Capture {
|
|
int ret = RET_ERR;
|
|
T value{};
|
|
std::string err;
|
|
std::promise<void> done;
|
|
};
|
|
struct AckCapture {
|
|
int ret = RET_ERR;
|
|
std::string err;
|
|
std::promise<void> done;
|
|
};
|
|
inline std::string rawText(const char* msg, std::size_t len) {
|
|
return (msg && len) ? std::string(msg, len) : std::string();
|
|
}
|
|
} // namespace detail
|
|
|
|
extern "C" {
|
|
inline void echo_native_ack(int ret, const char* msg, std::size_t len, void* ud) {
|
|
auto* c = static_cast<detail::AckCapture*>(ud);
|
|
c->ret = ret;
|
|
if (ret == RET_ERR) c->err = detail::rawText(msg, len);
|
|
c->done.set_value();
|
|
}
|
|
inline void echo_native_str(int ret, const char* msg, std::size_t len, void* ud) {
|
|
auto* c = static_cast<detail::Capture<std::string>*>(ud);
|
|
c->ret = ret;
|
|
if (ret == RET_OK) c->value = detail::rawText(msg, len);
|
|
else c->err = detail::rawText(msg, len);
|
|
c->done.set_value();
|
|
}
|
|
inline void echo_native_echo_shout(int ret, const char* msg, std::size_t len, void* ud) {
|
|
auto* c = static_cast<detail::Capture<ShoutResponse>*>(ud);
|
|
c->ret = ret;
|
|
if (ret == RET_OK) c->value = fromC(*reinterpret_cast<const ::ShoutResponse*>(msg));
|
|
else c->err = detail::rawText(msg, len);
|
|
c->done.set_value();
|
|
}
|
|
} // extern "C"
|
|
|
|
class EchoNode {
|
|
public:
|
|
explicit EchoNode(const EchoConfig& config) {
|
|
detail::AckCapture cap;
|
|
auto fut = cap.done.get_future();
|
|
auto c_config = toC(config);
|
|
ctx_ = echo_create(c_config.c, echo_native_ack, &cap);
|
|
if (!ctx_) throw std::runtime_error("echo_create returned null");
|
|
fut.wait();
|
|
if (cap.ret != RET_OK) throw std::runtime_error(cap.err);
|
|
}
|
|
|
|
ShoutResponse Shout(const ShoutRequest& req) {
|
|
detail::Capture<ShoutResponse> cap;
|
|
auto fut = cap.done.get_future();
|
|
auto c_req = toC(req);
|
|
if (echo_shout(ctx_, echo_native_echo_shout, &cap, c_req.c) != RET_OK)
|
|
throw std::runtime_error("echo_shout dispatch failed");
|
|
fut.wait();
|
|
if (cap.ret != RET_OK) throw std::runtime_error(cap.err);
|
|
return cap.value;
|
|
}
|
|
|
|
std::string Version() {
|
|
detail::Capture<std::string> cap;
|
|
auto fut = cap.done.get_future();
|
|
if (echo_version(ctx_, echo_native_str, &cap) != RET_OK)
|
|
throw std::runtime_error("echo_version dispatch failed");
|
|
fut.wait();
|
|
if (cap.ret != RET_OK) throw std::runtime_error(cap.err);
|
|
return cap.value;
|
|
}
|
|
|
|
~EchoNode() { if (ctx_) echo_destroy(ctx_); }
|
|
EchoNode(const EchoNode&) = delete;
|
|
EchoNode& operator=(const EchoNode&) = delete;
|
|
|
|
private:
|
|
void* ctx_ = nullptr;
|
|
};
|
|
|
|
} // namespace echo
|
|
|
|
#endif // NIM_FFI_GEN_ECHO_NATIVE_HPP
|