Typemaps jsoncpp => Python: recursive typemap(outargs)?

Julien Marrec <[email protected]> Wed, 3 Mar 2021 16:01:28 +0100
Newsgroups gmane.comp.programming.swig
Message-ID <CAEqKKtxmTDRDN7g-aTs2_ancc8gXpW8XPwfMpYHkxOUozsy-Qw@mail.gmail.com>
Hello,

First, has anyone wrapped jsoncpp
<https://github.com/open-source-parsers/jsoncpp> in Swig? If I can avoid
reinventing the wheel...

Otherwise, I basically have a Json::Value toJSON() method in C++.

I'd like to return a python dict instead (and a Hash in ruby...). So far,
I've done a workaround by creating a std::string toJSONString() { return
toJSON().toStyledString(); }, and using %pythoncode (and %init with
rb_eval_string in ruby). It works (see at end of email if you're curious),
but I'd like to try a typemap(argout) instead. All my attempts so far have
miserably failed, probably because:

   1. This is pretty much the first time I tried to do a typemap, and,
   2. I have no clue how to do a recursive call to the typemap(argout)
   itself.

Here is one of my attempts (I tried with Json::Value instead of Json::Value
* too)

#if defined SWIGPYTHON

%typemap(argout) Json::Value * {

  if ($1->isIntegral()) {
    $result = PyLong_FromLongLong($1->asInt64());
  } else if ($1->isNumeric()) {
    $result = PyFloat_FromDouble($1->asDouble());
  } else if ($1->isString()) {
    $result = PyUnicode_FromString($->.asString());
  } else if ($1->isArray()) {
    $result = PyList_New();
    for( const auto& n : *$1) {
        // TODO: this should do a recursive call to convert n (which
is Json::Value) to a python type...
        PyList_Append(n);
    }
  } else if ($1->isObject()) {
    $result = PyDict_New();
    for( const auto& id : $1->getMemberNames()) {
        // TODO: this should do a recursive call to convert *$1[id]
(which is a Json::Value) to a python type...
        PyDict_SetItemString($result, id.c_str(), *$1[id]);
    }
  }
}
#endif

The documentation for Json::Value is at
https://open-source-parsers.github.io/jsoncpp-docs/doxygen/class_json_1_1_value.html

*If someone could nudge me in the right direction, that'd be much
appreciated.*

Thank you,

Julien
------------------------------

For reference my current workaround: in epJSON.i:

#if defined SWIGRUBY
  // This isn't super clean and there might be a better way with
typemaps in SWIG rather than using a String in between,
  // but still helpful I think: we redefine toJSON that will return a
native ruby hash. 'json' is part of ruby stdlib since at least ruby
2.5.5
  %init %{
    rb_eval_string("OpenStudio::EPJSON.module_eval {
define_method(:toJSON) { |arg| json_str = self.toJSONString(arg);
require 'json'; JSON.load(json_str);  }; module_function(:toJSON) }");
 %}
#endif

#if defined SWIGPYTHON

  // Let's use monkey-patching via unbound functions
  // Edit: not even needed here
  %pythoncode %{
# Manually added: Lazy-load the json module (python std lib) and
return a dict via toJSONString
def toJSON(*args) -> dict:
    import json
    return json.loads(toJSONString(*args))
  %}
#endif


--
Julien Marrec, EBCP, BPI MFBA
Owner at EffiBEM <http://www.effibem.com>
T: +33 6 95 14 42 13

LinkedIn (en <https://www.linkedin.com/in/julienmarrec>) *| *(fr
<https://fr.linkedin.com/in/julienmarrec/fr>) :
<http://www.linkedin.com/in/julienmarrec>

_______________________________________________
Swig-user mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/swig-user