// Test the goin, goout, and goargout typemaps. %module go_inout %{ #include #include #include %} %inline %{ struct MyStruct { std::string str; }; struct RetStruct { std::string str; }; %} // Write a typemap that calls C++ by converting in and out of JSON. %go_import("encoding/json", "bytes", "encoding/binary", "reflect", "unsafe") %insert(go_header) %{ type In json.Marshaler %} %typemap(gotype) MyStruct "In" %typemap(imtype) MyStruct "string" %typemap(goin) MyStruct %{ { b, err := $input.MarshalJSON() if err != nil { panic(err) } $result = string(b) } %} %typemap(in) MyStruct %{ $1.str.assign($input.p, $input.n); %} %typemap(gotype) RetStruct "map[string]interface{}" %typemap(imtype) RetStruct "string" %typemap(out,fragment="AllocateString") RetStruct %{ $result = Swig_AllocateString($1.str.data(), $1.str.length()); %} %typemap(goout,fragment="CopyString") RetStruct %{ if err := json.Unmarshal([]byte(swigCopyString($1)), &$result); err != nil { panic(err) } %} %typemap(gotype) RetStruct* "*map[string]interface{}" %typemap(imtype) RetStruct* "*string" %typemap(out,fragment="AllocateString") RetStruct* %{ $result = (_gostring_*)malloc(sizeof(_gostring_)); *$result = Swig_AllocateString($1->str.data(), $1->str.length()); %} %typemap(goout,fragment="CopyString") RetStruct* %{ defer Swig_free(uintptr(unsafe.Pointer($1))) var rm map[string]interface{} if err := json.Unmarshal([]byte(swigCopyString(*$1)), &rm); err != nil { panic(err) } $result = &rm %} %inline %{ RetStruct Same(MyStruct s) { RetStruct r; r.str = s.str; return r; } %} %inline %{ struct MyArray { std::vector strings; }; void* Allocate(int n) { return new char[n]; } static uint64_t getuint64(const char* s) { uint64_t ret = 0; for (int i = 0; i < 8; i++, s++) { ret |= static_cast(*s) << i * 8; } return ret; } static void putuint64(std::string *s, size_t off, uint64_t v) { for (int i = 0; i < 8; i++) { (*s)[off + i] = (v >> (i * 8)) & 0xff; } } %} %typemap(gotype) MyArray* "*[]string" %typemap(imtype) MyArray* "*string" // Encode the slice as a single string, with length prefixes. %typemap(goin) MyArray* %{ { var buf bytes.Buffer bin := binary.LittleEndian var b [8]byte bin.PutUint64(b[:], uint64(len(*$input))) buf.Write(b[:]) for _, s := range *$input { bin.PutUint64(b[:], uint64(len(s))) buf.Write(b[:]) buf.WriteString(s) } bb := buf.Bytes() p := Allocate(len(bb)) copy((*[1<<15]byte)(unsafe.Pointer(p))[:len(bb)], bb) var str string (*reflect.StringHeader)(unsafe.Pointer(&str)).Data = uintptr(unsafe.Pointer(p)) (*reflect.StringHeader)(unsafe.Pointer(&str)).Len = len(bb) $result = &str } %} // Unpack the string holding the packed slice. %typemap(in) MyArray* (MyArray t) %{ { _gostring_ *s = $input; const char *p = static_cast(s->p); uint64_t len = getuint64(p); p += 8; t.strings.resize(len); for (uint64_t i = 0; i < len; i++) { uint64_t slen = getuint64(p); p += 8; t.strings[i].assign(p, slen); p += slen; } $1 = &t; } %} // Pack the vector into a string. %typemap(argout,fragment="AllocateString") MyArray* %{ { size_t tot = 8; std::vector::const_iterator p; for (p = $1->strings.begin(); p != $1->strings.end(); ++p) { tot += 8 + p->size(); } std::string str; str.resize(tot); putuint64(&str, 0, $1->strings.size()); size_t off = 8; for (p = $1->strings.begin(); p != $1->strings.end(); ++p) { putuint64(&str, off, p->size()); off += 8; str.replace(off, p->size(), *p); off += p->size(); } *$input = Swig_AllocateString(str.data(), str.size()); } %} // Unpack the string into a []string. %typemap(goargout,fragment="CopyString") MyArray* %{ { str := swigCopyString(*$input) bin := binary.LittleEndian size := bin.Uint64([]byte(str[:8])) str = str[8:] r := make([]string, size) for i := range r { len := bin.Uint64([]byte(str[:8])) str = str[8:] r[i] = str[:len] str = str[len:] } *$1 = r } %} %inline %{ void DoubleArray(MyArray* v) { size_t size = v->strings.size(); for (size_t i = 0; i < size; i++) { v->strings.push_back(v->strings[i] + v->strings[i]); } } %} %inline %{ class C1 { public: RetStruct* M() { RetStruct* r = new RetStruct; r->str = "{\"ID\":1}"; return r; } }; class C2 : public C1 { public: void M2(C1*) {} }; %} %typemap(gotype) (char *ps[], int cs) "[]string" %typemap(in) (char *ps[], int cs) %{ { int i; _gostring_* a; $2 = $input.len; a = (_gostring_*) $input.array; $1 = (char **) malloc (($2 + 1) * sizeof (char *)); for (i = 0; i < $2; i++) { _gostring_ *ps = &a[i]; $1[i] = (char *) malloc(ps->n + 1); memcpy($1[i], ps->p, ps->n); $1[i][ps->n] = '\0'; } $1[i] = NULL; } %} %typemap(freearg) (char *ps[], int cs) %{ { int i; for (i = 0; i < $2; i++) { free($1[i]); } free($1); } %} %inline %{ bool Strings(char *ps[], int cs) { return cs == 2 && strcmp(ps[0], "1") == 0 && strcmp(ps[1], "2") == 0 & ps[2] == NULL; } %}