| // Test the goin, goout, and goargout typemaps. |
| |
| %module go_inout |
| |
| %{ |
| #include <string> |
| #include <vector> |
| #include <stdint.h> |
| %} |
| |
| %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<std::string> 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<uint64_t>(*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<const char *>(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<std::string>::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; |
| } |
| %} |