Use information from one argument to create another argument in typemap(in)
Question:
Currently I have the following C snippet:
typedef struct My_Struct {
int x;
int y;
} my_struct_t;
void generate_buffer(my_struct_t info, uint8_t* buffer_out);
I am trying to come up with a python swig interface to call this function. The output buffer size is in info.x
.
The following typemap I tried, but fails unfortunately:
%typemap(in) (my_struct_t info, uint8_t* buffer_out) %{
my_struct_t tmp;
int res1 = SWIG_ConvertPtr($input, (void*)&tmp, SWIGTYPE_p_My_Struct, 0 );
if (!SWIG_IsOK(res1)) {
SWIG_exception_fail(SWIG_ArgError(res1), "Converting my_struct_t type to swig");
}
$2 = (uint8_t*)malloc(tmp.x);
$1 = tmp;
%}
%typemap(argout) (my_struct_t info, uint8_t* buffer_out) (PyObject* po) %{
po = PyBytes_FromStringAndSize((char*)$2,($1).x);
$result = SWIG_Python_AppendOutput($result,po);
%}
%typemap(freearg) (my_struct_t info, uint8_t* buffer_out) %{
free($2);
%}
I was expecting the info object to be accessible as is in the C function, also the newly allocated set of bytes to be absorbed and freed in the typemap.
The input typemap fails with junk values that I am finding hard to debug.
Answers:
SWIG_ConvertPtr
takes the address of a pointer to store the conversion. The (void*)
cast hides the mistake. See comments below:
test.i
%module test
%{
#include <stdint.h>
#include <stdlib.h>
%}
%typemap(in) (my_struct_t info, uint8_t* buffer_out) (my_struct_t* tmp) %{ // needs to be a pointer
// $&1_descriptor generates the appropriate SWIG descriptor for a my_struct_t*
int res1 = SWIG_ConvertPtr($input, (void*)&tmp, $&1_descriptor, 0 );
if (!SWIG_IsOK(res1)) {
SWIG_exception_fail(SWIG_ArgError(res1), "Converting my_struct_t type to swig");
}
$2 = malloc(tmp->x); // needs -> to dereference pointer
$1 = *tmp; // needs * to pass by value
%}
%typemap(argout) (my_struct_t info, uint8_t* buffer_out) (PyObject* po) %{
po = PyBytes_FromStringAndSize((char*)$2, ($1).x);
$result = SWIG_Python_AppendOutput($result, po);
%}
%typemap(freearg) (my_struct_t info, uint8_t* buffer_out) %{
free($2);
%}
// Demo implementation
%inline %{
typedef struct My_Struct {
int x; // Used x to match typemap
int y;
} my_struct_t;
void generate_buffer(my_struct_t info, uint8_t* buffer_out) {
memset(buffer_out, info.y, info.x);
}
%}
Demo:
>>> import test
>>> i = test.my_struct_t()
>>> i.x = 10
>>> i.y = ord('A')
>>> test.generate_buffer(i)
b'AAAAAAAAAA'
Currently I have the following C snippet:
typedef struct My_Struct {
int x;
int y;
} my_struct_t;
void generate_buffer(my_struct_t info, uint8_t* buffer_out);
I am trying to come up with a python swig interface to call this function. The output buffer size is in info.x
.
The following typemap I tried, but fails unfortunately:
%typemap(in) (my_struct_t info, uint8_t* buffer_out) %{
my_struct_t tmp;
int res1 = SWIG_ConvertPtr($input, (void*)&tmp, SWIGTYPE_p_My_Struct, 0 );
if (!SWIG_IsOK(res1)) {
SWIG_exception_fail(SWIG_ArgError(res1), "Converting my_struct_t type to swig");
}
$2 = (uint8_t*)malloc(tmp.x);
$1 = tmp;
%}
%typemap(argout) (my_struct_t info, uint8_t* buffer_out) (PyObject* po) %{
po = PyBytes_FromStringAndSize((char*)$2,($1).x);
$result = SWIG_Python_AppendOutput($result,po);
%}
%typemap(freearg) (my_struct_t info, uint8_t* buffer_out) %{
free($2);
%}
I was expecting the info object to be accessible as is in the C function, also the newly allocated set of bytes to be absorbed and freed in the typemap.
The input typemap fails with junk values that I am finding hard to debug.
SWIG_ConvertPtr
takes the address of a pointer to store the conversion. The (void*)
cast hides the mistake. See comments below:
test.i
%module test
%{
#include <stdint.h>
#include <stdlib.h>
%}
%typemap(in) (my_struct_t info, uint8_t* buffer_out) (my_struct_t* tmp) %{ // needs to be a pointer
// $&1_descriptor generates the appropriate SWIG descriptor for a my_struct_t*
int res1 = SWIG_ConvertPtr($input, (void*)&tmp, $&1_descriptor, 0 );
if (!SWIG_IsOK(res1)) {
SWIG_exception_fail(SWIG_ArgError(res1), "Converting my_struct_t type to swig");
}
$2 = malloc(tmp->x); // needs -> to dereference pointer
$1 = *tmp; // needs * to pass by value
%}
%typemap(argout) (my_struct_t info, uint8_t* buffer_out) (PyObject* po) %{
po = PyBytes_FromStringAndSize((char*)$2, ($1).x);
$result = SWIG_Python_AppendOutput($result, po);
%}
%typemap(freearg) (my_struct_t info, uint8_t* buffer_out) %{
free($2);
%}
// Demo implementation
%inline %{
typedef struct My_Struct {
int x; // Used x to match typemap
int y;
} my_struct_t;
void generate_buffer(my_struct_t info, uint8_t* buffer_out) {
memset(buffer_out, info.y, info.x);
}
%}
Demo:
>>> import test
>>> i = test.my_struct_t()
>>> i.x = 10
>>> i.y = ord('A')
>>> test.generate_buffer(i)
b'AAAAAAAAAA'