summaryrefslogtreecommitdiff
path: root/vendor/codeberg.org/gruf/go-ffmpreg/wasm/instance.go
blob: d2eccd9e93f1a76302276737f6b97544f7148c29 (plain)
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
package wasm

import (
	"context"
	"io"
	"unsafe"

	"github.com/tetratelabs/wazero"
	"github.com/tetratelabs/wazero/api"
	"github.com/tetratelabs/wazero/sys"
)

// CoreFeatures are the WebAssembly Core specification
// features our embedded binaries are compiled with.
const CoreFeatures = api.CoreFeatureSIMD |
	api.CoreFeatureBulkMemoryOperations |
	api.CoreFeatureNonTrappingFloatToIntConversion |
	api.CoreFeatureMutableGlobal |
	api.CoreFeatureReferenceTypes |
	api.CoreFeatureSignExtensionOps

// Args encompasses a common set of
// configuration options often passed to
// wazero.Runtime on module instantiation.
type Args struct {

	// Optional further module configuration function.
	// (e.g. to mount filesystem dir, set env vars, etc).
	Config func(wazero.ModuleConfig) wazero.ModuleConfig

	// Standard FDs.
	Stdin  io.Reader
	Stdout io.Writer
	Stderr io.Writer

	// CLI args.
	Args []string
}

// Run will run given compiled WebAssembly module
// within the given runtime, with given arguments.
// Returns the exit code, or error.
func Run(
	ctx context.Context,
	runtime wazero.Runtime,
	module wazero.CompiledModule,
	args Args,
) (rc uint32, err error) {

	// Prefix arguments with module name.
	cargs := make([]string, len(args.Args)+1)
	cargs[0] = module.Name()
	copy(cargs[1:], args.Args)

	// Prepare new module configuration.
	modcfg := wazero.NewModuleConfig()
	modcfg = modcfg.WithArgs(cargs...)
	modcfg = modcfg.WithStdin(args.Stdin)
	modcfg = modcfg.WithStdout(args.Stdout)
	modcfg = modcfg.WithStderr(args.Stderr)

	if args.Config != nil {
		// Pass through config fn.
		modcfg = args.Config(modcfg)
	}

	// Instantiate the module from precompiled wasm module data.
	mod, err := runtime.InstantiateModule(ctx, module, modcfg)

	if !isNil(mod) {
		// Ensure closed.
		_ = mod.Close(ctx)
	}

	// Try extract exit code.
	switch err := err.(type) {
	case *sys.ExitError:
		return err.ExitCode(), nil
	default:
		return 0, err
	}
}

// isNil will safely check if 'v' is nil without
// dealing with weird Go interface nil bullshit.
func isNil(i interface{}) bool {
	type eface struct{ Type, Data unsafe.Pointer }
	return (*(*eface)(unsafe.Pointer(&i))).Data == nil
}