using System; using System.Collections.Generic; using KitsuneCafe.Sys; using UnityEngine; using Wacs.Core.Runtime; using Wacs.Core.Runtime.Types; namespace KitsuneCafe.Scripting { public class RuntimeInstance { public const string DefaultStartFunction = "main"; public readonly WasmRuntime Runtime; public readonly Runtime Asset; public readonly IDictionary State; public RuntimeInstance(WasmRuntime runtime, Runtime asset, IDictionary state) { Runtime = runtime; Asset = asset; State = state; } public IResult Invoke(FuncAddr addr, InvokerOptions options = null) { var caller = Runtime.CreateInvokerAction(addr, options); try { caller(); return Result.Ok(default); } catch (Exception e) { return Result.Err(e); } } public IResult Invoke(FuncAddr addr, InvokerOptions options = null) { var caller = Runtime.CreateInvokerFunc(addr, options); try { T value = caller(); return Result.Ok(default); } catch (Exception e) { return Result.Err(e); } } public IResult Invoke(BindingPath path, InvokerOptions options = null) { if (Runtime.TryGetExportedFunction(path, out var addr)) { return Invoke(addr, options); } return Result.Err(new ArgumentException($"No such function \"{path}\"")); } public IResult Invoke(BindingPath path, InvokerOptions options = null) { if (Runtime.TryGetExportedFunction(path, out var addr)) { return Invoke(addr, options); } return Result.Err(new ArgumentException($"No such function \"{path}\"")); } public IResult Start(ModuleInstance module, InvokerOptions options = null) { return Invoke(module.StartFunc, options); } public IResult Start(string moduleName, InvokerOptions options = null) { return Start(Runtime.GetModule(moduleName), options); } public IResult Start(Module module, InvokerOptions options = null) { return Start(module.Name, options); } public IResult Start(InvokerOptions options = null) { if (Asset.Modules.Count != 1) { return Result.Err(new ArgumentException("Runtime has more than one module registered. Specify the module to start.")); } return Start(Asset.Modules[0], options); } } [CreateAssetMenu(menuName = KitsuneCafeMenu.Module + "Runtime")] public class Runtime : ScriptableObject { [SerializeField] private RuntimeAttributes attributes = new(); public RuntimeAttributes Attributes => attributes; [SerializeField] private List environments = new(); public List Environments => environments; [SerializeField] private List modules = new(); public List Modules => modules; public RuntimeInstance Instantiate() { var runtime = new WasmRuntime(attributes); var state = BindEnvironments(runtime); RegisterModules(runtime); return new RuntimeInstance(runtime, this, state); } private RuntimeState BindEnvironments(WasmRuntime runtime) { var state = new RuntimeState(); foreach (var env in environments) { env.Bind(runtime, state); } return state; } private void RegisterModules(WasmRuntime runtime) { foreach (var module in modules) { var instance = module.Instantiate(runtime); runtime.RegisterModule(module.Name, instance); } } } }