diff --git a/examples/nim_timer/cpp_bindings/nimtimer.hpp b/examples/nim_timer/cpp_bindings/nimtimer.hpp index 77af079..95f33d8 100644 --- a/examples/nim_timer/cpp_bindings/nimtimer.hpp +++ b/examples/nim_timer/cpp_bindings/nimtimer.hpp @@ -13,19 +13,26 @@ #include #include +#if !defined(NIM_FFI_NO_OPTIONAL_SERIALIZER) \ + && !defined(NIM_FFI_OPTIONAL_SERIALIZER_DEFINED_) \ + && (!defined(NLOHMANN_JSON_VERSION_MAJOR) \ + || (NLOHMANN_JSON_VERSION_MAJOR < 3) \ + || (NLOHMANN_JSON_VERSION_MAJOR == 3 && NLOHMANN_JSON_VERSION_MINOR < 12)) +#define NIM_FFI_OPTIONAL_SERIALIZER_DEFINED_ namespace nlohmann { template - void to_json(json& j, const std::optional& opt) { - if (opt) j = *opt; - else j = nullptr; - } - - template - void from_json(const json& j, std::optional& opt) { - if (j.is_null()) opt = std::nullopt; - else opt = j.get(); - } + struct adl_serializer> { + static void to_json(json& j, const std::optional& opt) { + if (opt) j = *opt; + else j = nullptr; + } + static void from_json(const json& j, std::optional& opt) { + if (j.is_null()) opt = std::nullopt; + else opt = j.get(); + } + }; } +#endif // ============================================================ // Types diff --git a/ffi/codegen/cpp.nim b/ffi/codegen/cpp.nim index 652af2f..988c500 100644 --- a/ffi/codegen/cpp.nim +++ b/ffi/codegen/cpp.nim @@ -64,19 +64,35 @@ proc generateCppHeader*( lines.add("") # ── nlohmann optional support ────────────────────────────────────────── + # Use nlohmann's documented extension point (adl_serializer specialization) + # rather than free-function to_json/from_json in namespace nlohmann -- the + # latter is ODR-fragile across libraries that all do the same. Three + # guards layer the protection: + # * NIM_FFI_NO_OPTIONAL_SERIALIZER : consumer opt-out for conflicts. + # * NIM_FFI_OPTIONAL_SERIALIZER_DEFINED_ : TU-level guard so multiple + # nim-ffi-generated headers don't redefine within one translation unit. + # * nlohmann version check : nlohmann >= 3.12 ships this specialization + # natively, so we skip to avoid an ODR violation against it. + lines.add("#if !defined(NIM_FFI_NO_OPTIONAL_SERIALIZER) \\") + lines.add(" && !defined(NIM_FFI_OPTIONAL_SERIALIZER_DEFINED_) \\") + lines.add(" && (!defined(NLOHMANN_JSON_VERSION_MAJOR) \\") + lines.add(" || (NLOHMANN_JSON_VERSION_MAJOR < 3) \\") + lines.add(" || (NLOHMANN_JSON_VERSION_MAJOR == 3 && NLOHMANN_JSON_VERSION_MINOR < 12))") + lines.add("#define NIM_FFI_OPTIONAL_SERIALIZER_DEFINED_") lines.add("namespace nlohmann {") lines.add(" template") - lines.add(" void to_json(json& j, const std::optional& opt) {") - lines.add(" if (opt) j = *opt;") - lines.add(" else j = nullptr;") - lines.add(" }") - lines.add("") - lines.add(" template") - lines.add(" void from_json(const json& j, std::optional& opt) {") - lines.add(" if (j.is_null()) opt = std::nullopt;") - lines.add(" else opt = j.get();") - lines.add(" }") + lines.add(" struct adl_serializer> {") + lines.add(" static void to_json(json& j, const std::optional& opt) {") + lines.add(" if (opt) j = *opt;") + lines.add(" else j = nullptr;") + lines.add(" }") + lines.add(" static void from_json(const json& j, std::optional& opt) {") + lines.add(" if (j.is_null()) opt = std::nullopt;") + lines.add(" else opt = j.get();") + lines.add(" }") + lines.add(" };") lines.add("}") + lines.add("#endif") lines.add("") # ── Types ──────────────────────────────────────────────────────────────────