├── cgoflags.go ├── ffi_darwin.go ├── ffi_linux.go ├── ffi_linux_test.go ├── dl ├── dl_darwin_test.go ├── dl_linux_test.go ├── dl_test.go └── dl.go ├── ffi_darwin_test.go ├── doc.go ├── .travis.yml ├── encoder.go ├── decoder.go ├── LICENSE ├── README.md ├── ffi_test.go ├── type_test.go ├── ffi.go ├── type.go ├── value.go └── value_test.go /cgoflags.go: -------------------------------------------------------------------------------- 1 | package ffi 2 | 3 | // #cgo pkg-config: libffi 4 | // #include "ffi.h" 5 | import "C" 6 | 7 | // EOF 8 | -------------------------------------------------------------------------------- /ffi_darwin.go: -------------------------------------------------------------------------------- 1 | package ffi 2 | 3 | const ( 4 | g_lib_prefix = "lib" 5 | g_lib_suffix = ".dylib" 6 | ) 7 | 8 | // EOF 9 | -------------------------------------------------------------------------------- /ffi_linux.go: -------------------------------------------------------------------------------- 1 | package ffi 2 | 3 | const ( 4 | g_lib_prefix = "lib" 5 | g_lib_suffix = ".so" 6 | ) 7 | 8 | // EOF 9 | -------------------------------------------------------------------------------- /ffi_linux_test.go: -------------------------------------------------------------------------------- 1 | package ffi_test 2 | 3 | var libc_name = "libc.so.6" 4 | var libm_name = "libm.so.6" 5 | 6 | // EOF 7 | -------------------------------------------------------------------------------- /dl/dl_darwin_test.go: -------------------------------------------------------------------------------- 1 | package dl_test 2 | 3 | var libc_name = "libc.dylib" 4 | var libm_name = "libm.dylib" 5 | 6 | // EOF 7 | -------------------------------------------------------------------------------- /dl/dl_linux_test.go: -------------------------------------------------------------------------------- 1 | package dl_test 2 | 3 | var libc_name = "libc.so.6" 4 | var libm_name = "libm.so.6" 5 | 6 | // EOF 7 | -------------------------------------------------------------------------------- /ffi_darwin_test.go: -------------------------------------------------------------------------------- 1 | package ffi_test 2 | 3 | var libc_name = "libc.dylib" 4 | var libm_name = "libm.dylib" 5 | 6 | // EOF 7 | -------------------------------------------------------------------------------- /doc.go: -------------------------------------------------------------------------------- 1 | // ffi provides an easy way to call into C code using the 2 | // libffi Foreign Function Interface library 3 | package ffi 4 | 5 | // EOF 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - 1.2 5 | 6 | before_install: 7 | - sudo apt-get update -qq 8 | - sudo apt-get install libffi-dev -qq 9 | 10 | notifications: 11 | email: 12 | recipients: 13 | - binet@cern.ch 14 | on_success: change 15 | on_failure: always 16 | -------------------------------------------------------------------------------- /encoder.go: -------------------------------------------------------------------------------- 1 | package ffi 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | // NewEncoder returns a new encoder that writes to v. 9 | func NewEncoder(v Value) *Encoder { 10 | enc := &Encoder{cval: v} 11 | return enc 12 | } 13 | 14 | // An Encoder writes Go objects to a C-binary blob 15 | type Encoder struct { 16 | cval Value 17 | } 18 | 19 | func (enc *Encoder) Encode(v interface{}) error { 20 | rv := reflect.ValueOf(v) 21 | rt := reflect.TypeOf(v) 22 | //fmt.Printf("::Encode: %v %v\n", rt.Name(), rv) 23 | // make sure we can encode this value v into enc.cval 24 | ct := ctype_from_gotype(rt) 25 | //if ct.Name() != enc.cval.Type().Name() { 26 | if !is_compatible(ct, enc.cval.Type()) { 27 | return fmt.Errorf("ffi.Encode: can not encode go-type [%s] (with c-type [%s]) into c-type [%s]", rt.Name(), ct.Name(), enc.cval.Type().Name()) 28 | } 29 | return enc.encode_value(rv) 30 | } 31 | 32 | func (enc *Encoder) encode_value(v reflect.Value) (err error) { 33 | enc.cval.set_value(v) 34 | defer func() { 35 | if r := recover(); r != nil { 36 | err = fmt.Errorf("ffi.Encoder: %v", r) 37 | } 38 | }() 39 | return err 40 | } 41 | 42 | // EOF 43 | -------------------------------------------------------------------------------- /dl/dl_test.go: -------------------------------------------------------------------------------- 1 | package dl_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/sbinet/go-ffi/dl" 7 | ) 8 | 9 | func TestDlOpenLibc(t *testing.T) { 10 | lib, err := dl.Open(libc_name, dl.Now) 11 | if err != nil { 12 | t.Errorf("%v", err) 13 | } 14 | err = lib.Close() 15 | if err != nil { 16 | t.Errorf("%v", err) 17 | } 18 | } 19 | 20 | func TestDlSymLibc(t *testing.T) { 21 | lib, err := dl.Open(libc_name, dl.Now) 22 | 23 | if err != nil { 24 | t.Errorf("%v", err) 25 | } 26 | 27 | _, err = lib.Symbol("puts") 28 | if err != nil { 29 | t.Errorf("%v", err) 30 | } 31 | 32 | err = lib.Close() 33 | if err != nil { 34 | t.Errorf("%v", err) 35 | } 36 | } 37 | 38 | func TestDlOpenLibm(t *testing.T) { 39 | lib, err := dl.Open(libm_name, dl.Now) 40 | if err != nil { 41 | t.Errorf("%v", err) 42 | } 43 | err = lib.Close() 44 | if err != nil { 45 | t.Errorf("%v", err) 46 | } 47 | } 48 | 49 | func TestDlSymLibm(t *testing.T) { 50 | lib, err := dl.Open(libm_name, dl.Now) 51 | 52 | if err != nil { 53 | t.Errorf("%v", err) 54 | } 55 | 56 | _, err = lib.Symbol("fabs") 57 | if err != nil { 58 | t.Errorf("%v", err) 59 | } 60 | 61 | err = lib.Close() 62 | if err != nil { 63 | t.Errorf("%v", err) 64 | } 65 | } 66 | 67 | // EOF 68 | -------------------------------------------------------------------------------- /decoder.go: -------------------------------------------------------------------------------- 1 | package ffi 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | // NewDecoder returns a new decoder that reads from v. 9 | func NewDecoder(v Value) *Decoder { 10 | dec := &Decoder{cval: v} 11 | return dec 12 | } 13 | 14 | // A Decoder reads Go objects from a C-binary blob 15 | type Decoder struct { 16 | cval Value 17 | } 18 | 19 | func (dec *Decoder) Decode(v interface{}) error { 20 | rv := reflect.ValueOf(v) 21 | rt := reflect.TypeOf(v) 22 | // FIXME ? 23 | if rt.Kind() == reflect.Ptr { 24 | rt = rt.Elem() 25 | } 26 | // make sure we can decode this value v from dec.cval 27 | ct := ctype_from_gotype(rt) 28 | if !is_compatible(ct, dec.cval.Type()) { 29 | return fmt.Errorf("ffi.Decode: can not decode go-type [%s] (with c-type [%s]) from c-type [%s]", rt.Name(), ct.Name(), dec.cval.Type().Name()) 30 | } 31 | return dec.decode_value(rv) 32 | } 33 | 34 | func (dec *Decoder) decode_value(v reflect.Value) (err error) { 35 | rt := v.Type() 36 | switch rt.Kind() { 37 | case reflect.Ptr: 38 | rt = rt.Elem() 39 | v = v.Elem() 40 | case reflect.Slice: 41 | v = v 42 | default: 43 | v = v.Elem() 44 | } 45 | 46 | v.Set(dec.cval.GoValue()) 47 | defer func() { 48 | if r := recover(); r != nil { 49 | err = fmt.Errorf("ffi.Decoder: %v", r) 50 | } 51 | }() 52 | return 53 | } 54 | 55 | // EOF 56 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2008 The NetBSD Foundation, Inc. 3 | * All rights reserved. 4 | * 5 | * This code is derived from software contributed to The NetBSD Foundation 6 | * by 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions 10 | * are met: 11 | * 1. Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * 2. Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 18 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 19 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 21 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | * POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | go-ffi 2 | ====== 3 | 4 | [![Build Status](https://drone.io/github.com/sbinet/go-ffi/status.png)](https://drone.io/github.com/sbinet/go-ffi/latest) 5 | [![Build Status](https://secure.travis-ci.org/sbinet/go-ffi.png)](http://travis-ci.org/sbinet/go-ffi) 6 | 7 | The ``ffi`` package wraps the ``libffi`` ``C`` library (and ``dlopen/dlclose``) to provide an easy way to call arbitrary functions from ``Go``. 8 | 9 | **DEPRECATED** Please use `github.com/gonuts/ffi` instead. 10 | 11 | Installation 12 | ------------ 13 | 14 | ``ffi`` is go-get-able: 15 | 16 | ``` 17 | $ go get github.com/sbinet/go-ffi 18 | ``` 19 | 20 | Example 21 | ------- 22 | 23 | ``` go 24 | // dl-open a library: here, the math library on darwin 25 | lib, err := ffi.NewLibrary("libm.dylib") 26 | handle_err(err) 27 | 28 | // get a handle to 'cos', with the correct signature 29 | cos, err := lib.Fct("cos", ffi.Double, []Type{ffi.Double}) 30 | handle_err(err) 31 | 32 | // call it 33 | out := cos(0.).Float() 34 | println("cos(0.)=", out) 35 | 36 | err = lib.Close() 37 | handle_err(err) 38 | ``` 39 | 40 | Limitations/TODO 41 | ----------------- 42 | 43 | - no check is performed b/w what the user provides as a signature and the "real" signature 44 | 45 | - it would be handy to use some tool to automatically infer the "real" function signature 46 | 47 | - it would be handy to also handle structs 48 | 49 | - better handling of types with no direct equivalent in go 50 | (short,void,...) 51 | 52 | - better handling of C_string and conversion to/from Go strings 53 | 54 | Documentation 55 | ------------- 56 | 57 | http://go.pkgdoc.org/github.com/sbinet/go-ffi/pkg/ffi 58 | 59 | -------------------------------------------------------------------------------- /dl/dl.go: -------------------------------------------------------------------------------- 1 | package dl 2 | 3 | // #include 4 | // #include 5 | // #cgo LDFLAGS: -ldl 6 | import "C" 7 | 8 | import ( 9 | "fmt" 10 | "unsafe" 11 | ) 12 | 13 | type Flags int 14 | 15 | const ( 16 | Lazy Flags = C.RTLD_LAZY 17 | Now Flags = C.RTLD_NOW 18 | Global Flags = C.RTLD_GLOBAL 19 | Local Flags = C.RTLD_LOCAL 20 | NoLoad Flags = C.RTLD_NOLOAD 21 | NoDelete Flags = C.RTLD_NODELETE 22 | // First Flags = C.RTLD_FIRST 23 | ) 24 | 25 | type Handle struct { 26 | c unsafe.Pointer 27 | } 28 | 29 | func Open(fname string, flags Flags) (Handle, error) { 30 | c_str := C.CString(fname) 31 | defer C.free(unsafe.Pointer(c_str)) 32 | 33 | h := C.dlopen(c_str, C.int(flags)) 34 | if h == nil { 35 | c_err := C.dlerror() 36 | return Handle{}, fmt.Errorf("dl: %s", C.GoString(c_err)) 37 | } 38 | return Handle{h}, nil 39 | } 40 | 41 | func (h Handle) Close() error { 42 | o := C.dlclose(h.c) 43 | if o != C.int(0) { 44 | c_err := C.dlerror() 45 | return fmt.Errorf("dl: %s", C.GoString(c_err)) 46 | } 47 | return nil 48 | } 49 | 50 | func (h Handle) Addr() uintptr { 51 | return uintptr(h.c) 52 | } 53 | 54 | func (h Handle) Symbol(symbol string) (uintptr, error) { 55 | c_sym := C.CString(symbol) 56 | defer C.free(unsafe.Pointer(c_sym)) 57 | 58 | c_addr := C.dlsym(h.c, c_sym) 59 | if c_addr == nil { 60 | c_err := C.dlerror() 61 | return 0, fmt.Errorf("dl: %s", C.GoString(c_err)) 62 | } 63 | return uintptr(c_addr), nil 64 | } 65 | 66 | // /* Portable libltdl versions of the system dlopen() API. */ 67 | // LT_SCOPE lt_dlhandle lt_dlopen (const char *filename); 68 | // LT_SCOPE lt_dlhandle lt_dlopenext (const char *filename); 69 | // LT_SCOPE lt_dlhandle lt_dlopenadvise (const char *filename, 70 | // lt_dladvise advise); 71 | // LT_SCOPE void * lt_dlsym (lt_dlhandle handle, const char *name); 72 | // LT_SCOPE const char *lt_dlerror (void); 73 | // LT_SCOPE int lt_dlclose (lt_dlhandle handle); 74 | 75 | // EOF 76 | -------------------------------------------------------------------------------- /ffi_test.go: -------------------------------------------------------------------------------- 1 | package ffi_test 2 | 3 | import ( 4 | "math" 5 | "path" 6 | "reflect" 7 | "runtime" 8 | "testing" 9 | 10 | ffi "github.com/sbinet/go-ffi" 11 | ) 12 | 13 | func eq(t *testing.T, ref, chk interface{}) { 14 | _, file, line, _ := runtime.Caller(1) 15 | file = path.Base(file) 16 | if !reflect.DeepEqual(ref, chk) { 17 | t.Errorf("%s:%d: expected [%v], got [%v]", file, line, ref, chk) 18 | } 19 | } 20 | 21 | type info struct { 22 | fct string // fct name 23 | arg float64 24 | res float64 // expected value 25 | } 26 | 27 | func TestFFIMathf(t *testing.T) { 28 | lib, err := ffi.NewLibrary(libm_name) 29 | 30 | if err != nil { 31 | t.Errorf("%v", err) 32 | } 33 | 34 | tests := []info{ 35 | {"cos", 0., math.Cos(0.)}, 36 | {"cos", math.Pi / 2., math.Cos(math.Pi / 2.)}, 37 | {"sin", 0., math.Sin(0.)}, 38 | {"sin", math.Pi / 2., math.Sin(math.Pi / 2.)}, 39 | } 40 | 41 | for _, info := range tests { 42 | f, err := lib.Fct(info.fct, ffi.C_double, []ffi.Type{ffi.C_double}) 43 | if err != nil { 44 | t.Errorf("could not locate function [%s]: %v", info.fct, err) 45 | } 46 | out := f(info.arg).Float() 47 | if math.Abs(out-info.res) > 1e-16 { 48 | t.Errorf("expected [%v], got [%v] (fct=%v(%v))", info.res, out, info.fct, info.arg) 49 | } 50 | 51 | } 52 | 53 | err = lib.Close() 54 | if err != nil { 55 | t.Errorf("error closing [%s]: %v", libm_name, err) 56 | } 57 | } 58 | 59 | func TestFFIMathi(t *testing.T) { 60 | lib, err := ffi.NewLibrary(libm_name) 61 | 62 | if err != nil { 63 | t.Errorf("%v", err) 64 | } 65 | 66 | f, err := lib.Fct("abs", ffi.C_int, []ffi.Type{ffi.C_int}) 67 | if err != nil { 68 | t.Errorf("could not locate function [abs]: %v", err) 69 | } 70 | { 71 | out := f(10).Int() 72 | if out != 10 { 73 | t.Errorf("expected [10], got [%v] (fct=abs(10))", out) 74 | } 75 | 76 | } 77 | { 78 | out := f(-10).Int() 79 | if out != 10 { 80 | t.Errorf("expected [10], got [%v] (fct=abs(-10))", out) 81 | } 82 | 83 | } 84 | 85 | err = lib.Close() 86 | if err != nil { 87 | t.Errorf("error closing [%s]: %v", libm_name, err) 88 | } 89 | } 90 | 91 | func TestFFIStrCmp(t *testing.T) { 92 | lib, err := ffi.NewLibrary(libc_name) 93 | 94 | if err != nil { 95 | t.Errorf("%v", err) 96 | } 97 | 98 | //int strcmp(const char* cs, const char* ct); 99 | f, err := lib.Fct("strcmp", ffi.C_int, []ffi.Type{ffi.C_pointer, ffi.C_pointer}) 100 | if err != nil { 101 | t.Errorf("could not locate function [strcmp]: %v", err) 102 | } 103 | { 104 | s1 := "foo" 105 | s2 := "foo" 106 | out := f(s1, s2).Int() 107 | if out != 0 { 108 | t.Errorf("expected [0], got [%v]", out) 109 | } 110 | 111 | } 112 | { 113 | s1 := "foo" 114 | s2 := "foo1" 115 | out := f(s1, s2).Int() 116 | if out == 0 { 117 | t.Errorf("expected [!0], got [%v]", out) 118 | } 119 | 120 | } 121 | 122 | err = lib.Close() 123 | if err != nil { 124 | t.Errorf("error closing [%s]: %v", libc_name, err) 125 | } 126 | } 127 | 128 | func TestFFIStrLen(t *testing.T) { 129 | lib, err := ffi.NewLibrary(libc_name) 130 | 131 | if err != nil { 132 | t.Errorf("%v", err) 133 | } 134 | 135 | //size_t strlen(const char* cs); 136 | f, err := lib.Fct("strlen", ffi.C_int, []ffi.Type{ffi.C_pointer}) 137 | if err != nil { 138 | t.Errorf("could not locate function [strlen]: %v", err) 139 | } 140 | { 141 | str := `foo-bar-\nfoo foo` 142 | out := int(f(str).Int()) 143 | if out != len(str) { 144 | t.Errorf("expected [%d], got [%d]", len(str), out) 145 | } 146 | 147 | } 148 | 149 | err = lib.Close() 150 | if err != nil { 151 | t.Errorf("error closing [%s]: %v", libc_name, err) 152 | } 153 | } 154 | 155 | func TestFFIStrCat(t *testing.T) { 156 | lib, err := ffi.NewLibrary(libc_name) 157 | 158 | if err != nil { 159 | t.Errorf("%v", err) 160 | } 161 | 162 | //char* strcat(char* s, const char* ct); 163 | f, err := lib.Fct("strcat", ffi.C_pointer, []ffi.Type{ffi.C_pointer, ffi.C_pointer}) 164 | if err != nil { 165 | t.Errorf("could not locate function [strlen]: %v", err) 166 | } 167 | { 168 | s1 := "foo" 169 | s2 := "bar" 170 | out := f(s1, s2).String() 171 | //FIXME 172 | if out != "foobar" && false { 173 | t.Errorf("expected [foobar], got [%s] (s1=%s, s2=%s)", out, s1, s2) 174 | } 175 | 176 | } 177 | 178 | err = lib.Close() 179 | if err != nil { 180 | t.Errorf("error closing [%s]: %v", libc_name, err) 181 | } 182 | } 183 | 184 | // EOF 185 | -------------------------------------------------------------------------------- /type_test.go: -------------------------------------------------------------------------------- 1 | package ffi_test 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "testing" 7 | "unsafe" 8 | 9 | ffi "github.com/sbinet/go-ffi" 10 | ) 11 | 12 | func TestBuiltinTypes(t *testing.T) { 13 | for _, table := range []struct { 14 | n string 15 | t ffi.Type 16 | rt reflect.Type 17 | }{ 18 | {"unsigned char", ffi.C_uchar, reflect.TypeOf(byte(0))}, 19 | {"char", ffi.C_char, reflect.TypeOf(byte(0))}, 20 | 21 | {"int8", ffi.C_int8, reflect.TypeOf(int8(0))}, 22 | {"uint8", ffi.C_uint8, reflect.TypeOf(uint8(0))}, 23 | {"int16", ffi.C_int16, reflect.TypeOf(int16(0))}, 24 | {"uint16", ffi.C_uint16, reflect.TypeOf(uint16(0))}, 25 | {"int32", ffi.C_int32, reflect.TypeOf(int32(0))}, 26 | {"uint32", ffi.C_uint32, reflect.TypeOf(uint32(0))}, 27 | {"int64", ffi.C_int64, reflect.TypeOf(int64(0))}, 28 | {"uint64", ffi.C_uint64, reflect.TypeOf(uint64(0))}, 29 | 30 | {"float", ffi.C_float, reflect.TypeOf(float32(0))}, 31 | {"double", ffi.C_double, reflect.TypeOf(float64(0))}, 32 | //FIXME: use float128 when/if available 33 | //{"long double", ffi.C_longdouble, reflect.TypeOf(complex128(0))}, 34 | 35 | {"*", ffi.C_pointer, reflect.TypeOf((*int)(nil))}, 36 | } { 37 | if table.n != table.t.Name() { 38 | t.Errorf("expected [%s], got [%s]", table.n, table.t.Name()) 39 | } 40 | if table.t.Size() != table.rt.Size() { 41 | t.Errorf("expected [%d], got [%d] (type=%q)", table.t.Size(), table.rt.Size(), table.n) 42 | } 43 | } 44 | } 45 | 46 | func TestNewStructType(t *testing.T) { 47 | 48 | arr10, err := ffi.NewArrayType(10, ffi.C_int32) 49 | if err != nil { 50 | t.Errorf(err.Error()) 51 | } 52 | eq(t, int(10), arr10.Len()) 53 | 54 | for _, table := range []struct { 55 | name string 56 | fields []ffi.Field 57 | size uintptr 58 | offsets []uintptr 59 | }{ 60 | {"struct_0", 61 | []ffi.Field{{"a", ffi.C_int}}, 62 | ffi.C_int.Size(), 63 | []uintptr{0}, 64 | }, 65 | {"struct_1", 66 | []ffi.Field{ 67 | {"a", ffi.C_int}, 68 | {"b", ffi.C_int}, 69 | }, 70 | ffi.C_int.Size() + ffi.C_int.Size(), 71 | []uintptr{0, ffi.C_int.Size()}, 72 | }, 73 | {"struct_2", 74 | []ffi.Field{ 75 | {"F1", ffi.C_uint8}, 76 | {"F2", ffi.C_int16}, 77 | {"F3", ffi.C_int32}, 78 | {"F4", ffi.C_uint8}, 79 | }, 80 | 12, 81 | []uintptr{0, 2, 4, 8}, 82 | }, 83 | //FIXME: 32b/64b alignement differ!! 84 | // make 2 tests! 85 | // {"struct_3", 86 | // []ffi.Field{ 87 | // {"F1", ffi.C_uint8}, 88 | // {"F2", arr10}, 89 | // {"F3", ffi.C_int32}, 90 | // {"F4", ffi.C_uint8}, 91 | // }, 92 | // 56, 93 | // []uintptr{0, 8, 48, 52}, 94 | // }, 95 | } { 96 | typ, err := ffi.NewStructType(table.name, table.fields) 97 | if err != nil { 98 | t.Errorf(err.Error()) 99 | } 100 | eq(t, table.name, typ.Name()) 101 | //eq(t, table.size, typ.Size()) 102 | if table.size != typ.Size() { 103 | t.Errorf("expected size [%d] got [%d] (type=%q)", table.size, typ.Size(), table.name) 104 | } 105 | eq(t, len(table.offsets), typ.NumField()) 106 | for i := 0; i < typ.NumField(); i++ { 107 | if table.offsets[i] != typ.Field(i).Offset { 108 | t.Errorf("type=%q field=%d: expected offset [%d]. got [%d]", table.name, i, table.offsets[i], typ.Field(i).Offset) 109 | } 110 | //eq(t, table.offsets[i], typ.Field(i).Offset) 111 | } 112 | eq(t, ffi.Struct, typ.Kind()) 113 | } 114 | 115 | // test type mismatch 116 | n := "struct_type_err" 117 | st, err := ffi.NewStructType(n, []ffi.Field{{"a", ffi.C_int}}) 118 | if err != nil { 119 | t.Errorf(err.Error()) 120 | } 121 | { 122 | // check we get the exact same instance 123 | st_dup, err := ffi.NewStructType(n, []ffi.Field{{"a", ffi.C_int}}) 124 | if err != nil { 125 | t.Errorf(err.Error()) 126 | } 127 | if !reflect.DeepEqual(st_dup, st) { 128 | t.Errorf("NewStructType is not idem-potent") 129 | } 130 | } 131 | { 132 | _, err := ffi.NewStructType( 133 | n, 134 | []ffi.Field{{"a", ffi.C_int}, {"b", ffi.C_int}}) 135 | if err == nil { 136 | t.Errorf("failed to raise an error") 137 | } 138 | errmsg := fmt.Sprintf("ffi.NewStructType: inconsistent re-declaration of [%s]", n) 139 | if err.Error() != errmsg { 140 | t.Errorf("failed to detect number of fields differ: %v", err) 141 | } 142 | } 143 | { 144 | _, err := ffi.NewStructType(n, []ffi.Field{{"b", ffi.C_int}}) 145 | if err == nil { 146 | t.Errorf("failed to raise an error") 147 | } 148 | errmsg := fmt.Sprintf("ffi.NewStructType: inconsistent re-declaration of [%s] (field #0 name mismatch)", n) 149 | if err.Error() != errmsg { 150 | t.Errorf("failed to detect field-name mismatch: %v", err) 151 | } 152 | } 153 | { 154 | _, err := ffi.NewStructType(n, []ffi.Field{{"a", ffi.C_uint}}) 155 | if err == nil { 156 | t.Errorf("failed to raise an error") 157 | } 158 | errmsg := fmt.Sprintf("ffi.NewStructType: inconsistent re-declaration of [%s] (field #0 type mismatch)", n) 159 | if err.Error() != errmsg { 160 | t.Errorf("failed to detect field-type mismatch: %v", err) 161 | } 162 | } 163 | } 164 | 165 | func TestNewArrayType(t *testing.T) { 166 | 167 | s_t, err := ffi.NewStructType("s_0", []ffi.Field{{"a", ffi.C_int32}}) 168 | if err != nil { 169 | t.Errorf(err.Error()) 170 | } 171 | 172 | p_s_t, err := ffi.NewPointerType(s_t) 173 | if err != nil { 174 | t.Errorf(err.Error()) 175 | } 176 | 177 | for _, table := range []struct { 178 | name string 179 | n int 180 | elem ffi.Type 181 | }{ 182 | {"uint8[10]", 10, ffi.C_uint8}, 183 | {"uint16[10]", 10, ffi.C_uint16}, 184 | {"uint32[10]", 10, ffi.C_uint32}, 185 | {"uint64[10]", 10, ffi.C_uint64}, 186 | {"int8[10]", 10, ffi.C_int8}, 187 | {"int16[10]", 10, ffi.C_int16}, 188 | {"int32[10]", 10, ffi.C_int32}, 189 | {"int64[10]", 10, ffi.C_int64}, 190 | 191 | {"float[10]", 10, ffi.C_float}, 192 | {"double[10]", 10, ffi.C_double}, 193 | 194 | {"s_0[10]", 10, s_t}, 195 | {"s_0*[10]", 10, p_s_t}, 196 | } { 197 | typ, err := ffi.NewArrayType(table.n, table.elem) 198 | if err != nil { 199 | t.Errorf(err.Error()) 200 | } 201 | eq(t, table.name, typ.Name()) 202 | eq(t, table.elem, typ.Elem()) 203 | eq(t, uintptr(table.n)*table.elem.Size(), typ.Size()) 204 | eq(t, table.n, typ.Len()) 205 | eq(t, ffi.Array, typ.Kind()) 206 | } 207 | } 208 | 209 | func TestNewSliceType(t *testing.T) { 210 | 211 | capSize := 2 * unsafe.Sizeof(reflect.SliceHeader{}.Cap) 212 | 213 | s_t, err := ffi.NewStructType("s_0", []ffi.Field{{"a", ffi.C_int32}}) 214 | if err != nil { 215 | t.Errorf(err.Error()) 216 | } 217 | 218 | p_s_t, err := ffi.NewPointerType(s_t) 219 | if err != nil { 220 | t.Errorf(err.Error()) 221 | } 222 | 223 | for _, table := range []struct { 224 | name string 225 | elem ffi.Type 226 | }{ 227 | {"uint8[]", ffi.C_uint8}, 228 | {"uint16[]", ffi.C_uint16}, 229 | {"uint32[]", ffi.C_uint32}, 230 | {"uint64[]", ffi.C_uint64}, 231 | {"int8[]", ffi.C_int8}, 232 | {"int16[]", ffi.C_int16}, 233 | {"int32[]", ffi.C_int32}, 234 | {"int64[]", ffi.C_int64}, 235 | 236 | {"float[]", ffi.C_float}, 237 | {"double[]", ffi.C_double}, 238 | 239 | {"s_0[]", s_t}, 240 | {"s_0*[]", p_s_t}, 241 | } { 242 | typ, err := ffi.NewSliceType(table.elem) 243 | if err != nil { 244 | t.Errorf(err.Error()) 245 | } 246 | eq(t, table.name, typ.Name()) 247 | eq(t, table.elem, typ.Elem()) 248 | eq(t, capSize+ffi.C_pointer.Size(), typ.Size()) 249 | //eq(t, table.n, typ.Len()) 250 | eq(t, ffi.Slice, typ.Kind()) 251 | } 252 | } 253 | 254 | func TestNewPointerType(t *testing.T) { 255 | s_t, err := ffi.NewStructType("s_0", []ffi.Field{{"a", ffi.C_int32}}) 256 | if err != nil { 257 | t.Errorf(err.Error()) 258 | } 259 | 260 | p_s_t, err := ffi.NewPointerType(s_t) 261 | if err != nil { 262 | t.Errorf(err.Error()) 263 | } 264 | 265 | for _, table := range []struct { 266 | name string 267 | elem ffi.Type 268 | }{ 269 | {"int8*", ffi.C_int8}, 270 | {"int16*", ffi.C_int16}, 271 | {"int32*", ffi.C_int32}, 272 | {"int64*", ffi.C_int64}, 273 | {"uint8*", ffi.C_uint8}, 274 | {"uint16*", ffi.C_uint16}, 275 | {"uint32*", ffi.C_uint32}, 276 | {"uint64*", ffi.C_uint64}, 277 | 278 | {"float*", ffi.C_float}, 279 | {"double*", ffi.C_double}, 280 | 281 | {"s_0*", s_t}, 282 | {"s_0**", p_s_t}, 283 | } { 284 | typ, err := ffi.NewPointerType(table.elem) 285 | if err != nil { 286 | t.Errorf(err.Error()) 287 | } 288 | eq(t, table.name, typ.Name()) 289 | eq(t, table.elem, typ.Elem()) 290 | eq(t, ffi.C_pointer.Size(), typ.Size()) 291 | eq(t, ffi.Ptr, typ.Kind()) 292 | } 293 | } 294 | 295 | // EOF 296 | -------------------------------------------------------------------------------- /ffi.go: -------------------------------------------------------------------------------- 1 | package ffi 2 | 3 | // #include 4 | // #include "ffi.h" 5 | // typedef void (*_go_ffi_fctptr_t)(void); 6 | import "C" 7 | 8 | import ( 9 | "fmt" 10 | "reflect" 11 | "strings" 12 | "unsafe" 13 | 14 | "github.com/sbinet/go-ffi/dl" 15 | ) 16 | 17 | // Abi is the ffi abi of the local plateform 18 | type Abi C.ffi_abi 19 | 20 | const ( 21 | FirstAbi Abi = C.FFI_FIRST_ABI 22 | DefaultAbi Abi = C.FFI_DEFAULT_ABI 23 | LastAbi Abi = C.FFI_LAST_ABI 24 | ) 25 | 26 | const ( 27 | TrampolineSize = C.FFI_TRAMPOLINE_SIZE 28 | NativeRawApi = C.FFI_NATIVE_RAW_API 29 | 30 | //Closures = C.FFI_CLOSURES 31 | //TypeSmallStruct1B = C.FFI_TYPE_SMALL_STRUCT_1B 32 | //TypeSmallStruct2B = C.FFI_TYPE_SMALL_STRUCT_2B 33 | //TypeSmallStruct4B = C.FFI_TYPE_SMALL_STRUCT_4B 34 | ) 35 | 36 | type Status uint32 37 | 38 | const ( 39 | Ok Status = C.FFI_OK 40 | BadTypedef Status = C.FFI_BAD_TYPEDEF 41 | BadAbi Status = C.FFI_BAD_ABI 42 | ) 43 | 44 | func (sc Status) String() string { 45 | switch sc { 46 | case Ok: 47 | return "FFI_OK" 48 | case BadTypedef: 49 | return "FFI_BAD_TYPEDEF" 50 | case BadAbi: 51 | return "FFI_BAD_ABI" 52 | } 53 | panic("unreachable") 54 | } 55 | 56 | // // Arg is a ffi argument 57 | // type Arg struct { 58 | // c C.ffi_arg 59 | // } 60 | 61 | // // SArg is a ffi argument 62 | // type SArg struct { 63 | // c C.ffi_sarg 64 | // } 65 | 66 | // Cif is the ffi call interface 67 | type Cif struct { 68 | c C.ffi_cif 69 | rtype Type 70 | args []Type 71 | } 72 | 73 | type FctPtr struct { 74 | c C._go_ffi_fctptr_t 75 | } 76 | 77 | // NewCif creates a new ffi call interface object 78 | func NewCif(abi Abi, rtype Type, args []Type) (*Cif, error) { 79 | cif := &Cif{} 80 | c_nargs := C.uint(len(args)) 81 | var c_args **C.ffi_type = nil 82 | if len(args) > 0 { 83 | var cargs = make([]*C.ffi_type, len(args)) 84 | for i, _ := range args { 85 | cargs[i] = args[i].cptr() 86 | } 87 | c_args = &cargs[0] 88 | } 89 | sc := C.ffi_prep_cif(&cif.c, C.ffi_abi(abi), c_nargs, rtype.cptr(), c_args) 90 | if sc != C.FFI_OK { 91 | return nil, fmt.Errorf("error while preparing cif (%s)", 92 | Status(sc)) 93 | } 94 | cif.rtype = rtype 95 | cif.args = args 96 | return cif, nil 97 | } 98 | 99 | // Call invokes the cif with the provided function pointer and arguments 100 | func (cif *Cif) Call(fct FctPtr, args ...interface{}) (reflect.Value, error) { 101 | nargs := len(args) 102 | if nargs != int(cif.c.nargs) { 103 | return reflect.New(reflect.TypeOf(0)), fmt.Errorf("ffi: invalid number of arguments. expected '%d', got '%s'.", 104 | int(cif.c.nargs), nargs) 105 | } 106 | var c_args *unsafe.Pointer = nil 107 | if nargs > 0 { 108 | cargs := make([]unsafe.Pointer, nargs) 109 | for i, _ := range args { 110 | var carg unsafe.Pointer 111 | //fmt.Printf("[%d]: (%v)\n", i, args[i]) 112 | t := reflect.TypeOf(args[i]) 113 | rv := reflect.ValueOf(args[i]) 114 | switch t.Kind() { 115 | case reflect.String: 116 | cstr := C.CString(args[i].(string)) 117 | defer C.free(unsafe.Pointer(cstr)) 118 | carg = unsafe.Pointer(&cstr) 119 | case reflect.Ptr: 120 | carg = unsafe.Pointer(rv.Elem().UnsafeAddr()) 121 | case reflect.Float32: 122 | vv := args[i].(float32) 123 | rv = reflect.ValueOf(&vv) 124 | carg = unsafe.Pointer(rv.Elem().UnsafeAddr()) 125 | case reflect.Float64: 126 | vv := args[i].(float64) 127 | rv = reflect.ValueOf(&vv) 128 | carg = unsafe.Pointer(rv.Elem().UnsafeAddr()) 129 | case reflect.Int: 130 | vv := args[i].(int) 131 | rv = reflect.ValueOf(&vv) 132 | carg = unsafe.Pointer(rv.Elem().UnsafeAddr()) 133 | case reflect.Int8: 134 | vv := args[i].(int8) 135 | rv = reflect.ValueOf(&vv) 136 | carg = unsafe.Pointer(rv.Elem().UnsafeAddr()) 137 | case reflect.Int16: 138 | vv := args[i].(int16) 139 | rv = reflect.ValueOf(&vv) 140 | carg = unsafe.Pointer(rv.Elem().UnsafeAddr()) 141 | case reflect.Int32: 142 | vv := args[i].(int32) 143 | rv = reflect.ValueOf(&vv) 144 | carg = unsafe.Pointer(rv.Elem().UnsafeAddr()) 145 | case reflect.Int64: 146 | vv := args[i].(int64) 147 | rv = reflect.ValueOf(&vv) 148 | carg = unsafe.Pointer(rv.Elem().UnsafeAddr()) 149 | case reflect.Uint: 150 | vv := args[i].(uint) 151 | rv = reflect.ValueOf(&vv) 152 | carg = unsafe.Pointer(rv.Elem().UnsafeAddr()) 153 | case reflect.Uint8: 154 | vv := args[i].(uint8) 155 | rv = reflect.ValueOf(&vv) 156 | carg = unsafe.Pointer(rv.Elem().UnsafeAddr()) 157 | case reflect.Uint16: 158 | vv := args[i].(uint16) 159 | rv = reflect.ValueOf(&vv) 160 | carg = unsafe.Pointer(rv.Elem().UnsafeAddr()) 161 | case reflect.Uint32: 162 | vv := args[i].(uint32) 163 | rv = reflect.ValueOf(&vv) 164 | carg = unsafe.Pointer(rv.Elem().UnsafeAddr()) 165 | case reflect.Uint64: 166 | vv := args[i].(uint64) 167 | rv = reflect.ValueOf(&vv) 168 | carg = unsafe.Pointer(rv.Elem().UnsafeAddr()) 169 | } 170 | cargs[i] = carg 171 | } 172 | c_args = &cargs[0] 173 | } 174 | out := reflect.New(rtype_from_ffi(cif.rtype.cptr())) 175 | var c_out unsafe.Pointer = unsafe.Pointer(out.Elem().UnsafeAddr()) 176 | //println("...ffi_call...") 177 | C.ffi_call(&cif.c, fct.c, c_out, c_args) 178 | //fmt.Printf("...ffi_call...[done] [%v]\n",out.Elem()) 179 | return out.Elem(), nil 180 | } 181 | 182 | type go_void struct{} 183 | 184 | func rtype_from_ffi(t *C.ffi_type) reflect.Type { 185 | switch t { 186 | case &C.ffi_type_void: 187 | return reflect.TypeOf(go_void{}) 188 | case &C.ffi_type_pointer: 189 | return reflect.TypeOf(uintptr(0)) 190 | case &C.ffi_type_uint: 191 | return reflect.TypeOf(uint(0)) 192 | case &C.ffi_type_sint: 193 | return reflect.TypeOf(int(0)) 194 | case &C.ffi_type_uint8: 195 | return reflect.TypeOf(uint8(0)) 196 | case &C.ffi_type_sint8: 197 | return reflect.TypeOf(int8(0)) 198 | case &C.ffi_type_uint16: 199 | return reflect.TypeOf(uint16(0)) 200 | case &C.ffi_type_sint16: 201 | return reflect.TypeOf(int16(0)) 202 | case &C.ffi_type_uint32: 203 | return reflect.TypeOf(uint32(0)) 204 | case &C.ffi_type_sint32: 205 | return reflect.TypeOf(int32(0)) 206 | case &C.ffi_type_uint64: 207 | return reflect.TypeOf(uint64(0)) 208 | case &C.ffi_type_sint64: 209 | return reflect.TypeOf(int64(0)) 210 | case &C.ffi_type_ulong: 211 | return reflect.TypeOf(uint64(0)) 212 | case &C.ffi_type_slong: 213 | return reflect.TypeOf(int64(0)) 214 | case &C.ffi_type_float: 215 | return reflect.TypeOf(float32(0)) 216 | case &C.ffi_type_double: 217 | return reflect.TypeOf(float64(0)) 218 | case &C.ffi_type_longdouble: 219 | // FIXME!! 220 | return reflect.TypeOf(complex128(0)) 221 | } 222 | panic("unreachable") 223 | } 224 | 225 | // void ffi_call(ffi_cif *cif, 226 | // void (*fn)(void), 227 | // void *rvalue, 228 | // void **avalue); 229 | 230 | // Closure models a ffi closure 231 | type Closure struct { 232 | c C.ffi_closure 233 | } 234 | 235 | // Library is a dl-opened library holding the corresponding dl.Handle 236 | type Library struct { 237 | handle dl.Handle 238 | } 239 | 240 | func get_lib_arch_name(libname string) string { 241 | fname := libname 242 | if !strings.HasPrefix(libname, g_lib_prefix) { 243 | fname = g_lib_prefix + libname 244 | } 245 | if !strings.HasSuffix(libname, g_lib_suffix) { 246 | fname = fname + g_lib_suffix 247 | } 248 | return fname 249 | } 250 | 251 | // NewLibrary takes the library filename and returns a handle towards it. 252 | func NewLibrary(libname string) (lib Library, err error) { 253 | //libname = get_lib_arch_name(libname) 254 | lib.handle, err = dl.Open(libname, dl.Now) 255 | return 256 | } 257 | 258 | func (lib Library) Close() error { 259 | return lib.handle.Close() 260 | } 261 | 262 | // Function is a dl-loaded function from a dl-opened library 263 | type Function func(args ...interface{}) reflect.Value 264 | 265 | type cfct struct { 266 | addr unsafe.Pointer 267 | } 268 | 269 | var nil_fct Function = func(args ...interface{}) reflect.Value { 270 | panic("ffi: nil_fct called") 271 | } 272 | 273 | /* 274 | func (lib Library) Fct(fctname string) (Function, error) { 275 | println("Fct(",fctname,")...") 276 | sym, err := lib.handle.Symbol(fctname) 277 | if err != nil { 278 | return nil_fct, err 279 | } 280 | 281 | addr := (C._go_ffi_fctptr_t)(unsafe.Pointer(sym)) 282 | cif, err := NewCif(DefaultAbi, Double, []Type{Double}) 283 | if err != nil { 284 | return nil_fct, err 285 | } 286 | 287 | fct := func(args ...interface{}) reflect.Value { 288 | println("...call.cif...") 289 | out, err := cif.Call(FctPtr{addr}, args...) 290 | if err != nil { 291 | panic(err) 292 | } 293 | println("...call.cif...[done]") 294 | return out 295 | } 296 | return Function(fct), nil 297 | } 298 | */ 299 | 300 | func (lib Library) Fct(fctname string, rtype Type, argtypes []Type) (Function, error) { 301 | //println("Fct(",fctname,")...") 302 | sym, err := lib.handle.Symbol(fctname) 303 | if err != nil { 304 | return nil_fct, err 305 | } 306 | 307 | addr := (C._go_ffi_fctptr_t)(unsafe.Pointer(sym)) 308 | cif, err := NewCif(DefaultAbi, rtype, argtypes) 309 | if err != nil { 310 | return nil_fct, err 311 | } 312 | 313 | fct := func(args ...interface{}) reflect.Value { 314 | //println("...call.cif...") 315 | out, err := cif.Call(FctPtr{addr}, args...) 316 | if err != nil { 317 | panic(err) 318 | } 319 | //println("...call.cif...[done]") 320 | return out 321 | } 322 | return Function(fct), nil 323 | } 324 | 325 | // EOF 326 | -------------------------------------------------------------------------------- /type.go: -------------------------------------------------------------------------------- 1 | package ffi 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "unsafe" 7 | ) 8 | 9 | // #include "ffi.h" 10 | // static void _go_ffi_type_set_type(ffi_type *t, unsigned short type) 11 | // { 12 | // t->type = type; 13 | // } 14 | // static unsigned short _go_ffi_type_get_type(ffi_type *t) 15 | // { 16 | // return t->type; 17 | // } 18 | // static void _go_ffi_type_set_elements(ffi_type *t, void *elmts) 19 | // { 20 | // t->elements = (ffi_type**)(elmts); 21 | // } 22 | // static void *_go_ffi_type_get_offset(void *data, unsigned n, ffi_type **types) 23 | // { 24 | // size_t ofs = 0; 25 | // unsigned i; 26 | // unsigned short a; 27 | // for (i = 0; i < n && types[i]; i++) { 28 | // a = ofs % types[i]->alignment; 29 | // if (a != 0) ofs += types[i]->alignment-a; 30 | // ofs += types[i]->size; 31 | // } 32 | // if (i < n || !types[i]) 33 | // return 0; 34 | // a = ofs % types[i]->alignment; 35 | // if (a != 0) ofs += types[i]->alignment-a; 36 | // return data+ofs; 37 | // } 38 | // static int _go_ffi_type_get_offsetof(ffi_type *t, int i) 39 | // { 40 | // void *v; 41 | // void *data = NULL + 2; // make a non-null pointer 42 | // if (t->type != FFI_TYPE_STRUCT) return 0; 43 | // v = _go_ffi_type_get_offset(data, i, t->elements); 44 | // if (v) { 45 | // return (int)(v - data); 46 | // } else { 47 | // return 0; 48 | // } 49 | // return 0; 50 | // } 51 | import "C" 52 | 53 | type Kind uint 54 | 55 | const ( 56 | Void Kind = C.FFI_TYPE_VOID 57 | Int Kind = C.FFI_TYPE_INT 58 | Float Kind = C.FFI_TYPE_FLOAT 59 | Double Kind = C.FFI_TYPE_DOUBLE 60 | LongDouble Kind = C.FFI_TYPE_LONGDOUBLE 61 | Uint8 Kind = C.FFI_TYPE_UINT8 62 | Int8 Kind = C.FFI_TYPE_SINT8 63 | Uint16 Kind = C.FFI_TYPE_UINT16 64 | Int16 Kind = C.FFI_TYPE_SINT16 65 | Uint32 Kind = C.FFI_TYPE_UINT32 66 | Int32 Kind = C.FFI_TYPE_SINT32 67 | Uint64 Kind = C.FFI_TYPE_UINT64 68 | Int64 Kind = C.FFI_TYPE_SINT64 69 | Struct Kind = C.FFI_TYPE_STRUCT 70 | Ptr Kind = C.FFI_TYPE_POINTER 71 | //FIXME 72 | Array Kind = 255 + iota 73 | Slice 74 | String 75 | ) 76 | 77 | func (k Kind) String() string { 78 | switch k { 79 | case Void: 80 | return "Void" 81 | case Int: 82 | return "Int" 83 | case Float: 84 | return "Float" 85 | case Double: 86 | return "Double" 87 | case LongDouble: 88 | return "LongDouble" 89 | case Uint8: 90 | return "Uint8" 91 | case Int8: 92 | return "Int8" 93 | case Uint16: 94 | return "Uint16" 95 | case Int16: 96 | return "Int16" 97 | case Uint32: 98 | return "Uint32" 99 | case Int32: 100 | return "Int32" 101 | case Uint64: 102 | return "Uint64" 103 | case Int64: 104 | return "Int64" 105 | case Struct: 106 | return "Struct" 107 | case Ptr: 108 | return "Ptr" 109 | case Array: 110 | return "Array" 111 | case Slice: 112 | return "Slice" 113 | case String: 114 | return "String" 115 | } 116 | panic("unreachable") 117 | } 118 | 119 | // Type is a FFI type, describing functions' type arguments 120 | type Type interface { 121 | cptr() *C.ffi_type 122 | 123 | // Name returns the type's name. 124 | Name() string 125 | 126 | // Size returns the number of bytes needed to store 127 | // a value of the given type. 128 | Size() uintptr 129 | 130 | // String returns a string representation of the type. 131 | String() string 132 | 133 | // Kind returns the specific kind of this type 134 | Kind() Kind 135 | 136 | // Align returns the alignment in bytes of a value of this type. 137 | Align() int 138 | 139 | // Len returns an array type's length 140 | // It panics if the type's Kind is not Array. 141 | Len() int 142 | 143 | // Elem returns a type's element type. 144 | // It panics if the type's Kind is not Array or Ptr 145 | Elem() Type 146 | 147 | // Field returns a struct type's i'th field. 148 | // It panics if the type's Kind is not Struct. 149 | // It panics if i is not in the range [0, NumField()). 150 | Field(i int) StructField 151 | 152 | // NumField returns a struct type's field count. 153 | // It panics if the type's Kind is not Struct. 154 | NumField() int 155 | 156 | // GoType returns the reflect.Type this ffi.Type is mirroring 157 | // It returns nil if there is no such equivalent go type. 158 | GoType() reflect.Type 159 | 160 | // set_gotype sets the reflect.Type associated with this ffi.Type 161 | set_gotype(t reflect.Type) 162 | } 163 | 164 | type cffi_type struct { 165 | n string 166 | c *C.ffi_type 167 | rt reflect.Type 168 | } 169 | 170 | func (t *cffi_type) cptr() *C.ffi_type { 171 | return t.c 172 | } 173 | 174 | func (t *cffi_type) Name() string { 175 | return t.n 176 | } 177 | 178 | func (t *cffi_type) Size() uintptr { 179 | return uintptr(t.c.size) 180 | } 181 | 182 | func (t *cffi_type) String() string { 183 | // fixme: 184 | return t.n 185 | } 186 | 187 | func (t *cffi_type) Kind() Kind { 188 | return Kind(C._go_ffi_type_get_type(t.c)) 189 | } 190 | 191 | func (t *cffi_type) Align() int { 192 | return int(t.c.alignment) 193 | } 194 | 195 | func (t *cffi_type) Len() int { 196 | if t.Kind() != Array { 197 | panic("ffi: Len of non-array type") 198 | } 199 | tt := (*cffi_array)(unsafe.Pointer(&t)) 200 | return tt.Len() 201 | } 202 | 203 | func (t *cffi_type) Elem() Type { 204 | switch t.Kind() { 205 | case Array: 206 | tt := (*cffi_array)(unsafe.Pointer(&t)) 207 | return tt.Elem() 208 | case Ptr: 209 | tt := (*cffi_ptr)(unsafe.Pointer(&t)) 210 | return tt.Elem() 211 | case Slice: 212 | tt := (*cffi_slice)(unsafe.Pointer(&t)) 213 | return tt.Elem() 214 | } 215 | panic("ffi: Elem of invalid type") 216 | } 217 | 218 | func (t *cffi_type) NumField() int { 219 | if t.Kind() != Struct { 220 | panic("ffi: NumField of non-struct type") 221 | } 222 | tt := (*cffi_struct)(unsafe.Pointer(&t)) 223 | return tt.NumField() 224 | } 225 | 226 | func (t *cffi_type) Field(i int) StructField { 227 | if t.Kind() != Struct { 228 | panic("ffi: Field of non-struct type") 229 | } 230 | tt := (*cffi_struct)(unsafe.Pointer(&t)) 231 | return tt.Field(i) 232 | } 233 | 234 | func (t *cffi_type) GoType() reflect.Type { 235 | return t.rt 236 | } 237 | 238 | func (t *cffi_type) set_gotype(rt reflect.Type) { 239 | t.rt = rt 240 | } 241 | 242 | var ( 243 | C_void Type = &cffi_type{"void", &C.ffi_type_void, nil} 244 | C_uchar = &cffi_type{"unsigned char", &C.ffi_type_uchar, reflect.TypeOf(uint8(0))} 245 | C_char = &cffi_type{"char", &C.ffi_type_schar, reflect.TypeOf(int8(0))} 246 | C_ushort = &cffi_type{"unsigned short", &C.ffi_type_ushort, reflect.TypeOf(uint16(0))} 247 | C_short = &cffi_type{"short", &C.ffi_type_sshort, reflect.TypeOf(int16(0))} 248 | C_uint = &cffi_type{"unsigned int", &C.ffi_type_uint, reflect.TypeOf(uint(0))} 249 | C_int = &cffi_type{"int", &C.ffi_type_sint, reflect.TypeOf(int(0))} 250 | C_ulong = &cffi_type{"unsigned long", &C.ffi_type_ulong, reflect.TypeOf(uint64(0))} 251 | C_long = &cffi_type{"long", &C.ffi_type_slong, reflect.TypeOf(int64(0))} 252 | C_uint8 = &cffi_type{"uint8", &C.ffi_type_uint8, reflect.TypeOf(uint8(0))} 253 | C_int8 = &cffi_type{"int8", &C.ffi_type_sint8, reflect.TypeOf(int8(0))} 254 | C_uint16 = &cffi_type{"uint16", &C.ffi_type_uint16, reflect.TypeOf(uint16(0))} 255 | C_int16 = &cffi_type{"int16", &C.ffi_type_sint16, reflect.TypeOf(int16(0))} 256 | C_uint32 = &cffi_type{"uint32", &C.ffi_type_uint32, reflect.TypeOf(uint32(0))} 257 | C_int32 = &cffi_type{"int32", &C.ffi_type_sint32, reflect.TypeOf(int32(0))} 258 | C_uint64 = &cffi_type{"uint64", &C.ffi_type_uint64, reflect.TypeOf(uint64(0))} 259 | C_int64 = &cffi_type{"int64", &C.ffi_type_sint64, reflect.TypeOf(int64(0))} 260 | C_float = &cffi_type{"float", &C.ffi_type_float, reflect.TypeOf(float32(0.))} 261 | C_double = &cffi_type{"double", &C.ffi_type_double, reflect.TypeOf(float64(0.))} 262 | C_longdouble = &cffi_type{"long double", &C.ffi_type_longdouble, nil} 263 | C_pointer = &cffi_type{"*", &C.ffi_type_pointer, reflect.TypeOf(nil)} 264 | ) 265 | 266 | type StructField struct { 267 | Name string // Name is the field name 268 | Type Type // field type 269 | Offset uintptr // offset within struct, in bytes 270 | } 271 | 272 | type cffi_struct struct { 273 | cffi_type 274 | fields []StructField 275 | } 276 | 277 | func (t *cffi_struct) NumField() int { 278 | return len(t.fields) 279 | } 280 | 281 | func (t *cffi_struct) Field(i int) StructField { 282 | if i < 0 || i >= len(t.fields) { 283 | panic("ffi: field index out of range") 284 | } 285 | return t.fields[i] 286 | } 287 | 288 | func (t *cffi_struct) set_gotype(rt reflect.Type) { 289 | t.cffi_type.rt = rt 290 | } 291 | 292 | type Field struct { 293 | Name string // Name is the field name 294 | Type Type // field type 295 | } 296 | 297 | var g_id_ch chan int 298 | 299 | // NewStructType creates a new ffi_type describing a C-struct 300 | func NewStructType(name string, fields []Field) (Type, error) { 301 | if name == "" { 302 | // anonymous type... 303 | // generate some id. 304 | name = fmt.Sprintf("_ffi_anon_type_%d", <-g_id_ch) 305 | } 306 | if t := TypeByName(name); t != nil { 307 | // check the definitions are the same 308 | if t.NumField() != len(fields) { 309 | return nil, fmt.Errorf("ffi.NewStructType: inconsistent re-declaration of [%s]", name) 310 | } 311 | for i := range fields { 312 | if fields[i].Name != t.Field(i).Name { 313 | return nil, fmt.Errorf("ffi.NewStructType: inconsistent re-declaration of [%s] (field #%d name mismatch)", name, i) 314 | 315 | } 316 | if fields[i].Type != t.Field(i).Type { 317 | return nil, fmt.Errorf("ffi.NewStructType: inconsistent re-declaration of [%s] (field #%d type mismatch)", name, i) 318 | 319 | } 320 | } 321 | return t, nil 322 | } 323 | c := C.ffi_type{} 324 | t := &cffi_struct{ 325 | cffi_type: cffi_type{n: name, c: &c}, 326 | fields: make([]StructField, len(fields)), 327 | } 328 | t.cffi_type.c.size = 0 329 | t.cffi_type.c.alignment = 0 330 | C._go_ffi_type_set_type(t.cptr(), C.FFI_TYPE_STRUCT) 331 | 332 | var c_fields **C.ffi_type = nil 333 | if len(fields) > 0 { 334 | var cargs = make([]*C.ffi_type, len(fields)+1) 335 | for i, f := range fields { 336 | cargs[i] = f.Type.cptr() 337 | } 338 | cargs[len(fields)] = nil 339 | c_fields = &cargs[0] 340 | } 341 | C._go_ffi_type_set_elements(t.cptr(), unsafe.Pointer(c_fields)) 342 | 343 | // initialize type (computes alignment and size) 344 | _, err := NewCif(DefaultAbi, t, nil) 345 | if err != nil { 346 | return nil, err 347 | } 348 | 349 | for i := 0; i < len(fields); i++ { 350 | //cft := C._go_ffi_type_get_element(t.cptr(), C.int(i)) 351 | ff := fields[i] 352 | t.fields[i] = StructField{ 353 | ff.Name, 354 | TypeByName(ff.Type.Name()), 355 | uintptr(C._go_ffi_type_get_offsetof(t.cptr(), C.int(i))), 356 | } 357 | } 358 | register_type(t) 359 | return t, nil 360 | } 361 | 362 | type cffi_array struct { 363 | cffi_type 364 | len int 365 | elem Type 366 | } 367 | 368 | func (t *cffi_array) Kind() Kind { 369 | // FIXME: ffi has no concept of array (as they decay to pointers in C) 370 | //return Kind(C._go_ffi_type_get_type(t.c)) 371 | return Array 372 | } 373 | 374 | func (t *cffi_array) Len() int { 375 | return t.len 376 | } 377 | 378 | func (t *cffi_array) Elem() Type { 379 | return t.elem 380 | } 381 | 382 | // NewArrayType creates a new ffi_type with the given size and element type. 383 | func NewArrayType(sz int, elmt Type) (Type, error) { 384 | n := fmt.Sprintf("%s[%d]", elmt.Name(), sz) 385 | if t := TypeByName(n); t != nil { 386 | return t, nil 387 | } 388 | c := C.ffi_type{} 389 | t := &cffi_array{ 390 | cffi_type: cffi_type{n: n, c: &c}, 391 | len: sz, 392 | elem: elmt, 393 | } 394 | t.cffi_type.c.size = C.size_t(sz * int(elmt.Size())) 395 | t.cffi_type.c.alignment = C_pointer.c.alignment 396 | var c_fields **C.ffi_type = nil 397 | C._go_ffi_type_set_elements(t.cptr(), unsafe.Pointer(c_fields)) 398 | C._go_ffi_type_set_type(t.cptr(), C.FFI_TYPE_POINTER) 399 | 400 | // initialize type (computes alignment and size) 401 | _, err := NewCif(DefaultAbi, t, nil) 402 | if err != nil { 403 | return nil, err 404 | } 405 | 406 | register_type(t) 407 | return t, nil 408 | } 409 | 410 | type cffi_ptr struct { 411 | cffi_type 412 | elem Type 413 | } 414 | 415 | func (t *cffi_ptr) Elem() Type { 416 | return t.elem 417 | } 418 | 419 | // NewPointerType creates a new ffi_type with the given element type 420 | func NewPointerType(elmt Type) (Type, error) { 421 | n := elmt.Name() + "*" 422 | if t := TypeByName(n); t != nil { 423 | return t, nil 424 | } 425 | c := C.ffi_type{} 426 | t := &cffi_ptr{ 427 | cffi_type: cffi_type{n: n, c: &c}, 428 | elem: elmt, 429 | } 430 | if elmt.GoType() != nil { 431 | t.cffi_type.rt = reflect.PtrTo(elmt.GoType()) 432 | } 433 | t.cffi_type.c.size = C_pointer.c.size 434 | t.cffi_type.c.alignment = C_pointer.c.alignment 435 | var c_fields **C.ffi_type = nil 436 | C._go_ffi_type_set_elements(t.cptr(), unsafe.Pointer(c_fields)) 437 | C._go_ffi_type_set_type(t.cptr(), C.FFI_TYPE_POINTER) 438 | 439 | // initialize type (computes alignment and size) 440 | _, err := NewCif(DefaultAbi, t, nil) 441 | if err != nil { 442 | return nil, err 443 | } 444 | 445 | register_type(t) 446 | return t, nil 447 | } 448 | 449 | type cffi_slice struct { 450 | cffi_type 451 | elem Type 452 | } 453 | 454 | func (t *cffi_slice) Kind() Kind { 455 | // FIXME: ffi has no concept of array (as they decay to pointers in C) 456 | //return Kind(C._go_ffi_type_get_type(t.c)) 457 | return Slice 458 | } 459 | 460 | func (t *cffi_slice) Elem() Type { 461 | return t.elem 462 | } 463 | 464 | // NewSliceType creates a new ffi_type slice with the given element type 465 | func NewSliceType(elmt Type) (Type, error) { 466 | n := elmt.Name() + "[]" 467 | if t := TypeByName(n); t != nil { 468 | return t, nil 469 | } 470 | c := C.ffi_type{} 471 | t := &cffi_slice{ 472 | cffi_type: cffi_type{n: n, c: &c}, 473 | elem: elmt, 474 | } 475 | t.cffi_type.c.size = 0 476 | t.cffi_type.c.alignment = 0 477 | C._go_ffi_type_set_type(t.cptr(), C.FFI_TYPE_STRUCT) 478 | 479 | var c_fields **C.ffi_type = nil 480 | var cargs = make([]*C.ffi_type, 3+1) 481 | cargs[0] = C_pointer.cptr() // ptr to C-array 482 | 483 | csize := unsafe.Sizeof(reflect.SliceHeader{}.Cap) 484 | if csize == 8 { 485 | // Go 1.1 spec allows (but doesn't force) sizeof(int) == 8 486 | cargs[1] = C_int64.cptr() // len 487 | cargs[2] = C_int64.cptr() // cap 488 | } else { 489 | cargs[1] = C_int.cptr() // len 490 | cargs[2] = C_int.cptr() // cap 491 | } 492 | cargs[3] = nil 493 | c_fields = &cargs[0] 494 | C._go_ffi_type_set_elements(t.cptr(), unsafe.Pointer(c_fields)) 495 | 496 | // initialize type (computes alignment and size) 497 | _, err := NewCif(DefaultAbi, t, nil) 498 | if err != nil { 499 | return nil, err 500 | } 501 | 502 | register_type(t) 503 | return t, nil 504 | } 505 | 506 | // the global map of types 507 | var g_types map[string]Type 508 | 509 | // TypeByName returns a ffi.Type by name. 510 | // Returns nil if no such type exists 511 | func TypeByName(n string) Type { 512 | t, ok := g_types[n] 513 | if ok { 514 | return t 515 | } 516 | return nil 517 | } 518 | 519 | func register_type(t Type) { 520 | g_types[t.Name()] = t 521 | } 522 | 523 | func ctype_from_gotype(rt reflect.Type) Type { 524 | var t Type 525 | 526 | switch rt.Kind() { 527 | case reflect.Int: 528 | t = C_int 529 | 530 | case reflect.Int8: 531 | t = C_int8 532 | 533 | case reflect.Int16: 534 | t = C_int16 535 | 536 | case reflect.Int32: 537 | t = C_int32 538 | 539 | case reflect.Int64: 540 | t = C_int64 541 | 542 | case reflect.Uint: 543 | t = C_uint 544 | 545 | case reflect.Uint8: 546 | t = C_uint8 547 | 548 | case reflect.Uint16: 549 | t = C_uint16 550 | 551 | case reflect.Uint32: 552 | t = C_uint32 553 | 554 | case reflect.Uint64: 555 | t = C_uint64 556 | 557 | case reflect.Float32: 558 | t = C_float 559 | 560 | case reflect.Float64: 561 | t = C_double 562 | 563 | case reflect.Array: 564 | et := ctype_from_gotype(rt.Elem()) 565 | ct, err := NewArrayType(rt.Len(), et) 566 | if err != nil { 567 | panic("ffi: " + err.Error()) 568 | } 569 | ct.set_gotype(rt) 570 | t = ct 571 | 572 | case reflect.Ptr: 573 | et := ctype_from_gotype(rt.Elem()) 574 | ct, err := NewPointerType(et) 575 | if err != nil { 576 | panic("ffi: " + err.Error()) 577 | } 578 | t = ct 579 | 580 | case reflect.Slice: 581 | et := ctype_from_gotype(rt.Elem()) 582 | ct, err := NewSliceType(et) 583 | if err != nil { 584 | panic("ffi: " + err.Error()) 585 | } 586 | ct.set_gotype(rt) 587 | t = ct 588 | 589 | case reflect.Struct: 590 | fields := make([]Field, rt.NumField()) 591 | for i := 0; i < rt.NumField(); i++ { 592 | field := rt.Field(i) 593 | fields[i] = Field{ 594 | Name: field.Name, 595 | Type: ctype_from_gotype(field.Type), 596 | } 597 | } 598 | ct, err := NewStructType(rt.Name(), fields) 599 | if err != nil { 600 | panic("ffi: " + err.Error()) 601 | } 602 | ct.set_gotype(rt) 603 | t = ct 604 | 605 | case reflect.String: 606 | panic("unimplemented") 607 | default: 608 | panic("unhandled kind [" + rt.Kind().String() + "]") 609 | } 610 | 611 | return t 612 | } 613 | 614 | // Associate creates a link b/w a ffi.Type and a reflect.Type to allow 615 | // automatic conversions b/w these types. 616 | func Associate(ct Type, rt reflect.Type) error { 617 | crt := ct.GoType() 618 | if crt != nil { 619 | if crt != rt { 620 | return fmt.Errorf("ffi.Associate: ffi.Type [%s] already associated to reflect.Type [%s]", ct.Name(), crt.Name()) 621 | } 622 | return nil 623 | } 624 | 625 | ct.set_gotype(rt) 626 | if ct.GoType() != rt { 627 | panic("ffi.Associate: internal error") 628 | } 629 | return nil 630 | } 631 | 632 | // PtrTo returns the pointer type with element t. 633 | // For example, if t represents type Foo, PtrTo(t) represents *Foo. 634 | func PtrTo(t Type) Type { 635 | typ, err := NewPointerType(t) 636 | if err != nil { 637 | return nil 638 | } 639 | return typ 640 | } 641 | 642 | // TypeOf returns the ffi Type of the value in the interface{}. 643 | // TypeOf(nil) returns nil 644 | // TypeOf(reflect.Type) returns the ffi Type corresponding to the reflected value 645 | func TypeOf(i interface{}) Type { 646 | switch typ := i.(type) { 647 | case reflect.Type: 648 | return ctype_from_gotype(typ) 649 | case reflect.Value: 650 | return ctype_from_gotype(typ.Type()) 651 | default: 652 | rt := reflect.TypeOf(i) 653 | return ctype_from_gotype(rt) 654 | } 655 | panic("unreachable") 656 | } 657 | 658 | // is_compatible returns whether two ffi Types are binary compatible 659 | func is_compatible(t1, t2 Type) bool { 660 | if t1.Kind() != t2.Kind() { 661 | //FIXME: test if it is int/intX and uint/uintX 662 | return false 663 | } 664 | switch t1.Kind() { 665 | case Struct: 666 | for i := 0; i < t1.NumField(); i++ { 667 | f1 := t1.Field(i) 668 | f2 := t2.Field(i) 669 | if !is_compatible(f1.Type, f2.Type) { 670 | return false 671 | } 672 | } 673 | case Array: 674 | if t1.Len() != t2.Len() { 675 | return false 676 | } 677 | et1 := t1.Elem() 678 | et2 := t2.Elem() 679 | if !is_compatible(et1, et2) { 680 | return false 681 | } 682 | return true 683 | 684 | case Ptr: 685 | et1 := t1.Elem() 686 | et2 := t2.Elem() 687 | if !is_compatible(et1, et2) { 688 | return false 689 | } 690 | return true 691 | 692 | case Slice: 693 | et1 := t1.Elem() 694 | et2 := t2.Elem() 695 | if !is_compatible(et1, et2) { 696 | return false 697 | } 698 | return true 699 | 700 | case String: 701 | panic("unimplemented: ffi.String") 702 | } 703 | return true 704 | } 705 | 706 | func init() { 707 | // init out id counter channel 708 | g_id_ch = make(chan int, 1) 709 | go func() { 710 | i := 0 711 | for { 712 | g_id_ch <- i 713 | i++ 714 | } 715 | }() 716 | 717 | g_types = make(map[string]Type) 718 | 719 | // initialize all builtin types 720 | init_type := func(t Type) { 721 | n := t.Name() 722 | //fmt.Printf("ctype [%s] - size: %v...\n", n, t.Size()) 723 | if _, ok := g_types[n]; ok { 724 | //fmt.Printf("ctypes [%s] already registered\n", n) 725 | return 726 | } 727 | //NewCif(DefaultAbi, t, nil) 728 | //fmt.Printf("ctype [%s] - size: %v\n", n, t.Size()) 729 | g_types[n] = t 730 | } 731 | 732 | init_type(C_void) 733 | init_type(C_uchar) 734 | init_type(C_char) 735 | init_type(C_ushort) 736 | init_type(C_short) 737 | init_type(C_uint) 738 | init_type(C_int) 739 | init_type(C_ulong) 740 | init_type(C_long) 741 | init_type(C_uint8) 742 | init_type(C_int8) 743 | init_type(C_uint16) 744 | init_type(C_int16) 745 | init_type(C_uint32) 746 | init_type(C_int32) 747 | init_type(C_uint64) 748 | init_type(C_int64) 749 | init_type(C_float) 750 | init_type(C_double) 751 | init_type(C_longdouble) 752 | init_type(C_pointer) 753 | 754 | } 755 | 756 | // make sure ffi_types satisfy ffi.Type interface 757 | var _ Type = (*cffi_type)(nil) 758 | var _ Type = (*cffi_array)(nil) 759 | var _ Type = (*cffi_ptr)(nil) 760 | var _ Type = (*cffi_slice)(nil) 761 | var _ Type = (*cffi_struct)(nil) 762 | 763 | // EOF 764 | -------------------------------------------------------------------------------- /value.go: -------------------------------------------------------------------------------- 1 | package ffi 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "runtime" 7 | "unsafe" 8 | ) 9 | 10 | const ptrSize = unsafe.Sizeof((*byte)(nil)) 11 | 12 | // TODO: This will have to go away when 13 | // the new gc goes in. 14 | func memmove(adst, asrc unsafe.Pointer, n uintptr) { 15 | dst := uintptr(adst) 16 | src := uintptr(asrc) 17 | switch { 18 | case src < dst && src+n > dst: 19 | // byte copy backward 20 | // careful: i is unsigned 21 | for i := n; i > 0; { 22 | i-- 23 | *(*byte)(unsafe.Pointer(dst + i)) = *(*byte)(unsafe.Pointer(src + i)) 24 | } 25 | case (n|src|dst)&(ptrSize-1) != 0: 26 | // byte copy forward 27 | for i := uintptr(0); i < n; i++ { 28 | *(*byte)(unsafe.Pointer(dst + i)) = *(*byte)(unsafe.Pointer(src + i)) 29 | } 30 | default: 31 | // word copy forward 32 | for i := uintptr(0); i < n; i += ptrSize { 33 | *(*uintptr)(unsafe.Pointer(dst + i)) = *(*uintptr)(unsafe.Pointer(src + i)) 34 | } 35 | } 36 | } 37 | 38 | // methodName returns the name of the calling method, 39 | // assumed to be two stack frames above. 40 | func methodName() string { 41 | pc, _, _, _ := runtime.Caller(2) 42 | f := runtime.FuncForPC(pc) 43 | if f == nil { 44 | return "unknown method" 45 | } 46 | return f.Name() 47 | } 48 | 49 | // A ValueError occurs when a Value method is invoked on 50 | // a Value that does not support it. Such cases are documented 51 | // in the description of each method. 52 | type ValueError struct { 53 | Method string 54 | Kind Kind 55 | } 56 | 57 | func (e *ValueError) Error() string { 58 | if e.Kind == 0 { 59 | return "ffi: call of " + e.Method + " on zero Value" 60 | } 61 | return "ffi: call of " + e.Method + " on " + e.Kind.String() + " Value" 62 | } 63 | 64 | // Value is the binary representation of an instance of type Type 65 | type Value struct { 66 | // typ holds the type of the value represented by the Value 67 | typ Type 68 | 69 | // val points at the value of this Value. 70 | val unsafe.Pointer 71 | } 72 | 73 | // New returns a Value representing a pointer to a new zero value for 74 | // the specified type. 75 | func New(typ Type) Value { 76 | if typ == nil { 77 | panic("ffi: New(nil)") 78 | } 79 | buf := make([]byte, int(typ.Size())) 80 | ptr := unsafe.Pointer(&buf[0]) 81 | v := Value{typ: typ, val: ptr} 82 | 83 | return v 84 | } 85 | 86 | // NewAt returns a Value representing a pointer to a value of the specified 87 | // type, using p as that pointer. 88 | func NewAt(typ Type, p unsafe.Pointer) Value { 89 | if typ == nil { 90 | panic("ffi: NewAt(nil)") 91 | } 92 | typ, err := NewPointerType(typ) 93 | if err != nil { 94 | return Value{} 95 | } 96 | 97 | v := Value{typ, p} 98 | return v 99 | } 100 | 101 | // mustBe panics if v's kind is not expected. 102 | func (v Value) mustBe(expected Kind) { 103 | k := v.typ.Kind() 104 | if k != expected { 105 | panic("ffi: call of " + methodName() + " on " + k.String() + " Value") 106 | } 107 | } 108 | 109 | // Addr returns a pointer value representing the address of v. 110 | // It panics if CanAddr() returns false. 111 | // Addr is typically used to obtain a pointer to a struct field. 112 | func (v Value) Addr() Value { 113 | typ := PtrTo(v.typ) 114 | if typ == nil { 115 | return Value{} 116 | } 117 | ptr := unsafe.Pointer(&v.val) 118 | return Value{typ, ptr} 119 | } 120 | 121 | // Buffer returns the underlying byte storage for this value. 122 | func (v Value) Buffer() []byte { 123 | buf := make([]byte, 0) 124 | val := reflect.ValueOf(&buf) 125 | slice := (*reflect.SliceHeader)(unsafe.Pointer(val.Pointer())) 126 | slice.Len = int(v.typ.Size()) 127 | slice.Data = uintptr(v.val) 128 | return buf 129 | } 130 | 131 | // Cap returns v's capacity. 132 | // It panics if v's Kind is not Array. 133 | func (v Value) Cap() int { 134 | k := v.Kind() 135 | switch k { 136 | case Array: 137 | elem_sz := v.typ.Elem().Size() 138 | return v.typ.Len() / int(elem_sz) 139 | case Slice: 140 | //FIXME: make more robust 141 | //NOTE: we assume the layout of our "slice header" is the same than 142 | // reflect.SliceHeader's... 143 | vcap := (*reflect.SliceHeader)(v.val).Cap 144 | elem_sz := v.typ.Elem().Size() 145 | return vcap / int(elem_sz) 146 | } 147 | panic(&ValueError{"ffi.Value.Cap", k}) 148 | } 149 | 150 | // Elem returns the value that the pointer v points to. 151 | // It panics if v's kind is not Ptr 152 | func (v Value) Elem() Value { 153 | v.mustBe(Ptr) 154 | typ := v.typ.Elem() 155 | val := v.val 156 | val = *(*unsafe.Pointer)(val) 157 | return Value{typ: typ, val: val} 158 | } 159 | 160 | // Field returns the i'th field of the struct v. 161 | // It panics if v's Kind is not Struct or i is out of range. 162 | func (v Value) Field(i int) Value { 163 | v.mustBe(Struct) 164 | tt := v.typ.(*cffi_struct) 165 | nfields := tt.NumField() 166 | if i < 0 || i >= nfields { 167 | panic("ffi: Field index out of range") 168 | } 169 | field := &tt.fields[i] 170 | typ := field.Type 171 | 172 | var val unsafe.Pointer 173 | // Indirect. Just bump pointer. 174 | val = unsafe.Pointer(uintptr(v.val) + field.Offset) 175 | return Value{typ, val} 176 | } 177 | 178 | // FieldByIndex returns the nested field corresponding to index. 179 | // It panics if v's Kind is not struct. 180 | func (v Value) FieldByIndex(index []int) Value { 181 | v.mustBe(Struct) 182 | for i, x := range index { 183 | if i > 0 { 184 | if v.Kind() == Ptr && v.Elem().Kind() == Struct { 185 | v = v.Elem() 186 | } 187 | } 188 | v = v.Field(x) 189 | } 190 | return v 191 | } 192 | 193 | // FieldByName returns the struct field with the given name. 194 | // It returns the zero Value if no field was found. 195 | // It panics if v's Kind is not struct. 196 | func (v Value) FieldByName(name string) Value { 197 | v.mustBe(Struct) 198 | for i := 0; i < v.typ.NumField(); i++ { 199 | if v.typ.Field(i).Name == name { 200 | return v.Field(i) 201 | } 202 | } 203 | return Value{} 204 | /* 205 | if f, ok := v.typ.FieldByName(name); ok { 206 | return v.FieldByIndex(f.Index) 207 | } 208 | return Value{} 209 | */ 210 | } 211 | 212 | // Float returns v's underlying value, as a float64. 213 | // It panics if v's Kind is not Float or Double 214 | func (v Value) Float() float64 { 215 | k := v.typ.Kind() 216 | switch k { 217 | case Float: 218 | return float64(*(*float32)(v.val)) 219 | case Double: 220 | return *(*float64)(v.val) 221 | } 222 | panic(&ValueError{"ffi.Value.Float", k}) 223 | } 224 | 225 | // GoValue returns v's value as a go reflect.Value if such a type exists. 226 | func (v Value) GoValue() reflect.Value { 227 | rt := v.Type().GoType() 228 | if rt == nil { 229 | panic(fmt.Sprintf("ffi.Value.GoValue: value of type %s has no associated reflect.Type!", v.Type().Name())) 230 | } 231 | rv := reflect.New(rt).Elem() 232 | switch k := rt.Kind(); k { 233 | case reflect.Int, 234 | reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 235 | rv.SetInt(v.Int()) 236 | 237 | case reflect.Uint, 238 | reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 239 | rv.SetUint(v.Uint()) 240 | 241 | case reflect.Float32, reflect.Float64: 242 | rv.SetFloat(v.Float()) 243 | 244 | case reflect.Array: 245 | for i := 0; i < rt.Len(); i++ { 246 | rv.Index(i).Set(v.Index(i).GoValue()) 247 | } 248 | 249 | case reflect.Ptr: 250 | //cval := v.Elem().GoValue().Addr() 251 | //rv.Set(cval) 252 | panic("ffi.Value.GoValue: Ptr not implemented") 253 | 254 | case reflect.Slice: 255 | vlen := v.Len() 256 | vcap := v.Cap() 257 | if vlen > vcap { 258 | vcap = vlen 259 | } 260 | rv = reflect.MakeSlice(rt, vlen, vcap) 261 | for i := 0; i < v.Len(); i++ { 262 | rv.Index(i).Set(v.Index(i).GoValue()) 263 | } 264 | 265 | case reflect.Struct: 266 | for i := 0; i < rt.NumField(); i++ { 267 | rv.Field(i).Set(v.Field(i).GoValue()) 268 | } 269 | 270 | case reflect.String: 271 | panic("ffi.Value.GoValue: String not implemented") 272 | 273 | default: 274 | panic("ffi.Value.GoValue: unhandled kind [" + rt.Kind().String() + "]") 275 | } 276 | return rv 277 | } 278 | 279 | // Index returns v's i'th element. 280 | // It panics if v's Kind is not Array or Slice or i is out of range. 281 | func (v Value) Index(i int) Value { 282 | k := v.typ.Kind() 283 | switch k { 284 | case Array: 285 | tt := v.typ.(*cffi_array) 286 | if i < 0 || i > int(tt.Len()) { 287 | panic("ffi: array index out of range") 288 | } 289 | typ := tt.Elem() 290 | offset := uintptr(i) * typ.Size() 291 | 292 | var val unsafe.Pointer = unsafe.Pointer(uintptr(v.val) + offset) 293 | return Value{typ, val} 294 | case Slice: 295 | s := (*reflect.SliceHeader)(v.val) 296 | if i < 0 || i >= s.Len { 297 | panic("ffi: slice index out of range") 298 | } 299 | tt := v.typ.(*cffi_slice) 300 | typ := tt.Elem() 301 | offset := uintptr(i) * typ.Size() 302 | val := unsafe.Pointer(s.Data + offset) 303 | return Value{typ, val} 304 | } 305 | panic(&ValueError{"ffi.Value.Index", k}) 306 | } 307 | 308 | // Int returns v's underlying value, as an int64. 309 | // It panics if v's Kind is not Int, Int8, Int16, Int32, or Int64. 310 | func (v Value) Int() int64 { 311 | k := v.typ.Kind() 312 | var p unsafe.Pointer = v.val 313 | switch k { 314 | case Int: 315 | return int64(*(*int)(p)) 316 | case Int8: 317 | return int64(*(*int8)(p)) 318 | case Int16: 319 | return int64(*(*int16)(p)) 320 | case Int32: 321 | return int64(*(*int32)(p)) 322 | case Int64: 323 | return int64(*(*int64)(p)) 324 | } 325 | panic(&ValueError{"ffi.Value.Int", k}) 326 | } 327 | 328 | // IsNil returns true if v is a nil value. 329 | // It panics if v's Kind is Ptr. 330 | func (v Value) IsNil() bool { 331 | v.mustBe(Ptr) 332 | ptr := v.val 333 | ptr = *(*unsafe.Pointer)(ptr) 334 | return ptr == nil 335 | } 336 | 337 | // IsValid returns true if v represents a value. 338 | // It returns false if v is the zero Value. 339 | // If IsValid returns false, all other methods except String panic. 340 | // Most functions and methods never return an invalid value. 341 | // If one does, its documentation states the conditions explicitly. 342 | func (v Value) IsValid() bool { 343 | return v.val != nil 344 | } 345 | 346 | // Kind returns v's Kind. 347 | func (v Value) Kind() Kind { 348 | return v.typ.Kind() 349 | } 350 | 351 | // Len returns v's length. 352 | // It panics if v's Kind is not Array 353 | func (v Value) Len() int { 354 | switch k := v.Kind(); k { 355 | case Array: 356 | tt := v.typ.(*cffi_array) 357 | return int(tt.Len()) 358 | case Slice: 359 | //FIXME: make more robust 360 | //NOTE: we assume the layout of our "slice header" is the same than 361 | // reflect.SliceHeader's... 362 | vlen := (*reflect.SliceHeader)(v.val).Len 363 | elem_sz := v.typ.Elem().Size() 364 | //fmt.Printf("::: type[%v] vlen=%v elem_sz=%v\n", v.typ.Name(), vlen, elem_sz) 365 | return vlen / int(elem_sz) 366 | default: 367 | panic(&ValueError{"ffi.Value.Len", k}) 368 | } 369 | panic("unreachable") 370 | } 371 | 372 | // NumField returns the number of fields in the struct v. 373 | // It panics if v's Kind is not Struct. 374 | func (v Value) NumField() int { 375 | v.mustBe(Struct) 376 | return v.typ.NumField() 377 | } 378 | 379 | func (v *Value) set_field(i int, f Value) { 380 | 381 | // fmt.Printf(":: v=0x%x i=%d f=0x%x...\n", v.UnsafeAddr(), i, f.UnsafeAddr()) 382 | vv := v.Field(i) 383 | memmove( 384 | unsafe.Pointer(vv.UnsafeAddr()), 385 | unsafe.Pointer(f.UnsafeAddr()), 386 | vv.typ.Size()) 387 | } 388 | 389 | // SetValue assigns x to the value v. 390 | // It panics if the type of x isn't binary compatible with the type of v. 391 | func (v *Value) SetValue(x reflect.Value) { 392 | rt := x.Type() 393 | ct := TypeOf(x.Interface()) 394 | if !is_compatible(v.typ, ct) { 395 | panic(fmt.Sprintf( 396 | "ffi.Value.SetValue: go-value of type [%s] can not be assigned to ffi.Value of type [%s]", 397 | rt.Name(), v.Type().Name())) 398 | } 399 | 400 | v.set_value(x) 401 | } 402 | 403 | // set_value assigns x to the value v. 404 | func (v *Value) set_value(x reflect.Value) { 405 | rt := x.Type() 406 | switch k := rt.Kind(); k { 407 | case reflect.Int, 408 | reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 409 | v.SetInt(x.Int()) 410 | 411 | case reflect.Uint, 412 | reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 413 | v.SetUint(x.Uint()) 414 | 415 | case reflect.Float32, reflect.Float64: 416 | v.SetFloat(x.Float()) 417 | 418 | case reflect.Array: 419 | for i := 0; i < rt.Len(); i++ { 420 | vv := v.Index(i) 421 | vv.set_value(x.Index(i)) 422 | } 423 | 424 | case reflect.Ptr: 425 | //vv := v.Elem() 426 | //vv.set_value(x.Elem()) 427 | panic("ffi.Value.SetValue: Ptr not implemented") 428 | 429 | case reflect.Slice: 430 | if x.Len() > v.Cap() { 431 | *v, _, _ = grow_slice(*v, x.Len()) 432 | } 433 | v.SetLen(x.Len()) 434 | for i := 0; i < x.Len(); i++ { 435 | vv := v.Index(i) 436 | vv.set_value(x.Index(i)) 437 | } 438 | 439 | case reflect.Struct: 440 | for i := 0; i < rt.NumField(); i++ { 441 | vv := v.Field(i) 442 | vv.set_value(x.Field(i)) 443 | v.set_field(i, vv) 444 | } 445 | 446 | case reflect.String: 447 | panic("ffi.Value.SetValue: String not implemented") 448 | 449 | default: 450 | panic("ffi.Value.SetValue: unhandled kind [" + rt.Kind().String() + "]") 451 | } 452 | } 453 | 454 | // SetFloat sets v's underlying value to x. 455 | // It panics if v's Kind is not Float or Double, or if CanSet() is false. 456 | func (v Value) SetFloat(x float64) { 457 | switch k := v.typ.Kind(); k { 458 | default: 459 | panic(&ValueError{"ffi.Value.SetFloat", k}) 460 | case Float: 461 | *(*float32)(v.val) = float32(x) 462 | case Double: 463 | *(*float64)(v.val) = x 464 | } 465 | } 466 | 467 | // SetInt sets v's underlying value to x. 468 | // It panics if v's Kind is not Int, Int8, Int16, Int32, or Int64, or if CanSet() is false. 469 | func (v Value) SetInt(x int64) { 470 | //v.mustBeAssignable() 471 | switch k := v.typ.Kind(); k { 472 | default: 473 | panic(&ValueError{"ffi.Value.SetInt", k}) 474 | case Int: 475 | *(*int)(v.val) = int(x) 476 | case Int8: 477 | *(*int8)(v.val) = int8(x) 478 | case Int16: 479 | *(*int16)(v.val) = int16(x) 480 | case Int32: 481 | *(*int32)(v.val) = int32(x) 482 | case Int64: 483 | *(*int64)(v.val) = x 484 | } 485 | } 486 | 487 | // SetLen sets v's length to n. 488 | // It panics if v's Kind is not Slice or if n is negative or 489 | // greater than the capacity of the slice. 490 | func (v Value) SetLen(n int) { 491 | v.mustBe(Slice) 492 | s := (*reflect.SliceHeader)(v.val) 493 | if n < 0 || n > int(s.Cap) { 494 | panic("reflect: slice length out of range in SetLen") 495 | } 496 | elem_sz := v.typ.Elem().Size() 497 | s.Len = n * int(elem_sz) 498 | //s.Cap = n * int(elem_sz) 499 | } 500 | 501 | // SetPointer sets the unsafe.Pointer value v to x. 502 | func (v Value) SetPointer(x unsafe.Pointer) { 503 | v.mustBe(Ptr) 504 | *(*unsafe.Pointer)(v.val) = x 505 | } 506 | 507 | // SetUint sets v's underlying value to x. 508 | // It panics if v's Kind is not Int, Int8, Int16, Int32, or Int64, or if CanSet() is false. 509 | func (v Value) SetUint(x uint64) { 510 | //v.mustBeAssignable() 511 | switch k := v.typ.Kind(); k { 512 | default: 513 | panic(&ValueError{"ffi.Value.SetUint", k}) 514 | // case Uint: 515 | // *(*uint)(v.val) = uint(x) 516 | case Uint8: 517 | *(*uint8)(v.val) = uint8(x) 518 | case Uint16: 519 | *(*uint16)(v.val) = uint16(x) 520 | case Uint32: 521 | *(*uint32)(v.val) = uint32(x) 522 | case Uint64: 523 | *(*uint64)(v.val) = x 524 | } 525 | } 526 | 527 | // Slice returns a slice of v. 528 | // It panics if v's Kind is not Array or Slice. 529 | func (v Value) Slice(beg, end int) Value { 530 | var ( 531 | cap int 532 | typ Type 533 | base unsafe.Pointer 534 | ) 535 | switch k := v.Kind(); k { 536 | default: 537 | panic(&ValueError{"ffi.Value.Slice", k}) 538 | case Array: 539 | tt := v.typ.(*cffi_array) 540 | cap = int(tt.Len()) 541 | var err error 542 | typ, err = NewSliceType(tt.Elem()) 543 | if err != nil { 544 | panic("ffi.Value.Slice: " + err.Error()) 545 | } 546 | base = v.val 547 | case Slice: 548 | typ = v.typ.(*cffi_slice) 549 | s := (*reflect.SliceHeader)(v.val) 550 | base = unsafe.Pointer(s.Data) 551 | cap = s.Cap 552 | 553 | } 554 | if beg < 0 || end < beg || end > cap { 555 | panic("ffi.Value.Slice: slice index out of bounds") 556 | } 557 | 558 | // Declare slice so that gc can see the base pointer in it. 559 | var x []byte 560 | 561 | // Reinterpret as *SliceHeader to edit. 562 | s := (*reflect.SliceHeader)(unsafe.Pointer(&x)) 563 | s.Data = uintptr(base) + uintptr(beg)*typ.Elem().Size() 564 | s.Len = end - beg 565 | s.Cap = cap - beg 566 | 567 | return Value{typ, unsafe.Pointer(&x)} 568 | } 569 | 570 | // Type returns v's type 571 | func (v Value) Type() Type { 572 | return v.typ 573 | } 574 | 575 | // Uint returns v's underlying value, as a uint64. 576 | // It panics if v's Kind is not Uint, Uintptr, Uint8, Uint16, Uint32, or Uint64. 577 | func (v Value) Uint() uint64 { 578 | k := v.typ.Kind() 579 | var p unsafe.Pointer = v.val 580 | switch k { 581 | // case Uint: 582 | // return uint64(*(*uint)(p)) 583 | case Uint8: 584 | return uint64(*(*uint8)(p)) 585 | case Uint16: 586 | return uint64(*(*uint16)(p)) 587 | case Uint32: 588 | return uint64(*(*uint32)(p)) 589 | case Uint64: 590 | return uint64(*(*uint64)(p)) 591 | // case Uintptr: 592 | // return uint64(*(*uintptr)(p)) 593 | } 594 | panic(&ValueError{"ffi.Value.Uint", k}) 595 | } 596 | 597 | // UnsafeAddr returns a pointer to v's data. 598 | // It is for advanced clients that also import the "unsafe" package. 599 | func (v Value) UnsafeAddr() uintptr { 600 | if v.typ == nil { 601 | panic("ffi: call of ffi.Value.UnsafeAddr on an invalid Value") 602 | } 603 | // FIXME: use flagAddr ?? 604 | return uintptr(v.val) 605 | } 606 | 607 | // Indirect returns the value that v points to. 608 | // If v is a nil pointer, Indirect returns a zero Value. 609 | // If v is not a pointer, Indirect returns v. 610 | func Indirect(v Value) Value { 611 | if v.typ.Kind() != Ptr { 612 | return v 613 | } 614 | return v.Elem() 615 | } 616 | 617 | // ValueOf returns a new Value initialized to the concrete value stored in 618 | // the interface i. 619 | // ValueOf(nil) returns the zero Value 620 | func ValueOf(i interface{}) Value { 621 | if i == nil { 622 | return Value{} 623 | } 624 | v := Value{} 625 | rv := reflect.ValueOf(i) 626 | rt := rv.Type() 627 | switch rt.Kind() { 628 | case reflect.Int: 629 | v = New(C_int) 630 | v.SetInt(rv.Int()) 631 | 632 | case reflect.Int8: 633 | v = New(C_int8) 634 | v.SetInt(rv.Int()) 635 | 636 | case reflect.Int16: 637 | v = New(C_int16) 638 | v.SetInt(rv.Int()) 639 | 640 | case reflect.Int32: 641 | v = New(C_int32) 642 | v.SetInt(rv.Int()) 643 | 644 | case reflect.Int64: 645 | v = New(C_int64) 646 | v.SetInt(rv.Int()) 647 | 648 | case reflect.Uint: 649 | v = New(C_uint) 650 | v.SetUint(rv.Uint()) 651 | 652 | case reflect.Uint8: 653 | v = New(C_uint8) 654 | v.SetUint(rv.Uint()) 655 | 656 | case reflect.Uint16: 657 | v = New(C_uint16) 658 | v.SetUint(rv.Uint()) 659 | 660 | case reflect.Uint32: 661 | v = New(C_uint32) 662 | v.SetUint(rv.Uint()) 663 | 664 | case reflect.Uint64: 665 | v = New(C_uint64) 666 | v.SetUint(rv.Uint()) 667 | 668 | case reflect.Float32: 669 | v = New(C_float) 670 | v.SetFloat(rv.Float()) 671 | 672 | case reflect.Float64: 673 | v = New(C_double) 674 | v.SetFloat(rv.Float()) 675 | 676 | case reflect.Array: 677 | ct := ctype_from_gotype(rt) 678 | v = New(ct) 679 | v.SetValue(rv) 680 | 681 | case reflect.Ptr: 682 | ct := ctype_from_gotype(rt) 683 | v = New(ct) 684 | v.SetValue(rv) 685 | 686 | case reflect.Struct: 687 | ct := ctype_from_gotype(rt) 688 | v = New(ct) 689 | v.SetValue(rv) 690 | 691 | case reflect.String: 692 | panic("ffi.ValueOf: String unimplemented") 693 | 694 | case reflect.Slice: 695 | ct := ctype_from_gotype(rt) 696 | v = MakeSlice(ct, rv.Len(), rv.Cap()) 697 | v.SetValue(rv) 698 | 699 | default: 700 | panic("unhandled kind [" + rt.Kind().String() + "]") 701 | } 702 | 703 | return v 704 | } 705 | 706 | // MakeSlice creates a new zero-initialized slice value 707 | // for the specified slice type, length, and capacity. 708 | func MakeSlice(typ Type, vlen, vcap int) Value { 709 | if typ.Kind() != Slice { 710 | panic("ffi.MakeSlice of non-slice type") 711 | } 712 | if vlen < 0 { 713 | panic("ffi.MakeSlice: negative len") 714 | } 715 | if vcap < 0 { 716 | panic("ffi.MakeSlice: negative cap") 717 | } 718 | if vlen > vcap { 719 | panic("ffi.MakeSlice: len > cap") 720 | } 721 | 722 | // Declare slice so that gc can see the base pointer in it. 723 | slice_len := uintptr(vlen) * typ.Elem().Size() 724 | slice_cap := uintptr(vcap) * typ.Elem().Size() 725 | x := make([]byte, slice_len, slice_cap) 726 | 727 | // Reinterpret as *SliceHeader to edit. 728 | //s := (*reflect.SliceHeader)(unsafe.Pointer(&x)) 729 | //s.Len = vlen 730 | //s.Cap = vcap 731 | 732 | return Value{typ, unsafe.Pointer(&x)} 733 | } 734 | 735 | // grow_slice grows the slice s so that it can hold extra more values, 736 | // allocating more capacity if needed. 737 | // It also returns the old and new slice lengths. 738 | func grow_slice(s Value, extra int) (Value, int, int) { 739 | s.mustBe(Slice) 740 | 741 | i0 := s.Len() 742 | i1 := i0 + extra 743 | if i1 < i0 { 744 | panic("ffi.Append: slice overflow") 745 | } 746 | m := s.Cap() 747 | if i1 <= m { 748 | return s.Slice(0, i1), i0, i1 749 | } 750 | if m == 0 { 751 | m = extra 752 | } else { 753 | for m < i1 { 754 | if i0 < 1024 { 755 | m += m 756 | } else { 757 | m += m / 4 758 | } 759 | } 760 | } 761 | t := MakeSlice(s.Type(), i1, m) 762 | tx := (*[]byte)(unsafe.Pointer(t.val)) 763 | sx := (*[]byte)(unsafe.Pointer(s.val)) 764 | _ = copy(*tx, *sx) 765 | return t, i0, i1 766 | } 767 | 768 | // EOF 769 | -------------------------------------------------------------------------------- /value_test.go: -------------------------------------------------------------------------------- 1 | package ffi_test 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | 7 | ffi "github.com/sbinet/go-ffi" 8 | ) 9 | 10 | func TestGetSetBuiltinValue(t *testing.T) { 11 | 12 | { 13 | const val = 42 14 | for _, tt := range []struct { 15 | n string 16 | t ffi.Type 17 | val interface{} 18 | }{ 19 | {"int", ffi.C_int, int64(val)}, 20 | {"int8", ffi.C_int8, int64(val)}, 21 | {"int16", ffi.C_int16, int64(val)}, 22 | {"int32", ffi.C_int32, int64(val)}, 23 | {"int64", ffi.C_int64, int64(val)}, 24 | } { 25 | cval := ffi.New(tt.t) 26 | eq(t, tt.n, cval.Type().Name()) 27 | eq(t, tt.t.Kind(), cval.Kind()) 28 | eq(t, reflect.Zero(reflect.TypeOf(tt.val)).Int(), cval.Int()) 29 | cval.SetInt(val) 30 | eq(t, tt.val, cval.Int()) 31 | } 32 | } 33 | 34 | { 35 | const val = 42 36 | for _, tt := range []struct { 37 | n string 38 | t ffi.Type 39 | val interface{} 40 | }{ 41 | {"unsigned int", ffi.C_uint, uint64(val)}, 42 | {"uint8", ffi.C_uint8, uint64(val)}, 43 | {"uint16", ffi.C_uint16, uint64(val)}, 44 | {"uint32", ffi.C_uint32, uint64(val)}, 45 | {"uint64", ffi.C_uint64, uint64(val)}, 46 | } { 47 | cval := ffi.New(tt.t) 48 | eq(t, tt.n, cval.Type().Name()) 49 | eq(t, tt.t.Kind(), cval.Kind()) 50 | eq(t, reflect.Zero(reflect.TypeOf(tt.val)).Uint(), cval.Uint()) 51 | cval.SetUint(val) 52 | eq(t, tt.val, cval.Uint()) 53 | } 54 | } 55 | 56 | { 57 | const val = -66.0 58 | for _, tt := range []struct { 59 | n string 60 | t ffi.Type 61 | val interface{} 62 | }{ 63 | {"float", ffi.C_float, float64(val)}, 64 | {"double", ffi.C_double, float64(val)}, 65 | //FIXME: Go has no equivalent for long double... 66 | //{"long double", ffi.C_longdouble, float128(val)}, 67 | } { 68 | cval := ffi.New(tt.t) 69 | eq(t, tt.n, cval.Type().Name()) 70 | eq(t, tt.t.Kind(), cval.Kind()) 71 | eq(t, reflect.Zero(reflect.TypeOf(tt.val)).Float(), cval.Float()) 72 | cval.SetFloat(val) 73 | eq(t, tt.val, cval.Float()) 74 | } 75 | } 76 | 77 | { 78 | const val = -66 79 | cval := ffi.New(ffi.C_int64) 80 | cptr := cval.Addr() 81 | cval.SetInt(val) 82 | eq(t, int64(val), cval.Int()) 83 | eq(t, int64(val), cptr.Elem().Int()) 84 | cval.SetInt(0) 85 | eq(t, int64(0), cptr.Elem().Int()) 86 | cptr.Elem().SetInt(val) 87 | eq(t, int64(val), cval.Int()) 88 | eq(t, int64(val), cptr.Elem().Int()) 89 | 90 | } 91 | } 92 | 93 | func TestGetSetArrayValue(t *testing.T) { 94 | 95 | { 96 | const val = 42 97 | for _, tt := range []struct { 98 | n string 99 | len int 100 | t ffi.Type 101 | val interface{} 102 | }{ 103 | {"uint8[10]", 10, ffi.C_uint8, [10]uint8{}}, 104 | {"uint16[10]", 10, ffi.C_uint16, [10]uint16{}}, 105 | {"uint32[10]", 10, ffi.C_uint32, [10]uint32{}}, 106 | {"uint64[10]", 10, ffi.C_uint64, [10]uint64{}}, 107 | } { 108 | ctyp, err := ffi.NewArrayType(tt.len, tt.t) 109 | if err != nil { 110 | t.Errorf(err.Error()) 111 | } 112 | cval := ffi.New(ctyp) 113 | eq(t, tt.n, cval.Type().Name()) 114 | eq(t, ctyp.Kind(), cval.Kind()) 115 | gtyp := reflect.TypeOf(tt.val) 116 | gval := reflect.New(gtyp).Elem() 117 | eq(t, gval.Len(), cval.Len()) 118 | for i := 0; i < gval.Len(); i++ { 119 | eq(t, gval.Index(i).Uint(), cval.Index(i).Uint()) 120 | gval.Index(i).SetUint(val) 121 | cval.Index(i).SetUint(val) 122 | eq(t, gval.Index(i).Uint(), cval.Index(i).Uint()) 123 | } 124 | } 125 | } 126 | 127 | { 128 | const val = 42 129 | for _, tt := range []struct { 130 | n string 131 | len int 132 | t ffi.Type 133 | val interface{} 134 | }{ 135 | {"int8[10]", 10, ffi.C_int8, [10]int8{}}, 136 | {"int16[10]", 10, ffi.C_int16, [10]int16{}}, 137 | {"int32[10]", 10, ffi.C_int32, [10]int32{}}, 138 | {"int64[10]", 10, ffi.C_int64, [10]int64{}}, 139 | } { 140 | ctyp, err := ffi.NewArrayType(tt.len, tt.t) 141 | if err != nil { 142 | t.Errorf(err.Error()) 143 | } 144 | cval := ffi.New(ctyp) 145 | eq(t, tt.n, cval.Type().Name()) 146 | eq(t, ctyp.Kind(), cval.Kind()) 147 | gtyp := reflect.TypeOf(tt.val) 148 | gval := reflect.New(gtyp).Elem() 149 | eq(t, gval.Len(), cval.Len()) 150 | for i := 0; i < gval.Len(); i++ { 151 | eq(t, gval.Index(i).Int(), cval.Index(i).Int()) 152 | gval.Index(i).SetInt(val) 153 | cval.Index(i).SetInt(val) 154 | eq(t, gval.Index(i).Int(), cval.Index(i).Int()) 155 | } 156 | } 157 | } 158 | 159 | { 160 | const val = -66.2 161 | for _, tt := range []struct { 162 | n string 163 | len int 164 | t ffi.Type 165 | val interface{} 166 | }{ 167 | {"float[10]", 10, ffi.C_float, [10]float32{}}, 168 | {"double[10]", 10, ffi.C_double, [10]float64{}}, 169 | // FIXME: go has no long double equivalent 170 | //{"long double[10]", 10, ffi.C_longdouble, [10]float128{}}, 171 | } { 172 | ctyp, err := ffi.NewArrayType(tt.len, tt.t) 173 | if err != nil { 174 | t.Errorf(err.Error()) 175 | } 176 | cval := ffi.New(ctyp) 177 | eq(t, tt.n, cval.Type().Name()) 178 | eq(t, ctyp.Kind(), cval.Kind()) 179 | gtyp := reflect.TypeOf(tt.val) 180 | gval := reflect.New(gtyp).Elem() 181 | eq(t, gval.Len(), cval.Len()) 182 | for i := 0; i < gval.Len(); i++ { 183 | eq(t, gval.Index(i).Float(), cval.Index(i).Float()) 184 | gval.Index(i).SetFloat(val) 185 | cval.Index(i).SetFloat(val) 186 | eq(t, gval.Index(i).Float(), cval.Index(i).Float()) 187 | } 188 | } 189 | } 190 | 191 | } 192 | 193 | func TestGetSetStructValue(t *testing.T) { 194 | 195 | const val = 42 196 | arr10, err := ffi.NewArrayType(10, ffi.C_int32) 197 | if err != nil { 198 | t.Errorf(err.Error()) 199 | } 200 | 201 | ctyp, err := ffi.NewStructType( 202 | "struct_ssv", 203 | []ffi.Field{ 204 | {"F1", ffi.C_uint16}, 205 | {"F2", arr10}, 206 | {"F3", ffi.C_int32}, 207 | {"F4", ffi.C_uint16}, 208 | }) 209 | eq(t, "struct_ssv", ctyp.Name()) 210 | eq(t, ffi.Struct, ctyp.Kind()) 211 | eq(t, 4, ctyp.NumField()) 212 | 213 | cval := ffi.New(ctyp) 214 | eq(t, ctyp.Kind(), cval.Kind()) 215 | eq(t, ctyp.NumField(), cval.NumField()) 216 | eq(t, uint64(0), cval.Field(0).Uint()) 217 | for i := 0; i < arr10.Len(); i++ { 218 | eq(t, int64(0), cval.Field(1).Index(i).Int()) 219 | } 220 | eq(t, int64(0), cval.Field(2).Int()) 221 | eq(t, uint64(0), cval.Field(3).Uint()) 222 | 223 | // set everything to 'val' 224 | cval.Field(0).SetUint(val) 225 | for i := 0; i < arr10.Len(); i++ { 226 | cval.Field(1).Index(i).SetInt(val) 227 | } 228 | cval.Field(2).SetInt(val) 229 | cval.Field(3).SetUint(val) 230 | 231 | // test values back 232 | eq(t, uint64(val), cval.Field(0).Uint()) 233 | for i := 0; i < arr10.Len(); i++ { 234 | eq(t, int64(val), cval.Field(1).Index(i).Int()) 235 | } 236 | eq(t, int64(val), cval.Field(2).Int()) 237 | eq(t, uint64(val), cval.Field(3).Uint()) 238 | 239 | // test values back - by field name 240 | eq(t, uint64(val), cval.FieldByName("F1").Uint()) 241 | for i := 0; i < arr10.Len(); i++ { 242 | eq(t, int64(val), cval.FieldByName("F2").Index(i).Int()) 243 | } 244 | eq(t, int64(val), cval.FieldByName("F3").Int()) 245 | eq(t, uint64(val), cval.FieldByName("F4").Uint()) 246 | } 247 | 248 | func TestGetSetStructWithSliceValue(t *testing.T) { 249 | 250 | const val = 42 251 | arr10, err := ffi.NewArrayType(10, ffi.C_int32) 252 | if err != nil { 253 | t.Errorf(err.Error()) 254 | } 255 | slityp, err := ffi.NewSliceType(ffi.C_int32) 256 | if err != nil { 257 | t.Errorf(err.Error()) 258 | } 259 | 260 | ctyp, err := ffi.NewStructType( 261 | "struct_sswsv", 262 | []ffi.Field{ 263 | {"F1", ffi.C_uint16}, 264 | {"F2", arr10}, 265 | {"F3", ffi.C_int32}, 266 | {"F4", ffi.C_uint16}, 267 | {"F5", slityp}, 268 | }) 269 | eq(t, "struct_sswsv", ctyp.Name()) 270 | eq(t, ffi.Struct, ctyp.Kind()) 271 | eq(t, 5, ctyp.NumField()) 272 | 273 | cval := ffi.New(ctyp) 274 | eq(t, ctyp.Kind(), cval.Kind()) 275 | eq(t, ctyp.NumField(), cval.NumField()) 276 | eq(t, uint64(0), cval.Field(0).Uint()) 277 | for i := 0; i < arr10.Len(); i++ { 278 | eq(t, int64(0), cval.Field(1).Index(i).Int()) 279 | } 280 | eq(t, int64(0), cval.Field(2).Int()) 281 | eq(t, uint64(0), cval.Field(3).Uint()) 282 | eq(t, int(0), cval.Field(4).Len()) 283 | eq(t, int(0), cval.Field(4).Len()) 284 | 285 | goval := struct { 286 | F1 uint16 287 | F2 [10]int32 288 | F3 int32 289 | F4 uint16 290 | F5 []int32 291 | }{ 292 | F1: val, 293 | F2: [10]int32{val, val, val, val, val, 294 | val, val, val, val, val}, 295 | F3: val, 296 | F4: val, 297 | F5: make([]int32, 2, 3), 298 | } 299 | goval.F5[0] = val 300 | goval.F5[1] = val 301 | 302 | cval.SetValue(reflect.ValueOf(goval)) 303 | 304 | eq(t, uint64(val), cval.Field(0).Uint()) 305 | for i := 0; i < arr10.Len(); i++ { 306 | eq(t, int64(val), cval.Field(1).Index(i).Int()) 307 | } 308 | eq(t, int64(val), cval.Field(2).Int()) 309 | eq(t, uint64(val), cval.Field(3).Uint()) 310 | eq(t, int(2), cval.Field(4).Len()) 311 | // FIXME: should we get the 'cap' from go ? 312 | eq(t, int( /*3*/ 2), cval.Field(4).Cap()) 313 | eq(t, int64(val), cval.Field(4).Index(0).Int()) 314 | eq(t, int64(val), cval.Field(4).Index(1).Int()) 315 | } 316 | 317 | func TestGetSetSliceValue(t *testing.T) { 318 | 319 | const sz = 10 320 | { 321 | const val = 42 322 | for _, tt := range []struct { 323 | n string 324 | t ffi.Type 325 | val interface{} 326 | }{ 327 | {"uint8[]", ffi.C_uint8, make([]uint8, sz)}, 328 | {"uint16[]", ffi.C_uint16, make([]uint16, sz)}, 329 | {"uint32[]", ffi.C_uint32, make([]uint32, sz)}, 330 | {"uint64[]", ffi.C_uint64, make([]uint64, sz)}, 331 | } { 332 | ctyp, err := ffi.NewSliceType(tt.t) 333 | if err != nil { 334 | t.Errorf(err.Error()) 335 | } 336 | cval := ffi.MakeSlice(ctyp, sz, sz) 337 | eq(t, tt.n, cval.Type().Name()) 338 | eq(t, ctyp.Kind(), cval.Kind()) 339 | gtyp := reflect.TypeOf(tt.val) 340 | gval := reflect.MakeSlice(gtyp, sz, sz) 341 | eq(t, gval.Len(), cval.Len()) 342 | eq(t, int(sz), cval.Len()) 343 | for i := 0; i < gval.Len(); i++ { 344 | eq(t, gval.Index(i).Uint(), cval.Index(i).Uint()) 345 | gval.Index(i).SetUint(val) 346 | cval.Index(i).SetUint(val) 347 | eq(t, gval.Index(i).Uint(), cval.Index(i).Uint()) 348 | } 349 | } 350 | } 351 | 352 | { 353 | const val = 42 354 | for _, tt := range []struct { 355 | n string 356 | t ffi.Type 357 | val interface{} 358 | }{ 359 | {"int8[]", ffi.C_int8, make([]int8, sz)}, 360 | {"int16[]", ffi.C_int16, make([]int16, sz)}, 361 | {"int32[]", ffi.C_int32, make([]int32, sz)}, 362 | {"int64[]", ffi.C_int64, make([]int64, sz)}, 363 | } { 364 | ctyp, err := ffi.NewSliceType(tt.t) 365 | if err != nil { 366 | t.Errorf(err.Error()) 367 | } 368 | cval := ffi.MakeSlice(ctyp, sz, sz) 369 | eq(t, tt.n, cval.Type().Name()) 370 | eq(t, ctyp.Kind(), cval.Kind()) 371 | gtyp := reflect.TypeOf(tt.val) 372 | gval := reflect.MakeSlice(gtyp, sz, sz) 373 | eq(t, gval.Len(), cval.Len()) 374 | eq(t, int(sz), cval.Len()) 375 | for i := 0; i < gval.Len(); i++ { 376 | eq(t, gval.Index(i).Int(), cval.Index(i).Int()) 377 | gval.Index(i).SetInt(val) 378 | cval.Index(i).SetInt(val) 379 | eq(t, gval.Index(i).Int(), cval.Index(i).Int()) 380 | } 381 | } 382 | } 383 | 384 | { 385 | const val = -66.2 386 | for _, tt := range []struct { 387 | n string 388 | t ffi.Type 389 | val interface{} 390 | }{ 391 | {"float[]", ffi.C_float, make([]float32, sz)}, 392 | {"double[]", ffi.C_double, make([]float64, sz)}, 393 | // FIXME: go has no long double equivalent 394 | //{"long double[]", ffi.C_longdouble, make([]float128, sz)} 395 | } { 396 | ctyp, err := ffi.NewSliceType(tt.t) 397 | if err != nil { 398 | t.Errorf(err.Error()) 399 | } 400 | cval := ffi.MakeSlice(ctyp, sz, sz) 401 | eq(t, tt.n, cval.Type().Name()) 402 | eq(t, ctyp.Kind(), cval.Kind()) 403 | gtyp := reflect.TypeOf(tt.val) 404 | gval := reflect.MakeSlice(gtyp, sz, sz) 405 | eq(t, gval.Len(), cval.Len()) 406 | eq(t, int(sz), cval.Len()) 407 | for i := 0; i < gval.Len(); i++ { 408 | eq(t, gval.Index(i).Float(), cval.Index(i).Float()) 409 | gval.Index(i).SetFloat(val) 410 | cval.Index(i).SetFloat(val) 411 | eq(t, gval.Index(i).Float(), cval.Index(i).Float()) 412 | } 413 | } 414 | } 415 | 416 | // now test if slices can automatically grow... 417 | { 418 | const val = 42 419 | for _, tt := range []struct { 420 | n string 421 | t ffi.Type 422 | val interface{} 423 | }{ 424 | {"uint8[]", ffi.C_uint8, make([]uint8, sz)}, 425 | {"uint16[]", ffi.C_uint16, make([]uint16, sz)}, 426 | {"uint32[]", ffi.C_uint32, make([]uint32, sz)}, 427 | {"uint64[]", ffi.C_uint64, make([]uint64, sz)}, 428 | } { 429 | ctyp, err := ffi.NewSliceType(tt.t) 430 | if err != nil { 431 | t.Errorf(err.Error()) 432 | } 433 | cval := ffi.MakeSlice(ctyp, 0, 0) 434 | eq(t, tt.n, cval.Type().Name()) 435 | eq(t, ctyp.Kind(), cval.Kind()) 436 | gtyp := reflect.TypeOf(tt.val) 437 | gval := reflect.MakeSlice(gtyp, sz, sz) 438 | eq(t, int(0), cval.Len()) 439 | cval.SetValue(gval) // <--------- 440 | eq(t, int(sz), cval.Len()) 441 | eq(t, gval.Len(), cval.Len()) 442 | for i := 0; i < gval.Len(); i++ { 443 | eq(t, gval.Index(i).Uint(), cval.Index(i).Uint()) 444 | gval.Index(i).SetUint(val) 445 | cval.Index(i).SetUint(val) 446 | eq(t, gval.Index(i).Uint(), cval.Index(i).Uint()) 447 | } 448 | } 449 | } 450 | 451 | { 452 | const val = 42 453 | for _, tt := range []struct { 454 | n string 455 | t ffi.Type 456 | val interface{} 457 | }{ 458 | {"int8[]", ffi.C_int8, make([]int8, sz)}, 459 | {"int16[]", ffi.C_int16, make([]int16, sz)}, 460 | {"int32[]", ffi.C_int32, make([]int32, sz)}, 461 | {"int64[]", ffi.C_int64, make([]int64, sz)}, 462 | } { 463 | ctyp, err := ffi.NewSliceType(tt.t) 464 | if err != nil { 465 | t.Errorf(err.Error()) 466 | } 467 | cval := ffi.MakeSlice(ctyp, 0, 0) 468 | eq(t, tt.n, cval.Type().Name()) 469 | eq(t, ctyp.Kind(), cval.Kind()) 470 | gtyp := reflect.TypeOf(tt.val) 471 | gval := reflect.MakeSlice(gtyp, sz, sz) 472 | eq(t, int(0), cval.Len()) 473 | cval.SetValue(gval) // <--------- 474 | eq(t, int(sz), cval.Len()) 475 | eq(t, gval.Len(), cval.Len()) 476 | for i := 0; i < gval.Len(); i++ { 477 | eq(t, gval.Index(i).Int(), cval.Index(i).Int()) 478 | gval.Index(i).SetInt(val) 479 | cval.Index(i).SetInt(val) 480 | eq(t, gval.Index(i).Int(), cval.Index(i).Int()) 481 | } 482 | } 483 | } 484 | 485 | { 486 | const val = -66.2 487 | for _, tt := range []struct { 488 | n string 489 | t ffi.Type 490 | val interface{} 491 | }{ 492 | {"float[]", ffi.C_float, make([]float32, sz)}, 493 | {"double[]", ffi.C_double, make([]float64, sz)}, 494 | // FIXME: go has no long double equivalent 495 | //{"long double[]", ffi.C_longdouble, make([]float128, sz)} 496 | } { 497 | ctyp, err := ffi.NewSliceType(tt.t) 498 | if err != nil { 499 | t.Errorf(err.Error()) 500 | } 501 | cval := ffi.MakeSlice(ctyp, 0, 0) 502 | eq(t, tt.n, cval.Type().Name()) 503 | eq(t, ctyp.Kind(), cval.Kind()) 504 | gtyp := reflect.TypeOf(tt.val) 505 | gval := reflect.MakeSlice(gtyp, sz, sz) 506 | eq(t, int(0), cval.Len()) 507 | cval.SetValue(gval) // <--------- 508 | eq(t, int(sz), cval.Len()) 509 | eq(t, gval.Len(), cval.Len()) 510 | for i := 0; i < gval.Len(); i++ { 511 | eq(t, gval.Index(i).Float(), cval.Index(i).Float()) 512 | gval.Index(i).SetFloat(val) 513 | cval.Index(i).SetFloat(val) 514 | eq(t, gval.Index(i).Float(), cval.Index(i).Float()) 515 | } 516 | } 517 | } 518 | } 519 | 520 | func TestValueOf(t *testing.T) { 521 | { 522 | const val = 42 523 | for _, v := range []interface{}{ 524 | int(val), 525 | int8(val), 526 | int16(val), 527 | int32(val), 528 | int64(val), 529 | } { 530 | eq(t, int64(val), ffi.ValueOf(v).Int()) 531 | } 532 | } 533 | 534 | { 535 | const val = 42 536 | for _, v := range []interface{}{ 537 | uint(val), 538 | uint8(val), 539 | uint16(val), 540 | uint32(val), 541 | uint64(val), 542 | } { 543 | eq(t, uint64(val), ffi.ValueOf(v).Uint()) 544 | } 545 | } 546 | { 547 | const val = 42.0 548 | for _, v := range []interface{}{ 549 | float32(val), 550 | float64(val), 551 | } { 552 | eq(t, float64(val), ffi.ValueOf(v).Float()) 553 | } 554 | } 555 | { 556 | const val = 42 557 | ctyp, err := ffi.NewStructType( 558 | "struct_ints", 559 | []ffi.Field{ 560 | {"F1", ffi.C_int8}, 561 | {"F2", ffi.C_int16}, 562 | {"F3", ffi.C_int32}, 563 | {"F4", ffi.C_int64}, 564 | }) 565 | if err != nil { 566 | t.Errorf(err.Error()) 567 | } 568 | cval := ffi.New(ctyp) 569 | for i := 0; i < ctyp.NumField(); i++ { 570 | cval.Field(i).SetInt(int64(val)) 571 | eq(t, int64(val), cval.Field(i).Int()) 572 | } 573 | gval := struct { 574 | F1 int8 575 | F2 int16 576 | F3 int32 577 | F4 int64 578 | }{val + 1, val + 1, val + 1, val + 1} 579 | rval := reflect.ValueOf(gval) 580 | eq(t, rval.NumField(), cval.NumField()) 581 | for i := 0; i < ctyp.NumField(); i++ { 582 | eq(t, rval.Field(i).Int()-1, cval.Field(i).Int()) 583 | } 584 | cval = ffi.ValueOf(gval) 585 | for i := 0; i < ctyp.NumField(); i++ { 586 | eq(t, rval.Field(i).Int(), cval.Field(i).Int()) 587 | } 588 | } 589 | } 590 | 591 | func TestEncoderDecoder(t *testing.T) { 592 | arr_10, _ := ffi.NewArrayType(10, ffi.C_int32) 593 | sli_10, _ := ffi.NewSliceType(ffi.C_int32) 594 | 595 | const sz = 10 596 | { 597 | const val = 42 598 | for _, v := range []interface{}{ 599 | int(val), 600 | int8(val), 601 | int16(val), 602 | int32(val), 603 | int64(val), 604 | } { 605 | ct := ffi.TypeOf(v) 606 | cv := ffi.New(ct) 607 | enc := ffi.NewEncoder(cv) 608 | err := enc.Encode(v) 609 | if err != nil { 610 | t.Errorf(err.Error()) 611 | } 612 | eq(t, int64(val), cv.Int()) 613 | 614 | // now decode back 615 | vv := reflect.New(reflect.TypeOf(v)) 616 | dec := ffi.NewDecoder(cv) 617 | err = dec.Decode(vv.Interface()) 618 | if err != nil { 619 | t.Errorf(err.Error()) 620 | } 621 | eq(t, vv.Elem().Int(), cv.Int()) 622 | } 623 | } 624 | 625 | { 626 | const val = 42 627 | for _, v := range []interface{}{ 628 | uint(val), 629 | uint8(val), 630 | uint16(val), 631 | uint32(val), 632 | uint64(val), 633 | } { 634 | ct := ffi.TypeOf(v) 635 | cv := ffi.New(ct) 636 | enc := ffi.NewEncoder(cv) 637 | err := enc.Encode(v) 638 | if err != nil { 639 | t.Errorf(err.Error()) 640 | } 641 | eq(t, uint64(val), cv.Uint()) 642 | 643 | // now decode back 644 | vv := reflect.New(reflect.TypeOf(v)) 645 | dec := ffi.NewDecoder(cv) 646 | err = dec.Decode(vv.Interface()) 647 | if err != nil { 648 | t.Errorf(err.Error()) 649 | } 650 | eq(t, vv.Elem().Uint(), cv.Uint()) 651 | } 652 | } 653 | { 654 | const val = 42.0 655 | for _, v := range []interface{}{ 656 | float32(val), 657 | float64(val), 658 | } { 659 | ct := ffi.TypeOf(v) 660 | cv := ffi.New(ct) 661 | enc := ffi.NewEncoder(cv) 662 | err := enc.Encode(v) 663 | if err != nil { 664 | t.Errorf(err.Error()) 665 | } 666 | eq(t, float64(val), cv.Float()) 667 | 668 | // now decode back 669 | vv := reflect.New(reflect.TypeOf(v)) 670 | dec := ffi.NewDecoder(cv) 671 | err = dec.Decode(vv.Interface()) 672 | if err != nil { 673 | t.Errorf(err.Error()) 674 | } 675 | eq(t, vv.Elem().Float(), cv.Float()) 676 | } 677 | } 678 | { 679 | const val = 42 680 | ctyp, err := ffi.NewStructType( 681 | "struct_ints", 682 | []ffi.Field{ 683 | {"F1", ffi.C_int8}, 684 | {"F2", ffi.C_int16}, 685 | {"F3", ffi.C_int32}, 686 | {"F4", ffi.C_int64}, 687 | }) 688 | if err != nil { 689 | t.Errorf(err.Error()) 690 | } 691 | cval := ffi.New(ctyp) 692 | gval := struct { 693 | F1 int8 694 | F2 int16 695 | F3 int32 696 | F4 int64 697 | }{val + 1, val + 1, val + 1, val + 1} 698 | err = ffi.Associate(ctyp, reflect.TypeOf(gval)) 699 | if err != nil { 700 | t.Errorf(err.Error()) 701 | } 702 | 703 | enc := ffi.NewEncoder(cval) 704 | err = enc.Encode(gval) 705 | if err != nil { 706 | t.Errorf(err.Error()) 707 | } 708 | 709 | rval := reflect.ValueOf(gval) 710 | for i := 0; i < ctyp.NumField(); i++ { 711 | eq(t, rval.Field(i).Int(), cval.Field(i).Int()) 712 | } 713 | 714 | // now decode back 715 | vv := reflect.New(rval.Type()) 716 | dec := ffi.NewDecoder(cval) 717 | err = dec.Decode(vv.Interface()) 718 | if err != nil { 719 | t.Errorf(err.Error()) 720 | } 721 | rval = vv.Elem() 722 | for i := 0; i < ctyp.NumField(); i++ { 723 | eq(t, rval.Field(i).Int(), cval.Field(i).Int()) 724 | } 725 | } 726 | { 727 | const val = 42 728 | ctyp, err := ffi.NewStructType( 729 | "struct_ints_arr10", 730 | []ffi.Field{ 731 | {"F1", ffi.C_int8}, 732 | {"F2", ffi.C_int16}, 733 | {"A1", arr_10}, 734 | {"F3", ffi.C_int32}, 735 | {"F4", ffi.C_int64}, 736 | }) 737 | if err != nil { 738 | t.Errorf(err.Error()) 739 | } 740 | cval := ffi.New(ctyp) 741 | gval := struct { 742 | F1 int8 743 | F2 int16 744 | A1 [sz]int32 745 | F3 int32 746 | F4 int64 747 | }{ 748 | val + 1, val + 1, 749 | [sz]int32{ 750 | val, val, val, val, val, 751 | val, val, val, val, val, 752 | }, 753 | val + 1, val + 1, 754 | } 755 | err = ffi.Associate(ctyp, reflect.TypeOf(gval)) 756 | if err != nil { 757 | t.Errorf(err.Error()) 758 | } 759 | enc := ffi.NewEncoder(cval) 760 | err = enc.Encode(gval) 761 | if err != nil { 762 | t.Errorf(err.Error()) 763 | } 764 | 765 | rval := reflect.ValueOf(gval) 766 | eq(t, rval.Field(0).Int(), cval.Field(0).Int()) 767 | eq(t, rval.Field(1).Int(), cval.Field(1).Int()) 768 | eq(t, rval.Field(3).Int(), cval.Field(3).Int()) 769 | eq(t, rval.Field(4).Int(), cval.Field(4).Int()) 770 | rfield := cval.Field(2) 771 | cfield := cval.Field(2) 772 | eq(t, rfield.Len(), cfield.Len()) 773 | for i := 0; i < cfield.Len(); i++ { 774 | eq(t, rfield.Index(i).Int(), cfield.Index(i).Int()) 775 | } 776 | 777 | // now decode back 778 | vv := reflect.New(rval.Type()) 779 | dec := ffi.NewDecoder(cval) 780 | err = dec.Decode(vv.Interface()) 781 | if err != nil { 782 | t.Errorf(err.Error()) 783 | } 784 | rval = vv.Elem() 785 | eq(t, rval.Field(0).Int(), cval.Field(0).Int()) 786 | eq(t, rval.Field(1).Int(), cval.Field(1).Int()) 787 | eq(t, rval.Field(3).Int(), cval.Field(3).Int()) 788 | eq(t, rval.Field(4).Int(), cval.Field(4).Int()) 789 | rfield = cval.Field(2) 790 | cfield = cval.Field(2) 791 | eq(t, rfield.Len(), cfield.Len()) 792 | for i := 0; i < cfield.Len(); i++ { 793 | eq(t, rfield.Index(i).Int(), cfield.Index(i).Int()) 794 | } 795 | } 796 | { 797 | const val = 42 798 | ctyp, err := ffi.NewStructType( 799 | "struct_ints_sli10", 800 | []ffi.Field{ 801 | {"F1", ffi.C_int8}, 802 | {"F2", ffi.C_int16}, 803 | {"S1", sli_10}, 804 | {"F3", ffi.C_int32}, 805 | {"F4", ffi.C_int64}, 806 | }) 807 | if err != nil { 808 | t.Errorf(err.Error()) 809 | } 810 | cval := ffi.New(ctyp) 811 | gval := struct { 812 | F1 int8 813 | F2 int16 814 | S1 []int32 815 | F3 int32 816 | F4 int64 817 | }{ 818 | val + 1, val + 1, 819 | []int32{ 820 | val, val, val, val, val, 821 | val, val, val, val, val, 822 | }, 823 | val + 1, val + 1, 824 | } 825 | err = ffi.Associate(ctyp, reflect.TypeOf(gval)) 826 | if err != nil { 827 | t.Errorf(err.Error()) 828 | } 829 | enc := ffi.NewEncoder(cval) 830 | err = enc.Encode(gval) 831 | if err != nil { 832 | t.Errorf(err.Error()) 833 | } 834 | 835 | rval := reflect.ValueOf(gval) 836 | eq(t, rval.Field(0).Int(), cval.Field(0).Int()) 837 | eq(t, rval.Field(1).Int(), cval.Field(1).Int()) 838 | eq(t, rval.Field(3).Int(), cval.Field(3).Int()) 839 | eq(t, rval.Field(4).Int(), cval.Field(4).Int()) 840 | rfield := cval.Field(2) 841 | cfield := cval.Field(2) 842 | eq(t, rfield.Len(), cfield.Len()) 843 | for i := 0; i < cfield.Len(); i++ { 844 | eq(t, rfield.Index(i).Int(), cfield.Index(i).Int()) 845 | } 846 | 847 | // now decode back 848 | vv := reflect.New(rval.Type()) 849 | dec := ffi.NewDecoder(cval) 850 | err = dec.Decode(vv.Interface()) 851 | if err != nil { 852 | t.Errorf(err.Error()) 853 | } 854 | rval = vv.Elem() 855 | eq(t, rval.Field(0).Int(), cval.Field(0).Int()) 856 | eq(t, rval.Field(1).Int(), cval.Field(1).Int()) 857 | eq(t, rval.Field(3).Int(), cval.Field(3).Int()) 858 | eq(t, rval.Field(4).Int(), cval.Field(4).Int()) 859 | rfield = cval.Field(2) 860 | cfield = cval.Field(2) 861 | eq(t, rfield.Len(), cfield.Len()) 862 | for i := 0; i < cfield.Len(); i++ { 863 | eq(t, rfield.Index(i).Int(), cfield.Index(i).Int()) 864 | } 865 | } 866 | { 867 | const val = 42 868 | ctyp, err := ffi.NewArrayType(sz, ffi.C_int32) 869 | if err != nil { 870 | t.Errorf(err.Error()) 871 | } 872 | cval := ffi.New(ctyp) 873 | gval := [sz]int32{ 874 | val, val, val, val, val, 875 | val, val, val, val, val, 876 | } 877 | err = ffi.Associate(ctyp, reflect.TypeOf(gval)) 878 | if err != nil { 879 | t.Errorf(err.Error()) 880 | } 881 | enc := ffi.NewEncoder(cval) 882 | err = enc.Encode(gval) 883 | if err != nil { 884 | t.Errorf(err.Error()) 885 | } 886 | for i := 0; i < cval.Type().Len(); i++ { 887 | eq(t, int64(val), cval.Index(i).Int()) 888 | } 889 | 890 | // now decode back 891 | vv := reflect.New(reflect.TypeOf(gval)) 892 | dec := ffi.NewDecoder(cval) 893 | err = dec.Decode(vv.Interface()) 894 | if err != nil { 895 | t.Errorf(err.Error()) 896 | } 897 | for i := 0; i < cval.Type().Len(); i++ { 898 | eq(t, vv.Elem().Index(i).Int(), cval.Index(i).Int()) 899 | } 900 | 901 | } 902 | 903 | { 904 | const val = 42 905 | ctyp, err := ffi.NewArrayType(sz, ffi.C_float) 906 | if err != nil { 907 | t.Errorf(err.Error()) 908 | } 909 | cval := ffi.New(ctyp) 910 | gval := [sz]float32{ 911 | val, val, val, val, val, 912 | val, val, val, val, val, 913 | } 914 | enc := ffi.NewEncoder(cval) 915 | err = enc.Encode(gval) 916 | if err != nil { 917 | t.Errorf(err.Error()) 918 | } 919 | for i := 0; i < cval.Type().Len(); i++ { 920 | eq(t, float64(val), cval.Index(i).Float()) 921 | } 922 | // now decode back 923 | vv := reflect.New(reflect.TypeOf(gval)) 924 | dec := ffi.NewDecoder(cval) 925 | err = dec.Decode(vv.Interface()) 926 | if err != nil { 927 | t.Errorf(err.Error()) 928 | } 929 | for i := 0; i < cval.Type().Len(); i++ { 930 | eq(t, vv.Elem().Index(i).Float(), cval.Index(i).Float()) 931 | } 932 | 933 | } 934 | 935 | { 936 | const val = 42 937 | ctyp, err := ffi.NewSliceType(ffi.C_int32) 938 | if err != nil { 939 | t.Errorf(err.Error()) 940 | } 941 | cval := ffi.MakeSlice(ctyp, sz, sz) 942 | gval := []int32{ 943 | val, val, val, val, val, 944 | val, val, val, val, val, 945 | } 946 | enc := ffi.NewEncoder(cval) 947 | err = enc.Encode(gval) 948 | if err != nil { 949 | t.Errorf(err.Error()) 950 | } 951 | for i := 0; i < cval.Len(); i++ { 952 | eq(t, int64(val), cval.Index(i).Int()) 953 | } 954 | // now decode back 955 | vv := reflect.New(reflect.TypeOf(gval)) 956 | dec := ffi.NewDecoder(cval) 957 | err = dec.Decode(vv.Interface()) 958 | if err != nil { 959 | t.Errorf(err.Error()) 960 | } 961 | for i := 0; i < cval.Len(); i++ { 962 | eq(t, vv.Elem().Index(i).Int(), cval.Index(i).Int()) 963 | } 964 | } 965 | { 966 | const val = 42 967 | ctyp, err := ffi.NewSliceType(ffi.C_float) 968 | if err != nil { 969 | t.Errorf(err.Error()) 970 | } 971 | cval := ffi.MakeSlice(ctyp, sz, sz) 972 | gval := []float32{ 973 | val, val, val, val, val, 974 | val, val, val, val, val, 975 | } 976 | enc := ffi.NewEncoder(cval) 977 | err = enc.Encode(gval) 978 | if err != nil { 979 | t.Errorf(err.Error()) 980 | } 981 | for i := 0; i < cval.Len(); i++ { 982 | eq(t, float64(val), cval.Index(i).Float()) 983 | } 984 | { 985 | // now decode back 986 | vv := reflect.New(reflect.TypeOf(gval)) 987 | dec := ffi.NewDecoder(cval) 988 | err = dec.Decode(vv.Interface()) 989 | if err != nil { 990 | t.Errorf(err.Error()) 991 | } 992 | for i := 0; i < cval.Len(); i++ { 993 | eq(t, vv.Elem().Index(i).Float(), cval.Index(i).Float()) 994 | } 995 | } 996 | } 997 | } 998 | 999 | func TestAllocValueOf(t *testing.T) { 1000 | const nmax = 10000 1001 | type Event struct { 1002 | F float64 1003 | Arr [2]float64 1004 | Sli []float64 1005 | } 1006 | type branch struct { 1007 | g reflect.Value 1008 | c ffi.Value 1009 | update func() 1010 | } 1011 | var evt Event 1012 | evt.Sli = make([]float64, 0) 1013 | set_branch := func(objaddr interface{}) *branch { 1014 | ptr := reflect.ValueOf(objaddr) 1015 | val := reflect.Indirect(ptr) 1016 | cval := ffi.ValueOf(val.Interface()) 1017 | var br *branch 1018 | br = &branch{ 1019 | g: val, 1020 | c: cval, 1021 | update: func() { 1022 | br.c.SetValue(br.g) 1023 | }, 1024 | } 1025 | return br 1026 | } 1027 | br := set_branch(&evt) 1028 | 1029 | for i := 0; i < nmax; i++ { 1030 | evt.F = float64(i + 1) 1031 | evt.Arr[0] = -evt.F 1032 | evt.Arr[1] = -2 * evt.F 1033 | evt.Sli = evt.Sli[:0] 1034 | evt.Sli = append(evt.Sli, -evt.F) 1035 | evt.Sli = append(evt.Sli, -2*evt.F) 1036 | 1037 | br.update() 1038 | eq(t, evt.F, br.c.Field(0).Float()) 1039 | eq(t, evt.Arr[0], br.c.Field(1).Index(0).Float()) 1040 | eq(t, evt.Arr[1], br.c.Field(1).Index(1).Float()) 1041 | eq(t, evt.Sli[0], br.c.Field(2).Index(0).Float()) 1042 | eq(t, evt.Sli[1], br.c.Field(2).Index(1).Float()) 1043 | } 1044 | 1045 | for i := 0; i < nmax; i++ { 1046 | evt.F = float64(i + 1) 1047 | evt.Arr[0] = -evt.F 1048 | evt.Arr[1] = -2 * evt.F 1049 | evt.Sli[0] = -evt.F 1050 | evt.Sli[1] = -2 * evt.F 1051 | 1052 | br.update() 1053 | eq(t, evt.F, br.c.Field(0).Float()) 1054 | eq(t, evt.Arr[0], br.c.Field(1).Index(0).Float()) 1055 | eq(t, evt.Arr[1], br.c.Field(1).Index(1).Float()) 1056 | eq(t, evt.Sli[0], br.c.Field(2).Index(0).Float()) 1057 | eq(t, evt.Sli[1], br.c.Field(2).Index(1).Float()) 1058 | } 1059 | 1060 | } 1061 | 1062 | // EOF 1063 | --------------------------------------------------------------------------------