devaskim
devaskim

Reputation: 559

Custom SWIG accessor functions or struct member type cast

I need some way to cast unit8_t array to char array or to char * string both to create Job object on Python side and print it fields after getting the object from C++ side. Does SWIG support custom accessor functions (i.e. get/set) or "magic" arg cast?

I tried the @ignore feature to skip processing of identifier and name members and add %inline accessor functions but no result.

In Python:

job = someFuncInCppCode()
print("Identifier: " + job.identifier)

Error while calling Python print:

Execution error: can only concatenate str (not "SwigPyObject") to str

C++ header

struct Job
{
  static const int MaxIdentifierLength = 20;
  static const int MaxNameLength = 40;

  uint8_t  identifier[MaxIdentifierLength];
  uint8_t   name[MaxNameLength];
  uint32_t  status;
};

SWIG auto-generated code:

SWIGINTERN PyObject *_wrap_Job_identifier_get(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
    PyObject *resultobj = 0;
    Job *arg1 = (Job *) 0 ;
    void *argp1 = 0 ;
    int res1 = 0 ;
    PyObject *swig_obj[1] ;
    uint8_t *result = 0 ;

    if (!args) SWIG_fail;
    swig_obj[0] = args;
    res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_Xrite__Device_Cpp__Topaz__Job, 0 |  0 );
    if (!SWIG_IsOK(res1)) {
        SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Job_identifier_get" "', argument " "1"" of type '" "Job *""'"); 
    }
    arg1 = reinterpret_cast<Job * >(argp1);
    result = (uint8_t *)(uint8_t *) ((arg1)->identifier);
    resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_unsigned_char, 0 |  0 );
    return resultobj;
    fail:
    return NULL;
}

Upvotes: 0

Views: 267

Answers (1)

Mark Tolonen
Mark Tolonen

Reputation: 177901

One way is defining an output typemap for that array type. See Typemaps for arrays in the SWIG documentation. Example:

test.i

%module test

%include <stdint.i>

// Convert uint8_t array assumed to be a null-terminated string.
%typemap(out) uint8_t[ANY] %{
    $result = PyBytes_FromString(reinterpret_cast<char*>($1));
%}

%inline %{
#include <stdint.h>

struct Job
{
  static const int MaxIdentifierLength = 20;
  static const int MaxNameLength = 40;

  uint8_t  identifier[MaxIdentifierLength];
  uint8_t  name[MaxNameLength];
  uint32_t status;
};

// test function
Job func() {
    return {"hello","world",5};
}
%}

Demo:

>>> import test
>>> j=test.func()
>>> j.name
b'world'
>>> j.identifier
b'hello'
>>> j.status
5

If you want every byte in the array visible use this typemap instead:

%typemap(out) uint8_t[ANY] %{
    $result = PyBytes_FromStringAndSize(reinterpret_cast<char*>($1), $1_dim0);
%}

Demo:

>>> import test
>>> j=test.func()
>>> j.identifier
b'hello\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

Upvotes: 1

Related Questions