--- include/nanobind_json/nanobind_json.hpp +++ include/nanobind_json/nanobind_json.hpp @@ -13,13 +13,15 @@ #include "nlohmann/json.hpp" -#include "nanobind/nanobind.hpp" +#include +#include namespace nb = nanobind; namespace nl = nlohmann; namespace pyjson { + inline nb::object from_json(const nl::json& j) { if (j.is_null()) @@ -40,7 +42,7 @@ } else if (j.is_string()) { - return nb::str(j.get()); + return nb::str(j.get().c_str()); } else if (j.is_array()) { @@ -56,7 +58,7 @@ nb::dict obj; for (nl::json::const_iterator it = j.cbegin(); it != j.cend(); ++it) { - obj[nb::str(it.key())] = from_json(it.value()); + obj[nb::str(it.key().c_str())] = from_json(it.value()); } return std::move(obj); } @@ -70,24 +72,24 @@ } if (nb::isinstance(obj)) { - return obj.cast(); + return nb::cast(obj); } if (nb::isinstance(obj)) { - return obj.cast(); + return nb::cast(obj); } if (nb::isinstance(obj)) { - return obj.cast(); + return nb::cast(obj); } if (nb::isinstance(obj)) { - nb::module base64 = nb::module::import("base64"); - return base64.attr("b64encode")(obj).attr("decode")("utf-8").cast(); + nb::module_ base64 = nb::module_::import_("base64"); + return nb::cast(base64.attr("b64encode")(obj).attr("decode")("utf-8")); } if (nb::isinstance(obj)) { - return obj.cast(); + return nb::cast(obj); } if (nb::isinstance(obj) || nb::isinstance(obj)) { @@ -103,11 +105,11 @@ auto out = nl::json::object(); for (const nb::handle key : obj) { - out[nb::str(key).cast()] = to_json(obj[key]); + out[nb::cast(nb::str(key))] = to_json(obj[key]); } return out; } - throw std::runtime_error("to_json not implemented for this type of object: " + nb::repr(obj).cast()); + throw std::runtime_error("to_json not implemented for this type of object: " + nb::cast(nb::repr(obj))); } } @@ -123,7 +125,7 @@ j = pyjson::to_json(obj); \ } \ \ - inline static T from_json(const json& j) \ + inline static nb::object from_json(const json& j) \ { \ return pyjson::from_json(j); \ } \ @@ -151,12 +153,6 @@ MAKE_NLJSON_SERIALIZER_DESERIALIZER(nb::dict); MAKE_NLJSON_SERIALIZER_ONLY(nb::handle); - MAKE_NLJSON_SERIALIZER_ONLY(nb::detail::item_accessor); - MAKE_NLJSON_SERIALIZER_ONLY(nb::detail::list_accessor); - MAKE_NLJSON_SERIALIZER_ONLY(nb::detail::tuple_accessor); - MAKE_NLJSON_SERIALIZER_ONLY(nb::detail::sequence_accessor); - MAKE_NLJSON_SERIALIZER_ONLY(nb::detail::str_attr_accessor); - MAKE_NLJSON_SERIALIZER_ONLY(nb::detail::obj_attr_accessor); #undef MAKE_NLJSON_SERIALIZER #undef MAKE_NLJSON_SERIALIZER_ONLY @@ -167,28 +163,53 @@ { namespace detail { - template <> struct type_caster - { - public: - NANOBIND_TYPE_CASTER(nl::json, _("json")); + + template <> struct type_caster { + using Value = nl::json; - bool load(handle src, bool) - { - try { - value = pyjson::to_json(src); - return true; - } - catch (...) - { - return false; - } - } + template using Cast = Value; + + // Value name for docstring generation + static constexpr auto Name = const_name("Json"); - static handle cast(nl::json src, return_value_policy /* policy */, handle /* parent */) + /// Python -> C++ caster, populates `caster1` and `caster2` upon success + bool from_python(handle src, uint8_t flags, + cleanup_list *cleanup) noexcept { + try { + value = pyjson::to_json(src); + return true; + } + catch (...) { - object obj = pyjson::from_json(src); - return obj.release(); + return false; } - }; + } + + template + static handle from_cpp(T *value, rv_policy policy, cleanup_list *cleanup) { + if (!value) + return none().release(); + return from_cpp(*value, policy, cleanup); + } + + template + static handle from_cpp(T &&value, rv_policy policy, + cleanup_list *cleanup) noexcept { + object obj = pyjson::from_json(value); + return obj.release(); + } + + template + bool can_cast() const noexcept { + return true; + } + + /// Return the constructed tuple by copying from the sub-casters + explicit operator Value() { + return value; + } + + Value value; + }; } }