grand Go SDK update (#1165)
* grand Go SDK update - Add `outbound-redis` set operations and `execute` function - Add `key-value` support - Remove `*_free` calls since they were buggy and unnecessary given that we tell `tinygo` to leak anyway - Remove `-wasm-abi=generic` option since it's been removed as of `tinygo` 0.27 Signed-off-by: Joel Dice <joel.dice@fermyon.com> * fix Go CI issues - Update Go and `tinygo` versions - Use `interface{}` instead of `any` for broader compatibility - Make `tinygo-outbound-redis` example sort the `SMEMBERS` result before comparing with the expected value Signed-off-by: Joel Dice <joel.dice@fermyon.com> * rename Go SDK key-value directory to key_value Signed-off-by: Joel Dice <joel.dice@fermyon.com> --------- Signed-off-by: Joel Dice <joel.dice@fermyon.com>
This commit is contained in:
parent
12596f3e59
commit
49721f2daf
|
@ -63,7 +63,7 @@ inputs:
|
|||
type: bool
|
||||
golang-version:
|
||||
description: 'golang version to setup'
|
||||
default: '1.17'
|
||||
default: '1.20'
|
||||
required: false
|
||||
type: string
|
||||
|
||||
|
@ -82,10 +82,10 @@ inputs:
|
|||
description: 'setup tinygo'
|
||||
required: false
|
||||
default: 'false'
|
||||
type: bool
|
||||
type: bool
|
||||
tinygo-version:
|
||||
description: 'tinygo version to setup'
|
||||
default: 'v0.22.0'
|
||||
default: 'v0.27.0'
|
||||
required: false
|
||||
type: string
|
||||
|
||||
|
@ -150,4 +150,4 @@ runs:
|
|||
uses: rajatjindal/setup-actions/tinygo@v0.0.1
|
||||
if: ${{ inputs.tinygo == 'true' }}
|
||||
with:
|
||||
version: ${{ inputs.tinygo-version }}
|
||||
version: ${{ inputs.tinygo-version }}
|
||||
|
|
|
@ -16,4 +16,4 @@ route = "/..."
|
|||
[component.config]
|
||||
message = "I'm a {{object}}"
|
||||
[component.build]
|
||||
command = "tinygo build -wasm-abi=generic -target=wasi -gc=leaking -no-debug -o main.wasm main.go"
|
||||
command = "tinygo build -target=wasi -gc=leaking -no-debug -o main.wasm main.go"
|
||||
|
|
|
@ -25,7 +25,7 @@ Building this as a WebAssembly module can be done using the `tinygo` compiler:
|
|||
|
||||
```shell
|
||||
$ spin build
|
||||
Executing the build command for component tinygo-hello: tinygo build -wasm-abi=generic -target=wasi -gc=leaking -no-debug -o main.wasm main.go
|
||||
Executing the build command for component tinygo-hello: tinygo build -target=wasi -gc=leaking -no-debug -o main.wasm main.go
|
||||
Successfully ran the build command for the Spin components.
|
||||
```
|
||||
|
||||
|
@ -44,7 +44,7 @@ allowed_http_hosts = [ "https://some-random-api.ml", "https://postman-echo.com"
|
|||
[component.trigger]
|
||||
route = "/hello"
|
||||
[component.build]
|
||||
command = "tinygo build -wasm-abi=generic -target=wasi -gc=leaking -no-debug -o main.wasm main.go"
|
||||
command = "tinygo build -target=wasi -gc=leaking -no-debug -o main.wasm main.go"
|
||||
```
|
||||
|
||||
At this point, we can execute the application with the `spin` CLI:
|
||||
|
|
|
@ -12,4 +12,4 @@ allowed_http_hosts = ["https://some-random-api.ml", "https://postman-echo.com"]
|
|||
[component.trigger]
|
||||
route = "/hello"
|
||||
[component.build]
|
||||
command = "tinygo build -wasm-abi=generic -target=wasi -gc=leaking -no-debug -o main.wasm main.go"
|
||||
command = "tinygo build -target=wasi -gc=leaking -no-debug -o main.wasm main.go"
|
||||
|
|
|
@ -31,7 +31,7 @@ Building this as a WebAssembly module can be done using the `tinygo` compiler:
|
|||
|
||||
```shell
|
||||
$ spin build
|
||||
Executing the build command for component tinygo-hello: tinygo build -wasm-abi=generic -target=wasi -gc=leaking -no-debug -o main.wasm main.go
|
||||
Executing the build command for component tinygo-hello: tinygo build -target=wasi -gc=leaking -no-debug -o main.wasm main.go
|
||||
Successfully ran the build command for the Spin components.
|
||||
```
|
||||
|
||||
|
@ -52,7 +52,7 @@ source = "main.wasm"
|
|||
[component.trigger]
|
||||
route = "/hello"
|
||||
[component.build]
|
||||
command = "tinygo build -wasm-abi=generic -target=wasi -gc=leaking -no-debug -o main.wasm main.go"
|
||||
command = "tinygo build -target=wasi -gc=leaking -no-debug -o main.wasm main.go"
|
||||
```
|
||||
|
||||
At this point, we can execute the application with the `spin` CLI:
|
||||
|
|
|
@ -11,4 +11,4 @@ source = "main.wasm"
|
|||
[component.trigger]
|
||||
route = "/hello"
|
||||
[component.build]
|
||||
command = "tinygo build -wasm-abi=generic -target=wasi -gc=leaking -no-debug -o main.wasm main.go"
|
||||
command = "tinygo build -target=wasi -gc=leaking -no-debug -o main.wasm main.go"
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
# Spin component in TinyGo
|
||||
|
||||
```shell
|
||||
$ RUST_LOG=spin=trace spin build --up
|
||||
```
|
||||
|
||||
The application can now receive requests on `http://localhost:3000/test`:
|
||||
|
||||
```shell
|
||||
$ curl -i localhost:3000/test
|
||||
HTTP/1.1 200 OK
|
||||
content-length: 67
|
||||
date: Tue, 29 Nov 2022 07:03:52 GMT
|
||||
```
|
|
@ -0,0 +1,7 @@
|
|||
module github.com/fermyon/spin/templates/spin-http-tinygo-key-value
|
||||
|
||||
go 1.17
|
||||
|
||||
require github.com/fermyon/spin/sdk/go v0.0.0
|
||||
|
||||
replace github.com/fermyon/spin/sdk/go v0.0.0 => ../../sdk/go/
|
|
@ -0,0 +1,74 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"reflect"
|
||||
"fmt"
|
||||
|
||||
spin_http "github.com/fermyon/spin/sdk/go/http"
|
||||
"github.com/fermyon/spin/sdk/go/key_value"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
||||
// handler for the http trigger
|
||||
spin_http.Handle(func(w http.ResponseWriter, r *http.Request) {
|
||||
store, err := key_value.Open("default");
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
defer key_value.Close(store)
|
||||
|
||||
if err := key_value.Set(store, "foo", []byte("bar")); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
{
|
||||
expected := []byte("bar")
|
||||
if value, err := key_value.Get(store, "foo"); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
} else if !reflect.DeepEqual(value, expected) {
|
||||
http.Error(
|
||||
w,
|
||||
fmt.Sprintf("expected %v, got %v", expected, value),
|
||||
http.StatusInternalServerError,
|
||||
)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
expected := []string{"foo"}
|
||||
if value, err := key_value.GetKeys(store); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
} else if !reflect.DeepEqual(value, expected) {
|
||||
http.Error(
|
||||
w,
|
||||
fmt.Sprintf("expected %v, got %v", expected, value),
|
||||
http.StatusInternalServerError,
|
||||
)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if err := key_value.Delete(store, "foo"); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if exists, err := key_value.Exists(store, "foo"); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
} else if exists {
|
||||
http.Error(w, "key was not deleted as expected", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func main() {}
|
|
@ -0,0 +1,14 @@
|
|||
spin_version = "1"
|
||||
authors = ["Fermyon Engineering <engineering@fermyon.com>"]
|
||||
name = "tinygo-key-value-example"
|
||||
trigger = { type = "http", base = "/" }
|
||||
version = "0.1.0"
|
||||
|
||||
[[component]]
|
||||
id = "key-value"
|
||||
source = "main.wasm"
|
||||
key_value_stores = ["default"]
|
||||
[component.trigger]
|
||||
route = "/test"
|
||||
[component.build]
|
||||
command = "tinygo build -target=wasi -gc=leaking -no-debug -o main.wasm main.go"
|
|
@ -4,4 +4,6 @@ go 1.17
|
|||
|
||||
require github.com/fermyon/spin/sdk/go v0.0.0
|
||||
|
||||
require golang.org/x/exp v0.0.0-20230213192124-5e25df0256eb // indirect
|
||||
|
||||
replace github.com/fermyon/spin/sdk/go v0.0.0 => ../../sdk/go/
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
golang.org/x/exp v0.0.0-20230213192124-5e25df0256eb h1:PaBZQdo+iSDyHT053FjUCgZQ/9uqVwPOcl7KSWhKn6w=
|
||||
golang.org/x/exp v0.0.0-20230213192124-5e25df0256eb/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
|
@ -4,7 +4,10 @@ import (
|
|||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"reflect"
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/exp/slices"
|
||||
spin_http "github.com/fermyon/spin/sdk/go/http"
|
||||
"github.com/fermyon/spin/sdk/go/redis"
|
||||
)
|
||||
|
@ -39,6 +42,7 @@ func init() {
|
|||
// get redis payload for `mykey`
|
||||
if payload, err := redis.Get(addr, "mykey"); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
} else {
|
||||
w.Write([]byte("mykey value was: "))
|
||||
w.Write(payload)
|
||||
|
@ -48,6 +52,7 @@ func init() {
|
|||
// incr `spin-go-incr` by 1
|
||||
if payload, err := redis.Incr(addr, "spin-go-incr"); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
} else {
|
||||
w.Write([]byte("spin-go-incr value: "))
|
||||
w.Write([]byte(strconv.FormatInt(payload, 10)))
|
||||
|
@ -62,6 +67,83 @@ func init() {
|
|||
w.Write([]byte(strconv.FormatInt(payload, 10)))
|
||||
w.Write([]byte("\n"))
|
||||
}
|
||||
|
||||
if _, err := redis.Sadd(addr, "myset", []string{"foo", "bar"}); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
{
|
||||
expected := []string{"bar", "foo"}
|
||||
payload, err := redis.Smembers(addr, "myset")
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
slices.Sort(payload)
|
||||
if !reflect.DeepEqual(payload, expected) {
|
||||
http.Error(
|
||||
w,
|
||||
fmt.Sprintf(
|
||||
"unexpected SMEMBERS result: expected %v, got %v",
|
||||
expected,
|
||||
payload,
|
||||
),
|
||||
http.StatusInternalServerError,
|
||||
)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := redis.Srem(addr, "myset", []string{"bar"}); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
{
|
||||
expected := []string{"foo"}
|
||||
if payload, err := redis.Smembers(addr, "myset"); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
} else if !reflect.DeepEqual(payload, expected) {
|
||||
http.Error(
|
||||
w,
|
||||
fmt.Sprintf(
|
||||
"unexpected SMEMBERS result: expected %v, got %v",
|
||||
expected,
|
||||
payload,
|
||||
),
|
||||
http.StatusInternalServerError,
|
||||
)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
message := redis.RedisParameter{Kind: redis.RedisParameterKindBinary, Val: []byte("message")}
|
||||
hello := redis.RedisParameter{Kind: redis.RedisParameterKindBinary, Val: []byte("hello")}
|
||||
if _, err := redis.Execute(addr, "set", []redis.RedisParameter{message, hello}); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
world := redis.RedisParameter{Kind: redis.RedisParameterKindBinary, Val: []byte(" world")}
|
||||
if _, err := redis.Execute(addr, "append", []redis.RedisParameter{message, world}); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if payload, err := redis.Execute(addr, "get", []redis.RedisParameter{message}); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
} else if !reflect.DeepEqual(
|
||||
payload,
|
||||
[]redis.RedisResult{redis.RedisResult{
|
||||
Kind: redis.RedisResultKindBinary,
|
||||
Val: []byte("hello world"),
|
||||
}}) {
|
||||
http.Error(w, "unexpected GET result", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -11,4 +11,4 @@ environment = { REDIS_ADDRESS = "redis://127.0.0.1:6379", REDIS_CHANNEL = "messa
|
|||
[component.trigger]
|
||||
route = "/publish"
|
||||
[component.build]
|
||||
command = "tinygo build -wasm-abi=generic -target=wasi -gc=leaking -no-debug -o main.wasm main.go"
|
||||
command = "tinygo build -target=wasi -gc=leaking -no-debug -o main.wasm main.go"
|
||||
|
|
|
@ -11,4 +11,4 @@ source = "main.wasm"
|
|||
[component.trigger]
|
||||
channel = "messages"
|
||||
[component.build]
|
||||
command = "tinygo build -wasm-abi=generic -target=wasi -gc=leaking -no-debug -o main.wasm main.go"
|
||||
command = "tinygo build -target=wasi -gc=leaking -no-debug -o main.wasm main.go"
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
# ----------------------------------------------------------------------
|
||||
.PHONY: test
|
||||
test: test-integration
|
||||
tinygo test -wasm-abi=generic -target=wasi -gc=leaking -v ./http
|
||||
tinygo test -wasm-abi=generic -target=wasi -gc=leaking -v ./redis
|
||||
tinygo test -target=wasi -gc=leaking -v ./http
|
||||
tinygo test -target=wasi -gc=leaking -v ./redis
|
||||
|
||||
.PHONY: test-integration
|
||||
test-integration: http/testdata/http-tinygo/main.wasm
|
||||
|
@ -12,7 +12,7 @@ test-integration: http/testdata/http-tinygo/main.wasm
|
|||
|
||||
http/testdata/http-tinygo/main.wasm: generate
|
||||
http/testdata/http-tinygo/main.wasm: http/testdata/http-tinygo/main.go
|
||||
tinygo build -wasm-abi=generic -target=wasi -gc=leaking -no-debug -o http/testdata/http-tinygo/main.wasm http/testdata/http-tinygo/main.go
|
||||
tinygo build -target=wasi -gc=leaking -no-debug -o http/testdata/http-tinygo/main.wasm http/testdata/http-tinygo/main.go
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Build examples
|
||||
|
@ -26,9 +26,10 @@ build-examples: $(EXAMPLES_DIR)/http-tinygo-outbound-http/main.wasm
|
|||
build-examples: $(EXAMPLES_DIR)/http-tinygo/main.wasm
|
||||
build-examples: $(EXAMPLES_DIR)/tinygo-outbound-redis/main.wasm
|
||||
build-examples: $(EXAMPLES_DIR)/tinygo-redis/main.wasm
|
||||
build-examples: $(EXAMPLES_DIR)/tinygo-key-value/main.wasm
|
||||
|
||||
$(EXAMPLES_DIR)/%/main.wasm: $(EXAMPLES_DIR)/%/main.go
|
||||
tinygo build -wasm-abi=generic -target=wasi -gc=leaking -no-debug -o $@ $<
|
||||
tinygo build -target=wasi -gc=leaking -no-debug -o $@ $<
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Generate C bindings
|
||||
|
@ -38,11 +39,12 @@ GENERATED_OUTBOUND_HTTP = http/wasi-outbound-http.c http/wasi-outbound-http.h
|
|||
GENERATED_SPIN_HTTP = http/spin-http.c http/spin-http.h
|
||||
GENERATED_OUTBOUND_REDIS = redis/outbound-redis.c redis/outbound-redis.h
|
||||
GENERATED_SPIN_REDIS = redis/spin-redis.c redis/spin-redis.h
|
||||
GENERATED_KEY_VALUE = key_value/key-value.c key_value/key-value.h
|
||||
|
||||
.PHONY: generate
|
||||
generate: $(GENERATED_OUTBOUND_HTTP) $(GENERATED_SPIN_HTTP)
|
||||
generate: $(GENERATED_OUTBOUND_REDIS) $(GENERATED_SPIN_REDIS)
|
||||
generate: $(GENERATED_SPIN_CONFIG)
|
||||
generate: $(GENERATED_SPIN_CONFIG) $(GENERATED_KEY_VALUE)
|
||||
|
||||
$(GENERATED_SPIN_CONFIG):
|
||||
wit-bindgen c --import ../../wit/ephemeral/spin-config.wit --out-dir ./config
|
||||
|
@ -59,16 +61,21 @@ $(GENERATED_OUTBOUND_REDIS):
|
|||
$(GENERATED_SPIN_REDIS):
|
||||
wit-bindgen c --export ../../wit/ephemeral/spin-redis.wit --out-dir ./redis
|
||||
|
||||
$(GENERATED_KEY_VALUE):
|
||||
wit-bindgen c --import ../../wit/ephemeral/key-value.wit --out-dir ./key_value
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Cleanup
|
||||
# ----------------------------------------------------------------------
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf $(GENERATED_SPIN_CONFIG)
|
||||
rm -f $(GENERATED_SPIN_CONFIG)
|
||||
rm -f $(GENERATED_OUTBOUND_HTTP) $(GENERATED_SPIN_HTTP)
|
||||
rm -f $(GENERATED_OUTBOUND_REDIS) $(GENERATED_SPIN_REDIS)
|
||||
rm -f $(GENERATED_KEY_VALUE)
|
||||
rm -f http/testdata/http-tinygo/main.wasm
|
||||
rm -f $(EXAMPLES_DIR)/http-tinygo/main.wasm
|
||||
rm -f $(EXAMPLES_DIR)/http-tinygo-outbound-http/main.wasm
|
||||
rm -f $(EXAMPLES_DIR)/tinygo-outbound-redis/main.wasm
|
||||
rm -f $(EXAMPLES_DIR)/tinygo-redis/main.wasm
|
||||
rm -f $(EXAMPLES_DIR)/tinygo-key-value/main.wasm
|
||||
|
|
|
@ -15,8 +15,6 @@ import (
|
|||
|
||||
//export spin_http_handle_http_request
|
||||
func handle_http_request(req *C.spin_http_request_t, res *C.spin_http_response_t) {
|
||||
defer C.spin_http_request_free(req)
|
||||
|
||||
var body []byte
|
||||
if req.body.is_some {
|
||||
body = C.GoBytes(unsafe.Pointer(req.body.val.ptr), C.int(req.body.val.len))
|
||||
|
|
|
@ -43,10 +43,6 @@ func post(url string, contentType string, body io.Reader) (*http.Response, error
|
|||
func send(req *http.Request) (*http.Response, error) {
|
||||
var spinReq C.wasi_outbound_http_request_t
|
||||
var spinRes C.wasi_outbound_http_response_t
|
||||
defer func() {
|
||||
C.wasi_outbound_http_request_free(&spinReq)
|
||||
C.wasi_outbound_http_response_free(&spinRes)
|
||||
}()
|
||||
|
||||
m, err := method(req.Method)
|
||||
if err != nil {
|
||||
|
|
|
@ -37,6 +37,7 @@ extern "C"
|
|||
#define SPIN_HTTP_HTTP_ERROR_INVALID_URL 2
|
||||
#define SPIN_HTTP_HTTP_ERROR_REQUEST_ERROR 3
|
||||
#define SPIN_HTTP_HTTP_ERROR_RUNTIME_ERROR 4
|
||||
#define SPIN_HTTP_HTTP_ERROR_TOO_MANY_REQUESTS 5
|
||||
typedef uint16_t spin_http_http_status_t;
|
||||
typedef uint8_t spin_http_method_t;
|
||||
#define SPIN_HTTP_METHOD_GET 0
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
.PHONY: build
|
||||
build:
|
||||
tinygo build -wasm-abi=generic -target=wasi -gc=leaking -o main.wasm main.go
|
||||
tinygo build -target=wasi -gc=leaking -o main.wasm main.go
|
||||
|
|
|
@ -37,6 +37,7 @@ extern "C"
|
|||
#define WASI_OUTBOUND_HTTP_HTTP_ERROR_INVALID_URL 2
|
||||
#define WASI_OUTBOUND_HTTP_HTTP_ERROR_REQUEST_ERROR 3
|
||||
#define WASI_OUTBOUND_HTTP_HTTP_ERROR_RUNTIME_ERROR 4
|
||||
#define WASI_OUTBOUND_HTTP_HTTP_ERROR_TOO_MANY_REQUESTS 5
|
||||
typedef uint16_t wasi_outbound_http_http_status_t;
|
||||
typedef uint8_t wasi_outbound_http_method_t;
|
||||
#define WASI_OUTBOUND_HTTP_METHOD_GET 0
|
||||
|
|
|
@ -61,7 +61,7 @@ func buildTinyGo(t *testing.T, dir string) {
|
|||
|
||||
t.Log("building example: ", dir)
|
||||
|
||||
cmd := exec.Command("tinygo", "build", "-wasm-abi=generic", "-target=wasi", "-gc=leaking", "-o", "main.wasm", "main.go")
|
||||
cmd := exec.Command("tinygo", "build", "-target=wasi", "-gc=leaking", "-o", "main.wasm", "main.go")
|
||||
cmd.Dir = dir
|
||||
|
||||
stderr := new(bytes.Buffer)
|
||||
|
@ -110,6 +110,7 @@ func TestBuildExamples(t *testing.T) {
|
|||
"../../examples/http-tinygo-outbound-http",
|
||||
"../../examples/tinygo-outbound-redis",
|
||||
"../../examples/tinygo-redis",
|
||||
"../../examples/tinygo-key-value",
|
||||
} {
|
||||
buildTinyGo(t, example)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,367 @@
|
|||
#include <stdlib.h>
|
||||
#include <key-value.h>
|
||||
|
||||
__attribute__((weak, export_name("canonical_abi_realloc")))
|
||||
void *canonical_abi_realloc(
|
||||
void *ptr,
|
||||
size_t orig_size,
|
||||
size_t align,
|
||||
size_t new_size
|
||||
) {
|
||||
if (new_size == 0)
|
||||
return (void*) align;
|
||||
void *ret = realloc(ptr, new_size);
|
||||
if (!ret)
|
||||
abort();
|
||||
return ret;
|
||||
}
|
||||
|
||||
__attribute__((weak, export_name("canonical_abi_free")))
|
||||
void canonical_abi_free(
|
||||
void *ptr,
|
||||
size_t size,
|
||||
size_t align
|
||||
) {
|
||||
if (size == 0)
|
||||
return;
|
||||
free(ptr);
|
||||
}
|
||||
#include <string.h>
|
||||
|
||||
void key_value_string_set(key_value_string_t *ret, const char *s) {
|
||||
ret->ptr = (char*) s;
|
||||
ret->len = strlen(s);
|
||||
}
|
||||
|
||||
void key_value_string_dup(key_value_string_t *ret, const char *s) {
|
||||
ret->len = strlen(s);
|
||||
ret->ptr = canonical_abi_realloc(NULL, 0, 1, ret->len);
|
||||
memcpy(ret->ptr, s, ret->len);
|
||||
}
|
||||
|
||||
void key_value_string_free(key_value_string_t *ret) {
|
||||
canonical_abi_free(ret->ptr, ret->len, 1);
|
||||
ret->ptr = NULL;
|
||||
ret->len = 0;
|
||||
}
|
||||
void key_value_error_free(key_value_error_t *ptr) {
|
||||
switch ((int32_t) ptr->tag) {
|
||||
case 5: {
|
||||
key_value_string_free(&ptr->val.io);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
void key_value_expected_store_error_free(key_value_expected_store_error_t *ptr) {
|
||||
if (!ptr->is_err) {
|
||||
} else {
|
||||
key_value_error_free(&ptr->val.err);
|
||||
}
|
||||
}
|
||||
void key_value_list_u8_free(key_value_list_u8_t *ptr) {
|
||||
canonical_abi_free(ptr->ptr, ptr->len * 1, 1);
|
||||
}
|
||||
void key_value_expected_list_u8_error_free(key_value_expected_list_u8_error_t *ptr) {
|
||||
if (!ptr->is_err) {
|
||||
key_value_list_u8_free(&ptr->val.ok);
|
||||
} else {
|
||||
key_value_error_free(&ptr->val.err);
|
||||
}
|
||||
}
|
||||
void key_value_expected_unit_error_free(key_value_expected_unit_error_t *ptr) {
|
||||
if (!ptr->is_err) {
|
||||
} else {
|
||||
key_value_error_free(&ptr->val.err);
|
||||
}
|
||||
}
|
||||
void key_value_expected_bool_error_free(key_value_expected_bool_error_t *ptr) {
|
||||
if (!ptr->is_err) {
|
||||
} else {
|
||||
key_value_error_free(&ptr->val.err);
|
||||
}
|
||||
}
|
||||
void key_value_list_string_free(key_value_list_string_t *ptr) {
|
||||
for (size_t i = 0; i < ptr->len; i++) {
|
||||
key_value_string_free(&ptr->ptr[i]);
|
||||
}
|
||||
canonical_abi_free(ptr->ptr, ptr->len * 8, 4);
|
||||
}
|
||||
void key_value_expected_list_string_error_free(key_value_expected_list_string_error_t *ptr) {
|
||||
if (!ptr->is_err) {
|
||||
key_value_list_string_free(&ptr->val.ok);
|
||||
} else {
|
||||
key_value_error_free(&ptr->val.err);
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((aligned(4)))
|
||||
static uint8_t RET_AREA[16];
|
||||
__attribute__((import_module("key-value"), import_name("open")))
|
||||
void __wasm_import_key_value_open(int32_t, int32_t, int32_t);
|
||||
void key_value_open(key_value_string_t *name, key_value_expected_store_error_t *ret0) {
|
||||
int32_t ptr = (int32_t) &RET_AREA;
|
||||
__wasm_import_key_value_open((int32_t) (*name).ptr, (int32_t) (*name).len, ptr);
|
||||
key_value_expected_store_error_t expected;
|
||||
switch ((int32_t) (*((uint8_t*) (ptr + 0)))) {
|
||||
case 0: {
|
||||
expected.is_err = false;
|
||||
|
||||
expected.val.ok = (uint32_t) (*((int32_t*) (ptr + 4)));
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
expected.is_err = true;
|
||||
key_value_error_t variant;
|
||||
variant.tag = (int32_t) (*((uint8_t*) (ptr + 4)));
|
||||
switch ((int32_t) variant.tag) {
|
||||
case 0: {
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
break;
|
||||
}
|
||||
case 5: {
|
||||
variant.val.io = (key_value_string_t) { (char*)(*((int32_t*) (ptr + 8))), (size_t)(*((int32_t*) (ptr + 12))) };
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
expected.val.err = variant;
|
||||
break;
|
||||
}
|
||||
}*ret0 = expected;
|
||||
}
|
||||
__attribute__((import_module("key-value"), import_name("get")))
|
||||
void __wasm_import_key_value_get(int32_t, int32_t, int32_t, int32_t);
|
||||
void key_value_get(key_value_store_t store, key_value_string_t *key, key_value_expected_list_u8_error_t *ret0) {
|
||||
int32_t ptr = (int32_t) &RET_AREA;
|
||||
__wasm_import_key_value_get((int32_t) (store), (int32_t) (*key).ptr, (int32_t) (*key).len, ptr);
|
||||
key_value_expected_list_u8_error_t expected;
|
||||
switch ((int32_t) (*((uint8_t*) (ptr + 0)))) {
|
||||
case 0: {
|
||||
expected.is_err = false;
|
||||
|
||||
expected.val.ok = (key_value_list_u8_t) { (uint8_t*)(*((int32_t*) (ptr + 4))), (size_t)(*((int32_t*) (ptr + 8))) };
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
expected.is_err = true;
|
||||
key_value_error_t variant;
|
||||
variant.tag = (int32_t) (*((uint8_t*) (ptr + 4)));
|
||||
switch ((int32_t) variant.tag) {
|
||||
case 0: {
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
break;
|
||||
}
|
||||
case 5: {
|
||||
variant.val.io = (key_value_string_t) { (char*)(*((int32_t*) (ptr + 8))), (size_t)(*((int32_t*) (ptr + 12))) };
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
expected.val.err = variant;
|
||||
break;
|
||||
}
|
||||
}*ret0 = expected;
|
||||
}
|
||||
__attribute__((import_module("key-value"), import_name("set")))
|
||||
void __wasm_import_key_value_set(int32_t, int32_t, int32_t, int32_t, int32_t, int32_t);
|
||||
void key_value_set(key_value_store_t store, key_value_string_t *key, key_value_list_u8_t *value, key_value_expected_unit_error_t *ret0) {
|
||||
int32_t ptr = (int32_t) &RET_AREA;
|
||||
__wasm_import_key_value_set((int32_t) (store), (int32_t) (*key).ptr, (int32_t) (*key).len, (int32_t) (*value).ptr, (int32_t) (*value).len, ptr);
|
||||
key_value_expected_unit_error_t expected;
|
||||
switch ((int32_t) (*((uint8_t*) (ptr + 0)))) {
|
||||
case 0: {
|
||||
expected.is_err = false;
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
expected.is_err = true;
|
||||
key_value_error_t variant;
|
||||
variant.tag = (int32_t) (*((uint8_t*) (ptr + 4)));
|
||||
switch ((int32_t) variant.tag) {
|
||||
case 0: {
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
break;
|
||||
}
|
||||
case 5: {
|
||||
variant.val.io = (key_value_string_t) { (char*)(*((int32_t*) (ptr + 8))), (size_t)(*((int32_t*) (ptr + 12))) };
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
expected.val.err = variant;
|
||||
break;
|
||||
}
|
||||
}*ret0 = expected;
|
||||
}
|
||||
__attribute__((import_module("key-value"), import_name("delete")))
|
||||
void __wasm_import_key_value_delete(int32_t, int32_t, int32_t, int32_t);
|
||||
void key_value_delete(key_value_store_t store, key_value_string_t *key, key_value_expected_unit_error_t *ret0) {
|
||||
int32_t ptr = (int32_t) &RET_AREA;
|
||||
__wasm_import_key_value_delete((int32_t) (store), (int32_t) (*key).ptr, (int32_t) (*key).len, ptr);
|
||||
key_value_expected_unit_error_t expected;
|
||||
switch ((int32_t) (*((uint8_t*) (ptr + 0)))) {
|
||||
case 0: {
|
||||
expected.is_err = false;
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
expected.is_err = true;
|
||||
key_value_error_t variant;
|
||||
variant.tag = (int32_t) (*((uint8_t*) (ptr + 4)));
|
||||
switch ((int32_t) variant.tag) {
|
||||
case 0: {
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
break;
|
||||
}
|
||||
case 5: {
|
||||
variant.val.io = (key_value_string_t) { (char*)(*((int32_t*) (ptr + 8))), (size_t)(*((int32_t*) (ptr + 12))) };
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
expected.val.err = variant;
|
||||
break;
|
||||
}
|
||||
}*ret0 = expected;
|
||||
}
|
||||
__attribute__((import_module("key-value"), import_name("exists")))
|
||||
void __wasm_import_key_value_exists(int32_t, int32_t, int32_t, int32_t);
|
||||
void key_value_exists(key_value_store_t store, key_value_string_t *key, key_value_expected_bool_error_t *ret0) {
|
||||
int32_t ptr = (int32_t) &RET_AREA;
|
||||
__wasm_import_key_value_exists((int32_t) (store), (int32_t) (*key).ptr, (int32_t) (*key).len, ptr);
|
||||
key_value_expected_bool_error_t expected;
|
||||
switch ((int32_t) (*((uint8_t*) (ptr + 0)))) {
|
||||
case 0: {
|
||||
expected.is_err = false;
|
||||
|
||||
expected.val.ok = (int32_t) (*((uint8_t*) (ptr + 4)));
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
expected.is_err = true;
|
||||
key_value_error_t variant;
|
||||
variant.tag = (int32_t) (*((uint8_t*) (ptr + 4)));
|
||||
switch ((int32_t) variant.tag) {
|
||||
case 0: {
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
break;
|
||||
}
|
||||
case 5: {
|
||||
variant.val.io = (key_value_string_t) { (char*)(*((int32_t*) (ptr + 8))), (size_t)(*((int32_t*) (ptr + 12))) };
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
expected.val.err = variant;
|
||||
break;
|
||||
}
|
||||
}*ret0 = expected;
|
||||
}
|
||||
__attribute__((import_module("key-value"), import_name("get-keys")))
|
||||
void __wasm_import_key_value_get_keys(int32_t, int32_t);
|
||||
void key_value_get_keys(key_value_store_t store, key_value_expected_list_string_error_t *ret0) {
|
||||
int32_t ptr = (int32_t) &RET_AREA;
|
||||
__wasm_import_key_value_get_keys((int32_t) (store), ptr);
|
||||
key_value_expected_list_string_error_t expected;
|
||||
switch ((int32_t) (*((uint8_t*) (ptr + 0)))) {
|
||||
case 0: {
|
||||
expected.is_err = false;
|
||||
|
||||
expected.val.ok = (key_value_list_string_t) { (key_value_string_t*)(*((int32_t*) (ptr + 4))), (size_t)(*((int32_t*) (ptr + 8))) };
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
expected.is_err = true;
|
||||
key_value_error_t variant;
|
||||
variant.tag = (int32_t) (*((uint8_t*) (ptr + 4)));
|
||||
switch ((int32_t) variant.tag) {
|
||||
case 0: {
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
break;
|
||||
}
|
||||
case 5: {
|
||||
variant.val.io = (key_value_string_t) { (char*)(*((int32_t*) (ptr + 8))), (size_t)(*((int32_t*) (ptr + 12))) };
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
expected.val.err = variant;
|
||||
break;
|
||||
}
|
||||
}*ret0 = expected;
|
||||
}
|
||||
__attribute__((import_module("key-value"), import_name("close")))
|
||||
void __wasm_import_key_value_close(int32_t);
|
||||
void key_value_close(key_value_store_t store) {
|
||||
__wasm_import_key_value_close((int32_t) (store));
|
||||
}
|
|
@ -0,0 +1,134 @@
|
|||
package key_value
|
||||
|
||||
// #include "key-value.h"
|
||||
import "C"
|
||||
import (
|
||||
"errors"
|
||||
"unsafe"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type Store C.key_value_store_t
|
||||
|
||||
type ErrorKind C.uint8_t
|
||||
|
||||
const (
|
||||
ErrorKindStoreTableFull = iota
|
||||
ErrorKindNoSuchStore
|
||||
ErrorKindAccessDenied
|
||||
ErrorKindInvalidStore
|
||||
ErrorKindNoSuchKey
|
||||
ErrorKindIo
|
||||
)
|
||||
|
||||
type Error struct {
|
||||
Kind ErrorKind
|
||||
Val interface{}
|
||||
}
|
||||
|
||||
func Open(name string) (Store, error) {
|
||||
cname := toCStr(name)
|
||||
var ret C.key_value_expected_store_error_t
|
||||
C.key_value_open(&cname, &ret)
|
||||
if ret.is_err {
|
||||
return 0xFFFF_FFFF, toErr((*C.key_value_error_t)(unsafe.Pointer(&ret.val)))
|
||||
} else {
|
||||
return *(*Store)(unsafe.Pointer(&ret.val)), nil
|
||||
}
|
||||
}
|
||||
|
||||
func Get(store Store, key string) ([]byte, error) {
|
||||
ckey := toCStr(key)
|
||||
var ret C.key_value_expected_list_u8_error_t
|
||||
C.key_value_get(C.uint32_t(store), &ckey, &ret)
|
||||
if ret.is_err {
|
||||
return []byte{}, toErr((*C.key_value_error_t)(unsafe.Pointer(&ret.val)))
|
||||
} else {
|
||||
list := (*C.key_value_list_u8_t)(unsafe.Pointer(&ret.val))
|
||||
return C.GoBytes(unsafe.Pointer(list.ptr), C.int(list.len)), nil
|
||||
}
|
||||
}
|
||||
|
||||
func Set(store Store, key string, value []byte) error {
|
||||
ckey := toCStr(key)
|
||||
cbytes := toCBytes(value)
|
||||
var ret C.key_value_expected_unit_error_t
|
||||
C.key_value_set(C.uint32_t(store), &ckey, &cbytes, &ret)
|
||||
if ret.is_err {
|
||||
return toErr((*C.key_value_error_t)(unsafe.Pointer(&ret.val)))
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func Delete(store Store, key string) error {
|
||||
ckey := toCStr(key)
|
||||
var ret C.key_value_expected_unit_error_t
|
||||
C.key_value_delete(C.uint32_t(store), &ckey, &ret)
|
||||
if ret.is_err {
|
||||
return toErr((*C.key_value_error_t)(unsafe.Pointer(&ret.val)))
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func Exists(store Store, key string) (bool, error) {
|
||||
ckey := toCStr(key)
|
||||
var ret C.key_value_expected_bool_error_t
|
||||
C.key_value_exists(C.uint32_t(store), &ckey, &ret)
|
||||
if ret.is_err {
|
||||
return false, toErr((*C.key_value_error_t)(unsafe.Pointer(&ret.val)))
|
||||
} else {
|
||||
return *(*bool)(unsafe.Pointer(&ret.val)), nil
|
||||
}
|
||||
}
|
||||
|
||||
func GetKeys(store Store) ([]string, error) {
|
||||
var ret C.key_value_expected_list_string_error_t
|
||||
C.key_value_get_keys(C.uint32_t(store), &ret)
|
||||
if ret.is_err {
|
||||
return []string{}, toErr((*C.key_value_error_t)(unsafe.Pointer(&ret.val)))
|
||||
} else {
|
||||
return fromCStrList((*C.key_value_list_string_t)(unsafe.Pointer(&ret.val))), nil
|
||||
}
|
||||
}
|
||||
|
||||
func Close(store Store) {
|
||||
C.key_value_close(C.uint32_t(store))
|
||||
}
|
||||
|
||||
func toCBytes(x []byte) C.key_value_list_u8_t {
|
||||
return C.key_value_list_u8_t{ptr: &x[0], len: C.size_t(len(x))}
|
||||
}
|
||||
|
||||
func toCStr(x string) C.key_value_string_t {
|
||||
return C.key_value_string_t{ptr: C.CString(x), len: C.size_t(len(x))}
|
||||
}
|
||||
|
||||
func fromCStrList(list *C.key_value_list_string_t) []string {
|
||||
listLen := int(list.len)
|
||||
var result []string
|
||||
|
||||
slice := unsafe.Slice(list.ptr, listLen)
|
||||
for i := 0; i < listLen; i++ {
|
||||
string := slice[i]
|
||||
result = append(result, C.GoStringN(string.ptr, C.int(string.len)))
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func toErr(error *C.key_value_error_t) error {
|
||||
switch error.tag {
|
||||
case ErrorKindStoreTableFull: return errors.New("store table full")
|
||||
case ErrorKindNoSuchStore: return errors.New("no such store")
|
||||
case ErrorKindAccessDenied: return errors.New("access denied")
|
||||
case ErrorKindInvalidStore: return errors.New("invalid store")
|
||||
case ErrorKindNoSuchKey: return errors.New("no such key")
|
||||
case ErrorKindIo: {
|
||||
string := (*C.key_value_string_t)(unsafe.Pointer(&error.val))
|
||||
return errors.New(fmt.Sprintf("io error: %s", C.GoStringN(string.ptr, C.int(string.len))))
|
||||
}
|
||||
default: return errors.New(fmt.Sprintf("unrecognized error: %v", error.tag))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
#ifndef __BINDINGS_KEY_VALUE_H
|
||||
#define __BINDINGS_KEY_VALUE_H
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct {
|
||||
char *ptr;
|
||||
size_t len;
|
||||
} key_value_string_t;
|
||||
|
||||
void key_value_string_set(key_value_string_t *ret, const char *s);
|
||||
void key_value_string_dup(key_value_string_t *ret, const char *s);
|
||||
void key_value_string_free(key_value_string_t *ret);
|
||||
typedef uint32_t key_value_store_t;
|
||||
typedef struct {
|
||||
uint8_t tag;
|
||||
union {
|
||||
key_value_string_t io;
|
||||
} val;
|
||||
} key_value_error_t;
|
||||
#define KEY_VALUE_ERROR_STORE_TABLE_FULL 0
|
||||
#define KEY_VALUE_ERROR_NO_SUCH_STORE 1
|
||||
#define KEY_VALUE_ERROR_ACCESS_DENIED 2
|
||||
#define KEY_VALUE_ERROR_INVALID_STORE 3
|
||||
#define KEY_VALUE_ERROR_NO_SUCH_KEY 4
|
||||
#define KEY_VALUE_ERROR_IO 5
|
||||
void key_value_error_free(key_value_error_t *ptr);
|
||||
typedef struct {
|
||||
bool is_err;
|
||||
union {
|
||||
key_value_store_t ok;
|
||||
key_value_error_t err;
|
||||
} val;
|
||||
} key_value_expected_store_error_t;
|
||||
void key_value_expected_store_error_free(key_value_expected_store_error_t *ptr);
|
||||
typedef struct {
|
||||
uint8_t *ptr;
|
||||
size_t len;
|
||||
} key_value_list_u8_t;
|
||||
void key_value_list_u8_free(key_value_list_u8_t *ptr);
|
||||
typedef struct {
|
||||
bool is_err;
|
||||
union {
|
||||
key_value_list_u8_t ok;
|
||||
key_value_error_t err;
|
||||
} val;
|
||||
} key_value_expected_list_u8_error_t;
|
||||
void key_value_expected_list_u8_error_free(key_value_expected_list_u8_error_t *ptr);
|
||||
typedef struct {
|
||||
bool is_err;
|
||||
union {
|
||||
key_value_error_t err;
|
||||
} val;
|
||||
} key_value_expected_unit_error_t;
|
||||
void key_value_expected_unit_error_free(key_value_expected_unit_error_t *ptr);
|
||||
typedef struct {
|
||||
bool is_err;
|
||||
union {
|
||||
bool ok;
|
||||
key_value_error_t err;
|
||||
} val;
|
||||
} key_value_expected_bool_error_t;
|
||||
void key_value_expected_bool_error_free(key_value_expected_bool_error_t *ptr);
|
||||
typedef struct {
|
||||
key_value_string_t *ptr;
|
||||
size_t len;
|
||||
} key_value_list_string_t;
|
||||
void key_value_list_string_free(key_value_list_string_t *ptr);
|
||||
typedef struct {
|
||||
bool is_err;
|
||||
union {
|
||||
key_value_list_string_t ok;
|
||||
key_value_error_t err;
|
||||
} val;
|
||||
} key_value_expected_list_string_error_t;
|
||||
void key_value_expected_list_string_error_free(key_value_expected_list_string_error_t *ptr);
|
||||
void key_value_open(key_value_string_t *name, key_value_expected_store_error_t *ret0);
|
||||
void key_value_get(key_value_store_t store, key_value_string_t *key, key_value_expected_list_u8_error_t *ret0);
|
||||
void key_value_set(key_value_store_t store, key_value_string_t *key, key_value_list_u8_t *value, key_value_expected_unit_error_t *ret0);
|
||||
void key_value_delete(key_value_store_t store, key_value_string_t *key, key_value_expected_unit_error_t *ret0);
|
||||
void key_value_exists(key_value_store_t store, key_value_string_t *key, key_value_expected_bool_error_t *ret0);
|
||||
void key_value_get_keys(key_value_store_t store, key_value_expected_list_string_error_t *ret0);
|
||||
void key_value_close(key_value_store_t store);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
|
@ -24,12 +24,6 @@ func publish(addr, channel string, payload []byte) error {
|
|||
cchannel := redisStr(channel)
|
||||
cpayload := C.outbound_redis_payload_t{ptr: &payload[0], len: C.size_t(len(payload))}
|
||||
|
||||
defer func() {
|
||||
C.outbound_redis_string_free(&caddr)
|
||||
C.outbound_redis_string_free(&cchannel)
|
||||
C.outbound_redis_payload_free(&cpayload)
|
||||
}()
|
||||
|
||||
err := C.outbound_redis_publish(&caddr, &cchannel, &cpayload)
|
||||
return toErr(err)
|
||||
}
|
||||
|
@ -40,12 +34,6 @@ func get(addr, key string) ([]byte, error) {
|
|||
|
||||
var cpayload C.outbound_redis_payload_t
|
||||
|
||||
defer func() {
|
||||
C.outbound_redis_string_free(&caddr)
|
||||
C.outbound_redis_string_free(&ckey)
|
||||
C.outbound_redis_payload_free(&cpayload)
|
||||
}()
|
||||
|
||||
err := C.outbound_redis_get(&caddr, &ckey, &cpayload)
|
||||
payload := C.GoBytes(unsafe.Pointer(cpayload.ptr), C.int(cpayload.len))
|
||||
return payload, toErr(err)
|
||||
|
@ -56,12 +44,6 @@ func set(addr, key string, payload []byte) error {
|
|||
ckey := redisStr(key)
|
||||
cpayload := C.outbound_redis_payload_t{ptr: &payload[0], len: C.size_t(len(payload))}
|
||||
|
||||
defer func() {
|
||||
C.outbound_redis_string_free(&caddr)
|
||||
C.outbound_redis_string_free(&ckey)
|
||||
C.outbound_redis_payload_free(&cpayload)
|
||||
}()
|
||||
|
||||
err := C.outbound_redis_set(&caddr, &ckey, &cpayload)
|
||||
return toErr(err)
|
||||
}
|
||||
|
@ -72,11 +54,6 @@ func incr(addr, key string) (int64, error) {
|
|||
|
||||
var cpayload C.int64_t
|
||||
|
||||
defer func() {
|
||||
C.outbound_redis_string_free(&caddr)
|
||||
C.outbound_redis_string_free(&ckey)
|
||||
}()
|
||||
|
||||
err := C.outbound_redis_incr(&caddr, &ckey, &cpayload)
|
||||
return int64(cpayload), toErr(err)
|
||||
}
|
||||
|
@ -87,15 +64,83 @@ func del(addr string, keys []string) (int64, error) {
|
|||
|
||||
var cpayload C.int64_t
|
||||
|
||||
defer func() {
|
||||
C.outbound_redis_string_free(&caddr)
|
||||
C.outbound_redis_list_string_free(&ckeys)
|
||||
}()
|
||||
|
||||
err := C.outbound_redis_del(&caddr, &ckeys, &cpayload)
|
||||
return int64(cpayload), toErr(err)
|
||||
}
|
||||
|
||||
func sadd(addr string, key string, values []string) (int64, error) {
|
||||
caddr := redisStr(addr)
|
||||
ckey := redisStr(key)
|
||||
cvalues := redisListStr(values)
|
||||
|
||||
var cpayload C.int64_t
|
||||
|
||||
err := C.outbound_redis_sadd(&caddr, &ckey, &cvalues, &cpayload)
|
||||
return int64(cpayload), toErr(err)
|
||||
}
|
||||
|
||||
func smembers(addr string, key string) ([]string, error) {
|
||||
caddr := redisStr(addr)
|
||||
ckey := redisStr(key)
|
||||
|
||||
var cpayload C.outbound_redis_list_string_t
|
||||
|
||||
err := C.outbound_redis_smembers(&caddr, &ckey, &cpayload)
|
||||
return fromRedisListStr(&cpayload), toErr(err)
|
||||
}
|
||||
|
||||
func srem(addr string, key string, values []string) (int64, error) {
|
||||
caddr := redisStr(addr)
|
||||
ckey := redisStr(key)
|
||||
cvalues := redisListStr(values)
|
||||
|
||||
var cpayload C.int64_t
|
||||
|
||||
err := C.outbound_redis_srem(&caddr, &ckey, &cvalues, &cpayload)
|
||||
return int64(cpayload), toErr(err)
|
||||
}
|
||||
|
||||
type RedisParameterKind C.uint8_t
|
||||
|
||||
const (
|
||||
RedisParameterKindInt64 = iota
|
||||
RedisParameterKindBinary
|
||||
)
|
||||
|
||||
type RedisParameter struct {
|
||||
Kind RedisParameterKind
|
||||
Val interface{}
|
||||
}
|
||||
|
||||
type RedisResultKind C.uint8_t
|
||||
|
||||
const (
|
||||
RedisResultKindNil = iota
|
||||
RedisResultKindStatus
|
||||
RedisResultKindInt64
|
||||
RedisResultKindBinary
|
||||
)
|
||||
|
||||
type RedisResult struct {
|
||||
Kind RedisResultKind
|
||||
Val interface{}
|
||||
}
|
||||
|
||||
func execute(addr string, command string, arguments []RedisParameter) ([]RedisResult, error) {
|
||||
caddr := redisStr(addr)
|
||||
ccommand := redisStr(command)
|
||||
carguments := redisListParameter(arguments)
|
||||
|
||||
var cpayload C.outbound_redis_list_redis_result_t
|
||||
|
||||
err := C.outbound_redis_execute(&caddr, &ccommand, &carguments, &cpayload)
|
||||
return fromRedisListResult(&cpayload), toErr(err)
|
||||
}
|
||||
|
||||
func redisStr(x string) C.outbound_redis_string_t {
|
||||
return C.outbound_redis_string_t{ptr: C.CString(x), len: C.size_t(len(x))}
|
||||
}
|
||||
|
||||
func redisListStr(xs []string) C.outbound_redis_list_string_t {
|
||||
var cxs []C.outbound_redis_string_t
|
||||
|
||||
|
@ -105,8 +150,69 @@ func redisListStr(xs []string) C.outbound_redis_list_string_t {
|
|||
return C.outbound_redis_list_string_t{ptr: &cxs[0], len: C.size_t(len(cxs))}
|
||||
}
|
||||
|
||||
func redisStr(x string) C.outbound_redis_string_t {
|
||||
return C.outbound_redis_string_t{ptr: C.CString(x), len: C.size_t(len(x))}
|
||||
func fromRedisListStr(list *C.outbound_redis_list_string_t) []string {
|
||||
listLen := int(list.len)
|
||||
var result []string
|
||||
|
||||
slice := unsafe.Slice(list.ptr, listLen)
|
||||
for i := 0; i < listLen; i++ {
|
||||
string := slice[i]
|
||||
result = append(result, C.GoStringN(string.ptr, C.int(string.len)))
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func redisParameter(x RedisParameter) C.outbound_redis_redis_parameter_t {
|
||||
var val C._Ctype_union___9
|
||||
switch x.Kind {
|
||||
case RedisParameterKindInt64: *(*C.int64_t)(unsafe.Pointer(&val)) = x.Val.(int64)
|
||||
case RedisParameterKindBinary: {
|
||||
value := x.Val.([]byte)
|
||||
payload := C.outbound_redis_payload_t{ptr: &value[0], len: C.size_t(len(value))}
|
||||
*(*C.outbound_redis_payload_t)(unsafe.Pointer(&val)) = payload
|
||||
}
|
||||
}
|
||||
return C.outbound_redis_redis_parameter_t{tag: C.uint8_t(x.Kind), val: val}
|
||||
}
|
||||
|
||||
func redisListParameter(xs []RedisParameter) C.outbound_redis_list_redis_parameter_t {
|
||||
var cxs []C.outbound_redis_redis_parameter_t
|
||||
|
||||
for i := 0; i < len(xs); i++ {
|
||||
cxs = append(cxs, redisParameter(xs[i]))
|
||||
}
|
||||
return C.outbound_redis_list_redis_parameter_t{ptr: &cxs[0], len: C.size_t(len(cxs))}
|
||||
}
|
||||
|
||||
func fromRedisResult(result *C.outbound_redis_redis_result_t) RedisResult {
|
||||
var val interface{}
|
||||
switch result.tag {
|
||||
case 0: val = nil
|
||||
case 1: {
|
||||
string := (*C.outbound_redis_string_t)(unsafe.Pointer(&result.val))
|
||||
val = C.GoStringN(string.ptr, C.int(string.len))
|
||||
}
|
||||
case 2: val = int64(*(*C.int64_t)(unsafe.Pointer(&result.val)))
|
||||
case 3: {
|
||||
payload := (*C.outbound_redis_payload_t)(unsafe.Pointer(&result.val))
|
||||
val = C.GoBytes(unsafe.Pointer(payload.ptr), C.int(payload.len))
|
||||
}
|
||||
}
|
||||
|
||||
return RedisResult{Kind: RedisResultKind(result.tag), Val: val}
|
||||
}
|
||||
|
||||
func fromRedisListResult(list *C.outbound_redis_list_redis_result_t) []RedisResult {
|
||||
listLen := int(list.len)
|
||||
var result []RedisResult
|
||||
|
||||
slice := unsafe.Slice(list.ptr, listLen)
|
||||
for i := 0; i < listLen; i++ {
|
||||
result = append(result, fromRedisResult(&slice[i]))
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func toErr(code C.uint8_t) error {
|
||||
|
|
|
@ -47,6 +47,26 @@ void outbound_redis_string_free(outbound_redis_string_t *ret) {
|
|||
void outbound_redis_payload_free(outbound_redis_payload_t *ptr) {
|
||||
canonical_abi_free(ptr->ptr, ptr->len * 1, 1);
|
||||
}
|
||||
void outbound_redis_redis_parameter_free(outbound_redis_redis_parameter_t *ptr) {
|
||||
switch ((int32_t) ptr->tag) {
|
||||
case 1: {
|
||||
outbound_redis_payload_free(&ptr->val.binary);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
void outbound_redis_redis_result_free(outbound_redis_redis_result_t *ptr) {
|
||||
switch ((int32_t) ptr->tag) {
|
||||
case 1: {
|
||||
outbound_redis_string_free(&ptr->val.status);
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
outbound_redis_payload_free(&ptr->val.binary);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
typedef struct {
|
||||
bool is_err;
|
||||
union {
|
||||
|
@ -73,6 +93,32 @@ void outbound_redis_list_string_free(outbound_redis_list_string_t *ptr) {
|
|||
}
|
||||
canonical_abi_free(ptr->ptr, ptr->len * 8, 4);
|
||||
}
|
||||
typedef struct {
|
||||
bool is_err;
|
||||
union {
|
||||
outbound_redis_list_string_t ok;
|
||||
outbound_redis_error_t err;
|
||||
} val;
|
||||
} outbound_redis_expected_list_string_error_t;
|
||||
void outbound_redis_list_redis_parameter_free(outbound_redis_list_redis_parameter_t *ptr) {
|
||||
for (size_t i = 0; i < ptr->len; i++) {
|
||||
outbound_redis_redis_parameter_free(&ptr->ptr[i]);
|
||||
}
|
||||
canonical_abi_free(ptr->ptr, ptr->len * 16, 8);
|
||||
}
|
||||
void outbound_redis_list_redis_result_free(outbound_redis_list_redis_result_t *ptr) {
|
||||
for (size_t i = 0; i < ptr->len; i++) {
|
||||
outbound_redis_redis_result_free(&ptr->ptr[i]);
|
||||
}
|
||||
canonical_abi_free(ptr->ptr, ptr->len * 16, 8);
|
||||
}
|
||||
typedef struct {
|
||||
bool is_err;
|
||||
union {
|
||||
outbound_redis_list_redis_result_t ok;
|
||||
outbound_redis_error_t err;
|
||||
} val;
|
||||
} outbound_redis_expected_list_redis_result_error_t;
|
||||
|
||||
__attribute__((aligned(8)))
|
||||
static uint8_t RET_AREA[16];
|
||||
|
@ -184,3 +230,91 @@ outbound_redis_error_t outbound_redis_del(outbound_redis_string_t *address, outb
|
|||
}*ret0 = expected.val.ok;
|
||||
return expected.is_err ? expected.val.err : -1;
|
||||
}
|
||||
__attribute__((import_module("outbound-redis"), import_name("sadd")))
|
||||
void __wasm_import_outbound_redis_sadd(int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t);
|
||||
outbound_redis_error_t outbound_redis_sadd(outbound_redis_string_t *address, outbound_redis_string_t *key, outbound_redis_list_string_t *values, int64_t *ret0) {
|
||||
int32_t ptr = (int32_t) &RET_AREA;
|
||||
__wasm_import_outbound_redis_sadd((int32_t) (*address).ptr, (int32_t) (*address).len, (int32_t) (*key).ptr, (int32_t) (*key).len, (int32_t) (*values).ptr, (int32_t) (*values).len, ptr);
|
||||
outbound_redis_expected_s64_error_t expected;
|
||||
switch ((int32_t) (*((uint8_t*) (ptr + 0)))) {
|
||||
case 0: {
|
||||
expected.is_err = false;
|
||||
|
||||
expected.val.ok = *((int64_t*) (ptr + 8));
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
expected.is_err = true;
|
||||
|
||||
expected.val.err = (int32_t) (*((uint8_t*) (ptr + 8)));
|
||||
break;
|
||||
}
|
||||
}*ret0 = expected.val.ok;
|
||||
return expected.is_err ? expected.val.err : -1;
|
||||
}
|
||||
__attribute__((import_module("outbound-redis"), import_name("smembers")))
|
||||
void __wasm_import_outbound_redis_smembers(int32_t, int32_t, int32_t, int32_t, int32_t);
|
||||
outbound_redis_error_t outbound_redis_smembers(outbound_redis_string_t *address, outbound_redis_string_t *key, outbound_redis_list_string_t *ret0) {
|
||||
int32_t ptr = (int32_t) &RET_AREA;
|
||||
__wasm_import_outbound_redis_smembers((int32_t) (*address).ptr, (int32_t) (*address).len, (int32_t) (*key).ptr, (int32_t) (*key).len, ptr);
|
||||
outbound_redis_expected_list_string_error_t expected;
|
||||
switch ((int32_t) (*((uint8_t*) (ptr + 0)))) {
|
||||
case 0: {
|
||||
expected.is_err = false;
|
||||
|
||||
expected.val.ok = (outbound_redis_list_string_t) { (outbound_redis_string_t*)(*((int32_t*) (ptr + 4))), (size_t)(*((int32_t*) (ptr + 8))) };
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
expected.is_err = true;
|
||||
|
||||
expected.val.err = (int32_t) (*((uint8_t*) (ptr + 4)));
|
||||
break;
|
||||
}
|
||||
}*ret0 = expected.val.ok;
|
||||
return expected.is_err ? expected.val.err : -1;
|
||||
}
|
||||
__attribute__((import_module("outbound-redis"), import_name("srem")))
|
||||
void __wasm_import_outbound_redis_srem(int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t);
|
||||
outbound_redis_error_t outbound_redis_srem(outbound_redis_string_t *address, outbound_redis_string_t *key, outbound_redis_list_string_t *values, int64_t *ret0) {
|
||||
int32_t ptr = (int32_t) &RET_AREA;
|
||||
__wasm_import_outbound_redis_srem((int32_t) (*address).ptr, (int32_t) (*address).len, (int32_t) (*key).ptr, (int32_t) (*key).len, (int32_t) (*values).ptr, (int32_t) (*values).len, ptr);
|
||||
outbound_redis_expected_s64_error_t expected;
|
||||
switch ((int32_t) (*((uint8_t*) (ptr + 0)))) {
|
||||
case 0: {
|
||||
expected.is_err = false;
|
||||
|
||||
expected.val.ok = *((int64_t*) (ptr + 8));
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
expected.is_err = true;
|
||||
|
||||
expected.val.err = (int32_t) (*((uint8_t*) (ptr + 8)));
|
||||
break;
|
||||
}
|
||||
}*ret0 = expected.val.ok;
|
||||
return expected.is_err ? expected.val.err : -1;
|
||||
}
|
||||
__attribute__((import_module("outbound-redis"), import_name("execute")))
|
||||
void __wasm_import_outbound_redis_execute(int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t);
|
||||
outbound_redis_error_t outbound_redis_execute(outbound_redis_string_t *address, outbound_redis_string_t *command, outbound_redis_list_redis_parameter_t *arguments, outbound_redis_list_redis_result_t *ret0) {
|
||||
int32_t ptr = (int32_t) &RET_AREA;
|
||||
__wasm_import_outbound_redis_execute((int32_t) (*address).ptr, (int32_t) (*address).len, (int32_t) (*command).ptr, (int32_t) (*command).len, (int32_t) (*arguments).ptr, (int32_t) (*arguments).len, ptr);
|
||||
outbound_redis_expected_list_redis_result_error_t expected;
|
||||
switch ((int32_t) (*((uint8_t*) (ptr + 0)))) {
|
||||
case 0: {
|
||||
expected.is_err = false;
|
||||
|
||||
expected.val.ok = (outbound_redis_list_redis_result_t) { (outbound_redis_redis_result_t*)(*((int32_t*) (ptr + 4))), (size_t)(*((int32_t*) (ptr + 8))) };
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
expected.is_err = true;
|
||||
|
||||
expected.val.err = (int32_t) (*((uint8_t*) (ptr + 4)));
|
||||
break;
|
||||
}
|
||||
}*ret0 = expected.val.ok;
|
||||
return expected.is_err ? expected.val.err : -1;
|
||||
}
|
||||
|
|
|
@ -24,16 +24,53 @@ extern "C"
|
|||
size_t len;
|
||||
} outbound_redis_payload_t;
|
||||
void outbound_redis_payload_free(outbound_redis_payload_t *ptr);
|
||||
typedef struct {
|
||||
uint8_t tag;
|
||||
union {
|
||||
int64_t int64;
|
||||
outbound_redis_payload_t binary;
|
||||
} val;
|
||||
} outbound_redis_redis_parameter_t;
|
||||
#define OUTBOUND_REDIS_REDIS_PARAMETER_INT64 0
|
||||
#define OUTBOUND_REDIS_REDIS_PARAMETER_BINARY 1
|
||||
void outbound_redis_redis_parameter_free(outbound_redis_redis_parameter_t *ptr);
|
||||
typedef struct {
|
||||
uint8_t tag;
|
||||
union {
|
||||
outbound_redis_string_t status;
|
||||
int64_t int64;
|
||||
outbound_redis_payload_t binary;
|
||||
} val;
|
||||
} outbound_redis_redis_result_t;
|
||||
#define OUTBOUND_REDIS_REDIS_RESULT_NIL 0
|
||||
#define OUTBOUND_REDIS_REDIS_RESULT_STATUS 1
|
||||
#define OUTBOUND_REDIS_REDIS_RESULT_INT64 2
|
||||
#define OUTBOUND_REDIS_REDIS_RESULT_BINARY 3
|
||||
void outbound_redis_redis_result_free(outbound_redis_redis_result_t *ptr);
|
||||
typedef struct {
|
||||
outbound_redis_string_t *ptr;
|
||||
size_t len;
|
||||
} outbound_redis_list_string_t;
|
||||
void outbound_redis_list_string_free(outbound_redis_list_string_t *ptr);
|
||||
typedef struct {
|
||||
outbound_redis_redis_parameter_t *ptr;
|
||||
size_t len;
|
||||
} outbound_redis_list_redis_parameter_t;
|
||||
void outbound_redis_list_redis_parameter_free(outbound_redis_list_redis_parameter_t *ptr);
|
||||
typedef struct {
|
||||
outbound_redis_redis_result_t *ptr;
|
||||
size_t len;
|
||||
} outbound_redis_list_redis_result_t;
|
||||
void outbound_redis_list_redis_result_free(outbound_redis_list_redis_result_t *ptr);
|
||||
outbound_redis_error_t outbound_redis_publish(outbound_redis_string_t *address, outbound_redis_string_t *channel, outbound_redis_payload_t *payload);
|
||||
outbound_redis_error_t outbound_redis_get(outbound_redis_string_t *address, outbound_redis_string_t *key, outbound_redis_payload_t *ret0);
|
||||
outbound_redis_error_t outbound_redis_set(outbound_redis_string_t *address, outbound_redis_string_t *key, outbound_redis_payload_t *value);
|
||||
outbound_redis_error_t outbound_redis_incr(outbound_redis_string_t *address, outbound_redis_string_t *key, int64_t *ret0);
|
||||
outbound_redis_error_t outbound_redis_del(outbound_redis_string_t *address, outbound_redis_list_string_t *keys, int64_t *ret0);
|
||||
outbound_redis_error_t outbound_redis_sadd(outbound_redis_string_t *address, outbound_redis_string_t *key, outbound_redis_list_string_t *values, int64_t *ret0);
|
||||
outbound_redis_error_t outbound_redis_smembers(outbound_redis_string_t *address, outbound_redis_string_t *key, outbound_redis_list_string_t *ret0);
|
||||
outbound_redis_error_t outbound_redis_srem(outbound_redis_string_t *address, outbound_redis_string_t *key, outbound_redis_list_string_t *values, int64_t *ret0);
|
||||
outbound_redis_error_t outbound_redis_execute(outbound_redis_string_t *address, outbound_redis_string_t *command, outbound_redis_list_redis_parameter_t *arguments, outbound_redis_list_redis_result_t *ret0);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -49,3 +49,27 @@ func Incr(addr, key string) (int64, error) {
|
|||
func Del(addr string, keys []string) (int64, error) {
|
||||
return del(addr, keys)
|
||||
}
|
||||
|
||||
// Adds the specified values to the set for the specified key, creating it if it
|
||||
// does not already exist.
|
||||
func Sadd(addr string, key string, values []string) (int64, error) {
|
||||
return sadd(addr, key, values)
|
||||
}
|
||||
|
||||
// Get the elements of the set for the specified key.
|
||||
func Smembers(addr string, key string) ([]string, error) {
|
||||
return smembers(addr, key)
|
||||
}
|
||||
|
||||
// Removes the specified elements from the set for the specified key. This has
|
||||
// no effect if the key does not exist.
|
||||
func Srem(addr string, key string, values []string) (int64, error) {
|
||||
return srem(addr, key, values)
|
||||
}
|
||||
|
||||
// Run the specified Redis command with the specified arguments, returning zero
|
||||
// or more results. This is a general-purpose function which should work with
|
||||
// any Redis command.
|
||||
func Execute(addr string, command string, arguments []RedisParameter) ([]RedisResult, error) {
|
||||
return execute(addr, command, arguments)
|
||||
}
|
||||
|
|
|
@ -26,9 +26,47 @@ size_t align
|
|||
return;
|
||||
free(ptr);
|
||||
}
|
||||
#include <string.h>
|
||||
|
||||
void spin_redis_string_set(spin_redis_string_t *ret, const char *s) {
|
||||
ret->ptr = (char*) s;
|
||||
ret->len = strlen(s);
|
||||
}
|
||||
|
||||
void spin_redis_string_dup(spin_redis_string_t *ret, const char *s) {
|
||||
ret->len = strlen(s);
|
||||
ret->ptr = canonical_abi_realloc(NULL, 0, 1, ret->len);
|
||||
memcpy(ret->ptr, s, ret->len);
|
||||
}
|
||||
|
||||
void spin_redis_string_free(spin_redis_string_t *ret) {
|
||||
canonical_abi_free(ret->ptr, ret->len, 1);
|
||||
ret->ptr = NULL;
|
||||
ret->len = 0;
|
||||
}
|
||||
void spin_redis_payload_free(spin_redis_payload_t *ptr) {
|
||||
canonical_abi_free(ptr->ptr, ptr->len * 1, 1);
|
||||
}
|
||||
void spin_redis_redis_parameter_free(spin_redis_redis_parameter_t *ptr) {
|
||||
switch ((int32_t) ptr->tag) {
|
||||
case 1: {
|
||||
spin_redis_payload_free(&ptr->val.binary);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
void spin_redis_redis_result_free(spin_redis_redis_result_t *ptr) {
|
||||
switch ((int32_t) ptr->tag) {
|
||||
case 1: {
|
||||
spin_redis_string_free(&ptr->val.status);
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
spin_redis_payload_free(&ptr->val.binary);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
typedef struct {
|
||||
bool is_err;
|
||||
union {
|
||||
|
|
|
@ -7,6 +7,15 @@ extern "C"
|
|||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct {
|
||||
char *ptr;
|
||||
size_t len;
|
||||
} spin_redis_string_t;
|
||||
|
||||
void spin_redis_string_set(spin_redis_string_t *ret, const char *s);
|
||||
void spin_redis_string_dup(spin_redis_string_t *ret, const char *s);
|
||||
void spin_redis_string_free(spin_redis_string_t *ret);
|
||||
typedef uint8_t spin_redis_error_t;
|
||||
#define SPIN_REDIS_ERROR_SUCCESS 0
|
||||
#define SPIN_REDIS_ERROR_ERROR 1
|
||||
|
@ -15,6 +24,29 @@ extern "C"
|
|||
size_t len;
|
||||
} spin_redis_payload_t;
|
||||
void spin_redis_payload_free(spin_redis_payload_t *ptr);
|
||||
typedef struct {
|
||||
uint8_t tag;
|
||||
union {
|
||||
int64_t int64;
|
||||
spin_redis_payload_t binary;
|
||||
} val;
|
||||
} spin_redis_redis_parameter_t;
|
||||
#define SPIN_REDIS_REDIS_PARAMETER_INT64 0
|
||||
#define SPIN_REDIS_REDIS_PARAMETER_BINARY 1
|
||||
void spin_redis_redis_parameter_free(spin_redis_redis_parameter_t *ptr);
|
||||
typedef struct {
|
||||
uint8_t tag;
|
||||
union {
|
||||
spin_redis_string_t status;
|
||||
int64_t int64;
|
||||
spin_redis_payload_t binary;
|
||||
} val;
|
||||
} spin_redis_redis_result_t;
|
||||
#define SPIN_REDIS_REDIS_RESULT_NIL 0
|
||||
#define SPIN_REDIS_REDIS_RESULT_STATUS 1
|
||||
#define SPIN_REDIS_REDIS_RESULT_INT64 2
|
||||
#define SPIN_REDIS_REDIS_RESULT_BINARY 3
|
||||
void spin_redis_redis_result_free(spin_redis_redis_result_t *ptr);
|
||||
spin_redis_error_t spin_redis_handle_redis_message(spin_redis_payload_t *message);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -12,4 +12,4 @@ allowed_http_hosts = []
|
|||
[component.trigger]
|
||||
route = "{{http-path}}"
|
||||
[component.build]
|
||||
command = "tinygo build -wasm-abi=generic -target=wasi -gc=leaking -no-debug -o main.wasm main.go"
|
||||
command = "tinygo build -target=wasi -gc=leaking -no-debug -o main.wasm main.go"
|
||||
|
|
|
@ -5,5 +5,5 @@ allowed_http_hosts = []
|
|||
[component.trigger]
|
||||
route = "{{http-path}}"
|
||||
[component.build]
|
||||
command = "tinygo build -wasm-abi=generic -target=wasi -gc=leaking -no-debug -o main.wasm main.go"
|
||||
command = "tinygo build -target=wasi -gc=leaking -no-debug -o main.wasm main.go"
|
||||
workdir = "{{ output-path }}"
|
||||
|
|
|
@ -12,4 +12,4 @@ allowed_http_hosts = []
|
|||
[component.trigger]
|
||||
channel = "{{redis-channel}}"
|
||||
[component.build]
|
||||
command = "tinygo build -wasm-abi=generic -target=wasi -gc=leaking -no-debug -o main.wasm main.go"
|
||||
command = "tinygo build -target=wasi -gc=leaking -no-debug -o main.wasm main.go"
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
.PHONY: build
|
||||
build:
|
||||
tinygo build -wasm-abi=generic -target=wasi -gc=leaking -o main.wasm main.go
|
||||
tinygo build -target=wasi -gc=leaking -o main.wasm main.go
|
||||
|
|
Loading…
Reference in New Issue