-
Notifications
You must be signed in to change notification settings - Fork 6
/
instance.go
124 lines (111 loc) · 2.87 KB
/
instance.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
package py
/*
#include "Python.h"
*/
import "C"
import (
"fmt"
"gopkg.in/sensorbee/py.v0/mainthread"
"gopkg.in/sensorbee/sensorbee.v0/data"
"unsafe"
)
// ObjectInstance is a bind of Python instance, used as `PyInstance`.
type ObjectInstance struct {
Object
}
// Call calls `name` function.
// [TODO] this function is not supported named arguments
func (ins *ObjectInstance) Call(name string, args ...data.Value) (data.Value,
error) {
type Result struct {
val data.Value
err error
}
ch := make(chan *Result)
mainthread.Exec(func() {
if ins.p == nil {
ch <- &Result{nil, fmt.Errorf("ins.p of %p is nil while calling %s", ins, name)}
return
}
v, err := invoke(ins.p, name, args, nil)
ch <- &Result{v, err}
})
res := <-ch
return res.val, res.err
}
// CheckFunc checks if function having the name exists. It returns true when the
// function is found.
func (ins *ObjectInstance) CheckFunc(name string) bool {
ch := make(chan bool)
mainthread.Exec(func() {
if ins.p == nil {
ch <- false
return
}
f, err := getPyFunc(ins.p, name)
if err != nil {
ch <- false
return
}
defer f.decRef()
ch <- true
})
return <-ch
}
// CallDirect calls `name` function and return `PyObject` directly.
// This method is suitable for getting the instance object that called method
// returned.
func (ins *ObjectInstance) CallDirect(name string, args []data.Value,
kwdArg data.Map) (Object, error) {
type Result struct {
val Object
err error
}
ch := make(chan *Result)
mainthread.Exec(func() {
v, err := invokeDirect(ins.p, name, args, kwdArg)
ch <- &Result{v, err}
})
res := <-ch
return res.val, res.err
}
func newInstance(m *ObjectModule, name string, args []data.Value, kwdArgs data.Map) (
result ObjectInstance, resErr error) {
cName := C.CString(name)
defer C.free(unsafe.Pointer(cName))
defer func() {
if r := recover(); r != nil {
resErr = fmt.Errorf("cannot call '%v' due to panic: %v", name, r)
}
}()
pyInstance := C.PyObject_GetAttrString(m.p, cName)
if pyInstance == nil {
return ObjectInstance{}, fmt.Errorf("fail to get '%v' class: %v", name, getPyErr())
}
defer C.Py_DecRef(pyInstance)
// no named arguments
pyArg, err := convertArgsGo2Py(args)
if err != nil {
return ObjectInstance{}, fmt.Errorf("fail to convert non named arguments in creating '%v' instance: %v",
name, err.Error())
}
defer pyArg.decRef()
// named arguments
var pyKwdArg *C.PyObject
if len(kwdArgs) == 0 {
pyKwdArg = nil
} else {
o, err := newPyObj(kwdArgs)
if err != nil {
return ObjectInstance{}, fmt.Errorf("fail to convert named arguments in creating '%v' instance: %v",
name, err.Error())
}
defer o.decRef()
pyKwdArg = o.p
}
ret := C.PyObject_Call(pyInstance, pyArg.p, pyKwdArg)
if ret == nil {
return ObjectInstance{}, fmt.Errorf("fail to create '%v' instance: %v", name, getPyErr())
}
return ObjectInstance{Object{p: ret}}, nil
}