Skip to content

Commit 58c86fd

Browse files
committed
Implemented load from file safe in go port.
1 parent 40d7494 commit 58c86fd

File tree

2 files changed

+128
-46
lines changed

2 files changed

+128
-46
lines changed
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# Go Port
2+
3+
This project implements a wrapper of MetaCall API for Go.
4+
5+
## Examples
6+
7+
Non-thread safe:
8+
```go
9+
import (
10+
"github.com/metacall/core/source/ports/go_port/source"
11+
"os"
12+
)
13+
14+
func main() {
15+
16+
if err := metacall.Initialize(); err != nil {
17+
fmt.Println(err)
18+
os.Exit(1)
19+
}
20+
21+
defer metacall.Destroy()
22+
23+
scripts := []string{ "test.mock" }
24+
25+
if err := metacall.LoadFromFile("mock", scripts); err != nil {
26+
fmt.Println(err)
27+
return
28+
}
29+
30+
ret, err := metacall.Call("three_str", "e", "f", "g")
31+
32+
if err != nil {
33+
fmt.Println(err)
34+
return
35+
}
36+
37+
if str, ok := ret.(string); ok {
38+
fmt.Println(str)
39+
}
40+
}
41+
```
42+
43+
Thread safe:
44+
```go
45+
import (
46+
"github.com/metacall/core/source/ports/go_port/source"
47+
"os"
48+
)
49+
50+
func main() {
51+
52+
if err := metacall.InitializeSafe(); err != nil {
53+
fmt.Println(err)
54+
os.Exit(1)
55+
}
56+
57+
defer metacall.DestroySafe()
58+
59+
scripts := []string{"test.mock"}
60+
61+
if err := metacall.LoadFromFileSafe("mock", scripts); err != nil {
62+
fmt.Println(err)
63+
return
64+
}
65+
66+
ret, err := metacall.CallSafe("three_str", "e", "f", "g")
67+
68+
if err != nil {
69+
fmt.Println(err)
70+
return
71+
}
72+
73+
if str, ok := ret.(string); ok {
74+
fmt.Println(str)
75+
}
76+
}
77+
```

source/ports/go_port/source/go_port.go

Lines changed: 51 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -7,25 +7,41 @@ package metacall
77
import "C"
88

99
import (
10-
"errors"
10+
"fmt"
1111
"runtime"
1212
"sync"
1313
"unsafe"
1414
)
1515

16-
const PtrSizeInBytes = (32 << uintptr(^uintptr(0)>>63)) >> 3
16+
type loadFromFileSafeWork struct {
17+
tag string
18+
scripts []string
19+
err chan error
20+
}
21+
22+
type callReturnSafeWork struct {
23+
value interface{}
24+
err error
25+
}
1726

18-
type Work interface{}
27+
type callSafeWork struct {
28+
function string
29+
size int
30+
args []interface{}
31+
ret chan callReturnSafeWork
32+
}
33+
34+
const PtrSizeInBytes = (32 << uintptr(^uintptr(0)>>63)) >> 3
1935

20-
var queue = make(chan Work, 1)
36+
var queue = make(chan interface{}, 1)
2137
var toggle chan struct{}
2238
var lock sync.Mutex
2339
var wg sync.WaitGroup
2440

2541
func Initialize() error {
2642
// TODO: Remove this once go loader is implemented
27-
if int(C.metacall_initialize()) != 0 {
28-
return errors.New("MetaCall failed to initialize")
43+
if result := int(C.metacall_initialize()); result != 0 {
44+
return fmt.Errorf("initializing MetaCall (error code %d)", result)
2945
}
3046

3147
return nil
@@ -42,15 +58,19 @@ func InitializeSafe() error {
4258
}
4359

4460
toggle = make(chan struct{}, 1)
61+
initErr := make(chan error, 1)
4562

46-
go func(<-chan struct{}) {
63+
go func(initErr chan error, toggle <-chan struct{}) {
4764
// Bind this goroutine to its thread
4865
runtime.LockOSThread()
4966

5067
// Initialize MetaCall
51-
err := Initialize()
68+
if err := Initialize(); err != nil {
69+
initErr <- err
70+
return
71+
}
5272

53-
// TODO: Here I must pass err to the outside function
73+
close(initErr)
5474

5575
for {
5676
select {
@@ -64,9 +84,9 @@ func InitializeSafe() error {
6484
wg.Done()
6585
}
6686
}
67-
}(toggle)
87+
}(initErr, toggle)
6888

69-
return nil // TODO: return err
89+
return <-initErr
7090
}
7191

7292
func LoadFromFile(tag string, scripts []string) error {
@@ -86,16 +106,23 @@ func LoadFromFile(tag string, scripts []string) error {
86106
}
87107

88108
if int(C.metacall_load_from_file(cTag, (**C.char)(cScripts), (C.size_t)(size), nil)) != 0 {
89-
return errors.New("MetaCall failed to load script")
109+
return fmt.Errorf("%s loader failed to load a script from the list: %v", tag, scripts)
90110
}
91111

92112
return nil
93113
}
94114

95115
func LoadFromFileSafe(tag string, scripts []string) error {
96-
w := Work{}
116+
result := make(chan error, 1)
117+
w := loadFromFileSafeWork{
118+
tag,
119+
scripts,
120+
result,
121+
}
97122
wg.Add(1)
98123
queue <- w
124+
125+
return <-result
99126
}
100127

101128
func Call(function string, args ...interface{}) (interface{}, error) {
@@ -106,7 +133,7 @@ func Call(function string, args ...interface{}) (interface{}, error) {
106133
cFunc := C.metacall_function(cFunction)
107134

108135
if cFunc == nil {
109-
return nil, errors.New("Function not found")
136+
return nil, fmt.Errorf("function %s not found", function)
110137
}
111138

112139
size := len(args)
@@ -184,17 +211,25 @@ func Call(function string, args ...interface{}) (interface{}, error) {
184211

185212
// Call sends work and blocks until it's processed
186213
func CallSafe(function string, args ...interface{}) (interface{}, error) {
187-
w := Work{}
214+
ret := make(chan callReturnSafeWork, 1)
215+
w := callSafeWork{
216+
function: function,
217+
size: len(args),
218+
args: args,
219+
ret: ret,
220+
}
188221
wg.Add(1)
189222
queue <- w
223+
224+
return nil, nil // TODO
190225
}
191226

192227
func Destroy() {
193228
C.metacall_destroy()
194229
}
195230

196231
// Shutdown disables the metacall adapter waiting for all calls to complete
197-
func DestorySafe() {
232+
func DestroySafe() {
198233
lock.Lock()
199234
close(toggle)
200235
toggle = nil
@@ -203,33 +238,3 @@ func DestorySafe() {
203238
// Wait for all work to complete
204239
wg.Wait()
205240
}
206-
207-
/*
208-
func main() {
209-
210-
if err := metacall.Initialize(); err != nil {
211-
fmt.Println(err)
212-
os.Exit(1)
213-
}
214-
215-
defer metacall.Destroy()
216-
217-
scripts := []string{ "test.mock" }
218-
219-
if err := metacall.LoadFromFile("mock", scripts); err != nil {
220-
fmt.Println(err)
221-
return
222-
}
223-
224-
ret, err := metacall.Call("three_str", "e", "f", "g")
225-
226-
if err != nil {
227-
fmt.Println(err)
228-
return
229-
}
230-
231-
if str, ok := ret.(string); ok {
232-
fmt.Println(str)
233-
}
234-
}
235-
*/

0 commit comments

Comments
 (0)