mirror of
https://github.com/logos-messaging/nim-ffi.git
synced 2026-06-20 16:29:31 +00:00
173 lines
6.2 KiB
Smarty
173 lines
6.2 KiB
Smarty
// ── encode_cbor overloads (primitives + containers) ─────────────────────
|
|
// Per-struct encode_cbor / decode_cbor are emitted by cpp.nim next to each
|
|
// generated struct; these helpers cover the leaf types they defer into.
|
|
// Guarded so two nim-ffi headers can share a translation unit.
|
|
#ifndef NIM_FFI_CBOR_HELPERS_HPP_INCLUDED
|
|
#define NIM_FFI_CBOR_HELPERS_HPP_INCLUDED
|
|
|
|
inline CborError encode_cbor(CborEncoder& e, bool v) {
|
|
return cbor_encode_boolean(&e, v);
|
|
}
|
|
inline CborError encode_cbor(CborEncoder& e, int64_t v) {
|
|
return cbor_encode_int(&e, v);
|
|
}
|
|
inline CborError encode_cbor(CborEncoder& e, int32_t v) {
|
|
return cbor_encode_int(&e, static_cast<int64_t>(v));
|
|
}
|
|
inline CborError encode_cbor(CborEncoder& e, uint64_t v) {
|
|
return cbor_encode_uint(&e, v);
|
|
}
|
|
inline CborError encode_cbor(CborEncoder& e, double v) {
|
|
return cbor_encode_double(&e, v);
|
|
}
|
|
inline CborError encode_cbor(CborEncoder& e, const std::string& v) {
|
|
return cbor_encode_text_string(&e, v.data(), v.size());
|
|
}
|
|
|
|
template<typename T>
|
|
inline CborError encode_cbor(CborEncoder& e, const std::vector<T>& v) {
|
|
CborEncoder arr;
|
|
CborError err = cbor_encoder_create_array(&e, &arr, v.size());
|
|
if (err) return err;
|
|
for (const auto& item : v) {
|
|
err = encode_cbor(arr, item);
|
|
if (err) return err;
|
|
}
|
|
return cbor_encoder_close_container(&e, &arr);
|
|
}
|
|
|
|
template<typename T>
|
|
inline CborError encode_cbor(CborEncoder& e, const std::optional<T>& v) {
|
|
if (!v) return cbor_encode_null(&e);
|
|
return encode_cbor(e, *v);
|
|
}
|
|
|
|
// ── decode_cbor overloads ───────────────────────────────────────────────
|
|
|
|
inline CborError decode_cbor(CborValue& it, bool& out) {
|
|
if (!cbor_value_is_boolean(&it)) return CborErrorImproperValue;
|
|
CborError err = cbor_value_get_boolean(&it, &out);
|
|
if (err) return err;
|
|
return cbor_value_advance(&it);
|
|
}
|
|
inline CborError decode_cbor(CborValue& it, int64_t& out) {
|
|
if (!cbor_value_is_integer(&it)) return CborErrorImproperValue;
|
|
CborError err = cbor_value_get_int64_checked(&it, &out);
|
|
if (err) return err;
|
|
return cbor_value_advance(&it);
|
|
}
|
|
inline CborError decode_cbor(CborValue& it, int32_t& out) {
|
|
int64_t tmp = 0;
|
|
CborError err = decode_cbor(it, tmp);
|
|
if (err) return err;
|
|
out = static_cast<int32_t>(tmp);
|
|
return CborNoError;
|
|
}
|
|
inline CborError decode_cbor(CborValue& it, uint64_t& out) {
|
|
if (!cbor_value_is_unsigned_integer(&it)) return CborErrorImproperValue;
|
|
CborError err = cbor_value_get_uint64(&it, &out);
|
|
if (err) return err;
|
|
return cbor_value_advance(&it);
|
|
}
|
|
inline CborError decode_cbor(CborValue& it, double& out) {
|
|
if (cbor_value_is_double(&it)) {
|
|
CborError err = cbor_value_get_double(&it, &out);
|
|
if (err) return err;
|
|
return cbor_value_advance(&it);
|
|
}
|
|
if (cbor_value_is_float(&it)) {
|
|
float f = 0.0f;
|
|
CborError err = cbor_value_get_float(&it, &f);
|
|
if (err) return err;
|
|
out = static_cast<double>(f);
|
|
return cbor_value_advance(&it);
|
|
}
|
|
return CborErrorImproperValue;
|
|
}
|
|
inline CborError decode_cbor(CborValue& it, std::string& out) {
|
|
if (!cbor_value_is_text_string(&it)) return CborErrorImproperValue;
|
|
size_t len = 0;
|
|
CborError err = cbor_value_get_string_length(&it, &len);
|
|
if (err) return err;
|
|
out.resize(len);
|
|
err = cbor_value_copy_text_string(&it, out.empty() ? nullptr : &out[0], &len, nullptr);
|
|
if (err) return err;
|
|
return cbor_value_advance(&it);
|
|
}
|
|
|
|
template<typename T>
|
|
inline CborError decode_cbor(CborValue& it, std::vector<T>& out) {
|
|
if (!cbor_value_is_array(&it)) return CborErrorImproperValue;
|
|
size_t len = 0;
|
|
CborError err = cbor_value_get_array_length(&it, &len);
|
|
if (err) return err;
|
|
out.clear();
|
|
out.resize(len);
|
|
CborValue inner;
|
|
err = cbor_value_enter_container(&it, &inner);
|
|
if (err) return err;
|
|
for (size_t i = 0; i < len; ++i) {
|
|
err = decode_cbor(inner, out[i]);
|
|
if (err) return err;
|
|
}
|
|
return cbor_value_leave_container(&it, &inner);
|
|
}
|
|
|
|
template<typename T>
|
|
inline CborError decode_cbor(CborValue& it, std::optional<T>& out) {
|
|
if (cbor_value_is_null(&it)) {
|
|
out = std::nullopt;
|
|
return cbor_value_advance(&it);
|
|
}
|
|
T tmp{};
|
|
CborError err = decode_cbor(it, tmp);
|
|
if (err) return err;
|
|
out = std::move(tmp);
|
|
return CborNoError;
|
|
}
|
|
|
|
// ── Public entry points ─────────────────────────────────────────────────
|
|
|
|
template<typename T>
|
|
inline Result<std::vector<std::uint8_t>> encodeCborFFI(const T& value) {
|
|
// Start with a generous 4 KiB buffer; double on overflow until it fits.
|
|
std::vector<std::uint8_t> buf(4096);
|
|
while (true) {
|
|
CborEncoder enc;
|
|
cbor_encoder_init(&enc, buf.data(), buf.size(), 0);
|
|
CborError err = encode_cbor(enc, value);
|
|
if (err == CborNoError) {
|
|
const size_t used = cbor_encoder_get_buffer_size(&enc, buf.data());
|
|
buf.resize(used);
|
|
return Result<std::vector<std::uint8_t>>::ok(std::move(buf));
|
|
}
|
|
if (err == CborErrorOutOfMemory) {
|
|
const size_t extra = cbor_encoder_get_extra_bytes_needed(&enc);
|
|
buf.resize(buf.size() + (extra > 0 ? extra : buf.size()));
|
|
continue;
|
|
}
|
|
return Result<std::vector<std::uint8_t>>::err(
|
|
std::string("FFI CBOR encode failed: ") + cbor_error_string(err));
|
|
}
|
|
}
|
|
|
|
template<typename T>
|
|
inline Result<T> decodeCborFFI(const std::vector<std::uint8_t>& bytes) {
|
|
CborParser parser;
|
|
CborValue it;
|
|
CborError err = cbor_parser_init(bytes.data(), bytes.size(), 0, &parser, &it);
|
|
if (err != CborNoError) {
|
|
return Result<T>::err(std::string("FFI CBOR parse init failed: ") +
|
|
cbor_error_string(err));
|
|
}
|
|
T out{};
|
|
err = decode_cbor(it, out);
|
|
if (err != CborNoError) {
|
|
return Result<T>::err(std::string("FFI CBOR decode failed: ") +
|
|
cbor_error_string(err));
|
|
}
|
|
return Result<T>::ok(std::move(out));
|
|
}
|
|
|
|
#endif // NIM_FFI_CBOR_HELPERS_HPP_INCLUDED
|