Поскольку вы специально запросили решения, для которых не требуется ничего конкретного языка поддержки, я бы предложил использовать %inline
для предоставления альтернативной формы func
с синтаксисом, который вы предпочитаете.Что-то вроде этого должно сделать это:
%module test
%rename(func) func_adjusted;
%newobject func_adjusted();
%inline %{
struct func1_out {
// can make tuple syntax work here if you would rather, but likely having names is clearer anyway
char buf1[4096];
size_t buf1len;
char buf2[4096];
size_t buf2len;
};
// with the rename we pretend this is the C function, but really it is specific to our wrapper module.
struct func1_out *func_adjusted() {
struct func1_out *ret = malloc(sizeof *ret);
// could also dynamically allocate buf1 and buf2 instead of fixed max size.
func(buf1, &buf1len, buf2, &buf2len);
return ret;
}
%}
%ignore func;
%include "blahblah.h"
Вы, вероятно, захотите немного больше поработать с массивами char buf1
и buf2
внутри этой структуры, чтобы сделать ее более естественной для пользователя Python, но это можно сделать с помощью carrays.i или %extend
в структуре, чтобы сохранить все это в C / SWIG, а не на Python.
Вы также можете сделать что-то не специфичноек функции, которую вы оборачиваете, используя многопараметрические карты типов.Чтобы избежать специфики Python, вы можете использовать %append_output
для возврата нескольких элементов из одной функции.Это не работает для статически типизированных языков, таких как Java или C #, но оно должно работать для большинства / всех динамически типизированных.
Чтобы в дальнейшем избежать необходимости в дополнительном, специфичном для языка коде, мы можем использовать carrays.i, которыйгенерирует некоторые дополнительные функции для каждого определяемого нами типа.В частности, мы используем ByteArray_cast
, new_ByteArray
и delete_ByteArray
для обработки довольно большого количества случаев, с которыми мы можем столкнуться.Это должно работать как для C, так и для C ++.
%module test
%include <carrays.i>
%array_class(char, ByteArray);
%typemap(in,numinputs=0) (char* mutable_buffer, size_t mutable_buffer_size) (ByteArray *tmp=NULL) {
// N.B. using new_ByteArray() here makes this work well with both C and C++ code
tmp = new_ByteArray(4096);
$1 = ByteArray_cast(tmp);
$1[0] = 0x0;
$2 = 4096;
}
%typemap(freearg) (char* mutable_buffer, size_t mutable_buffer_size) {
// conditional is needed here as in some cases delete_ByteArray would dereference a null pointer
if (tmp$argnum) delete_ByteArray(tmp$argnum);
}
%typemap(argout) (char* mutable_buffer, size_t mutable_buffer_size) {
// Take ownership from in typemap
%append_output(SWIG_NewPointerObj(SWIG_as_voidptr(tmp$argnum), $descriptor(ByteArray*), SWIG_POINTER_NEW));
tmp$argnum = NULL;
}
%apply (char *mutable_buffer, size_t mutable_buffer_size) { (char *buf, size_t buflen), (char *buf2, size_t buf2len) };
%inline %{
void func(char* buf, size_t buflen, char* buf2, size_t buf2len) {
strncpy(buf, "this is buffer1", buflen);
strncpy(buf2, "this is buffer2", buf2len);
}
%}
Это работает, как и ожидалось, с Python 3.7 в моем тестировании.Обратите внимание, что вам нужно запустить swig с аргументом -builtin
, чтобы получить точное поведение, которое вы ищете здесь, или потребовать дополнительный пользовательский код для обходного пути:
a,b = test.func()
# needed for the non builtin case, I can't see a way to avoid that without Python specific code
aa=test.ByteArray_frompointer(a)
# for the -builtin case it just works though
Здесь нетздесь нет большого выбора для аккуратных интерфейсов, потому что ваши требования довольно ограничительны:
- без использования специфичных для lang исправлений.
- У меня нет полномочий изменятьAPI.Я просто хочу сделать его простым в использовании.
С учетом этих двух факторов мало что остается открытым для использования.
Лично я предпочитаю писать некоторые специфичные для PythonC, если он делает интерфейс, который пользователи Python видят более естественным, даже если это означает, что тот же интерфейс не может быть дублирован на 100% на другом языке.Здесь есть гораздо более аккуратные решения для небольшой дополнительной языковой работы, которая обычно окупается.
Я бы сказал, что мощь SWIG заключается не в том, чтобы «написать один раз, импортировать куда угодно», а в том, чтобы помочь вам абстрагироваться и модульноспецифичные для языка части интуитивного интерфейса.