Using Generated Code
Exposing Interface Implementation to Components
Use the static method CreateWaaSInstance()
defined as a member of the interface.
// <auto-generated />
partial interface IEnv
{
public static IInstance CreateWaaSInstance(IEnv target);
}
CreateWaaSInstance()
is a method that wraps an interface implemented in C# and converts it to IInstance
.
By converting it to IInstance
, it can be imported when instantiating a component.
It can be used when you want to provide the necessary implementation to the component from the C# side.
var component = LoadComponent();
var instance = component.Instantiate(null, new Dictionary<string, ISortedExportable>()
{
{ "my-game:my-sequencer/env", IEnv.CreateWaaSInstance(new EnvImpl()) }
});
public class EnvImpl : IEnv { /* Implement here */ }
Handling Ownership
When Owned<T>
is passed to C# code as an argument, you need to do one of the following:
- Drop ownership by calling
Owned<T>.Dispose()
- Transfer ownership by passing
Owned<T>
to another function
If you do not do this, resources will leak.
Linking Resources to C# Objects
If you want to provide the implementation of a resource type on the C# side, you can link the resource to a C# object.
To link a resource to a C# object, inherit HostResourceTypeBase<T>
in the implementation class of the resource type.
You can convert the resource type and C# object using the Wrap()
or Unwrap()
method.
using WaaS.ComponentModel.Binding;
using WaaS.ComponentModel.Runtime;
using System;
using System.IO;
[ComponentInterface(@"env")]
public partial interface IEnv
{
[ComponentResource(@"stream")]
public partial interface IStreamResourceImpl : IResourceImpl
{
[ComponentApi("[constructor]stream")]
Owned<IStreamResourceImpl> Create();
[ComponentApi("[method]stream.write-byte")]
void WriteByte(Borrowed<IStreamResourceImpl> self, byte value);
}
}
public class StreamResourceType : HostResourceTypeBase<Stream>, IEnv.IStreamResourceImpl
{
public Owned<IEnv.IStreamResourceImpl> Create()
{
var stream = File.Open("hoge.txt", FileMode.Create, FileAccess.Write);
// Stream -> Owned<IStreamResourceImpl>
var handle = Wrap<IEnv.IStreamResourceImpl>(stream);
return handle;
}
public void WriteByte(Borrowed<IEnv.IStreamResourceImpl> self, byte value)
{
// Borrowed<IStreamResourceImpl> -> Stream
var stream = Unwrap(self);
stream.WriteByte(value);
}
public IResourceType Type => this;
}
public class EnvImpl : IEnv
{
public IEnv.IStreamResourceImpl Stream { get; } = new StreamResourceType();
}
When creating Owned<T>
with Wrap()
, the object will be referenced from the internal table.
By returning Owned<T>
as a return value, the reference will be released when the resource is no longer needed.
Calling Functions exposed by Components
You can use a struct Wrapper
defined as a member of the interface by the Source Generator.
// <auto-generated />
partial interface IEnv
{
public readonly struct Wrapper : IEnv
{
public Wrapper(IInstance instance, ExecutionContext context);
public ValueTask ShowMessage(string @speaker, string @message);
public ValueTask<uint> ShowOptions(ReadOnlyMemory<string> @options)
}
}
Wrapper
is a struct that wraps externally created IInstance
and converts it to IEnv
.
It is assumed that the target instance exports functions that correspond to IEnv
(no automatic check is performed).
It can be used when calling functions exported by components from C#.
var component = await componentAsset.LoadComponentAsync();
var instance = component.Instantiate(null, new Dictionary<string, ISortedExportable>());
using var context = new ExecutionContext();
var wrapper = new IEnv.Wrapper(instance, context);
await wraapper.ShowMessage("Me", "Hello");