Attributes
By defining the interface that corresponds to the WIT in C# and giving the appropriate attributes, the Source Generator that comes with WaaS automatically generates convenient code for binding.
If you use wit2waas
, attributes are automatically applied, so manual attribute assignment is not required.
Please refer to Use Generated Code.
Declare an interface
To generate bindings corresponding to WIT interfaces and worlds, declare a partial
interface
in C# and apply the [ComponentInterface]
attribute.
using WaaS.ComponentModel.Binding;
[ComponentInterface(@"env")]
public partial interface IEnv
{
/* Define the interface members here */
}
For types and functions included in this interface
, define them as members of this interface
. Depending on the type of member to be defined, you need to apply the corresponding attribute.
Declare a function
To define a function included in the interface, define a method as a member of the interface and apply the [ComponentApi]
attribute.
using WaaS.ComponentModel.Binding;
using System.Threading.Tasks;
[ComponentInterface(@"env")]
public partial interface IEnv
{
[ComponentApi(@"show-message")]
ValueTask ShowMessage(string @message);
}
- The argument of
[ComponentApi]
must be the function name of WIT. - The return type can be an awaitable type such as ValueTask.
- It is awaited by the caller and the result is obtained.
- For other types that can be used as arguments or return values, refer to Types that can be used in functions.
When calling an awaitable
function, ExecutionContext.Invoke()
cannot be used.
Use ExecutionContext.InvokeAsync()
.
Types that can be used in a function
Component Model Type | C# Type |
---|---|
string | string |
bool | bool |
s8 | sbyte |
u8 | byte |
s16 | short |
u16 | ushort |
s32 | int |
u32 | uint |
s64 | long |
u64 | ulong |
f32 | float |
f64 | double |
char | WaaS.ComponentModel.Binding.ComponentChar 1 |
record | → Defining a record |
variant | → Defining a variant |
list<T> | System.ReadOnlyMemory<T> |
tuple<...> | System.ValueTuple<...> or System.Tuple<...> |
flags | → Defining flags |
enum | → Defining an enum |
options<T> | → Using options |
result<T, E> | WaaS.ComponentModel.Binding.Result<TOk, TError> |
own<T> | → Defining resource types |
borrow<T> | → Defining resource types |
Defining a record
To define a record, declare a record
in C# and apply the [ComponentRecord]
attribute.
using WaaS.ComponentModel.Binding;
[ComponentInterface(@"env")]
public partial interface IEnv
{
[ComponentRecord]
public readonly partial struct Message
{
[ComponentField]
public (string, Sprite?) Speaker { get; private init; }
[ComponentField]
public string Text { get; private init; }
[ComponentField]
public MessageAttributes Attributes { get; private init; }
}
}
- Define a
partial
class
orstruct
as a member of theinterface
with[ComponentInterface]
applied, and apply the[ComponentRecord]
attribute. - Apply the
[ComponentField]
attribute to the property. - Apply the
init
orset
accessor to the property. Accessibility doesn't matter. - The property type uses the corresponding C# type for the Component Model type. The available types are the same as Types that can be used in a function.
Defining a variant
To define a variant, declare a variant
in C# and apply the [ComponentVariant]
attribute.
#enable nullable
using WaaS.ComponentModel.Binding;
[ComponentInterface(@"env")]
public partial interface IEnv
{
[ComponentVariant]
public readonly partial struct Sprite
{
[ComponentCase]
public MyGame.MySequencer.IEnv.WellKnownSprites? WellKnown { get; private init; }
[ComponentCase]
public string? Addressable { get; private init; }
}
}
- Defne a
partial
class
orstruct
as a member of theinterface
with[ComponentInterface]
applied, and apply the[ComponentVariant]
attribute. - Apply the
[ComponentCase]
attribute to the property. - Apply the
init
orset
accessor to the property. Accessibility doesn't matter. - The property type uses the corresponding C# type for the Component Model type. The available types are the same as Types that can be used in a function.
- In addition, it is recommended to make the property type
nullable
.
- In addition, it is recommended to make the property type
Generated members
Members are generated to access the variant information.
// <auto-generated />
partial interface IEnv
{
partial struct Sprite
{
public VariantCase Case { get; private init; }
public enum VariantCase
{
WellKnown,
Addressable,
}
}
}
By using the Case
property, you can get the type of the variant.
return sprite.Case switch
{
IEnv.Sprite.VariantCase.WellKnown => GetWellKnownSprite(sprite.WellKnown),
IEnv.Sprite.VariantCase.Addressable => GetAddressableSprite(sprite.Addressable),
_ => throw new IndexOutOfRangeException()
};
Defining flags
To define flags, declare an enum
in C# and apply the [ComponentFlags]
attribute.
using WaaS.ComponentModel.Binding;
using System;
[ComponentInterface(@"env")]
public partial interface IEnv
{
[Flags]
public enum MessageAttributes : byte
{
Fast = 1 << 0,
Large = 1 << 1,
Slow = 1 << 2,
Auto = 1 << 3,
}
}
- Define an
enum
as a member of theinterface
with[ComponentInterface]
applied, and apply theSystem.Flags
attribute. - Use an integer type from
byte
touint
as the underlying type depending on the number of flags.- Use
byte
if there are 8 or fewer flags. - Use
ushort
if there are 16 or fewer flags. - Use
uint
for other cases.
- Use
With WaaS, you cannot define a flags
type with more than 32 flags.
Defining an enum
To define an enum, declare an enum
in C#.
using WaaS.ComponentModel.Binding;
using System;
[ComponentInterface(@"env")]
public partial interface IEnv
{
public enum WellKnownSprites
{
Unknown,
Hero,
Rival,
Professor,
}
}
- Define an
enum
as a member of theinterface
with[ComponentInterface]
applied. - The
System.Flags
attribute cannot be applied.
In the Component Model enum
, you cannot specify the values of the enumeration constants.
If you specify the values of the enumeration constants on the C# side, they are sorted in ascending order as unsigned integer representations, and indexes are assigned in order.
public enum WellKnownSprites : uint
{
Unknown = 100, // '1' in Component Model
Hero = 200, // '2' in Component Model
Rival = 0, // '0' in Component Model
Professor = 1000, // '3' in Component Model
}
Using options
To represent option<T>
in Component Model, use WaaS.ComponentModel.Binding.Option<T>
.
However, T?
can also be used in the following cases.
- When the type
T
is a value type. - When it is used directly as the type of a member of a record or variant.
- Except when used as a type argument, such as an element of a tuple or list.
Defining resource types
When a resource type is defined in an interface with the [ComponentInterface]
attribute, the following members are required in the C# interface.
using WaaS.ComponentModel.Binding;
using WaaS.ComponentModel.Runtime;
using System;
[ComponentInterface(@"env")]
public partial interface IEnv
{
[ComponentResource(@"some-resource-name")]
public partial interface ISomeResourceImpl : IResourceImpl
{
/* ... */
}
}
- Define a
partial
interface
as a member of theinterface
with the[ComponentInterface]
attribute applied. - The interface inherits
IResourceImpl
.
When using a resource type as a parameter or return value, use Owned<ISomeResourceImpl>
to own it, and Borrowed<ISomeResourceImpl>
to borrow it.
When Owned<ISomeResourceImpl>
is passed to C# code as an argument, you must handle ownership properly.
Defining resource type members
public partial interface ISomeResourceImpl : IResourceImpl
{
[ComponentApi("[constructor]some-resource-name")]
ValueTask<Owned<ISomeResourceImpl>> SomeResource(/* ... */);
[ComponentApi("[method]some-resource-name.some-method")]
ValueTask</* return type */> SomeMethod(Borrowed<ISomeResourceImpl> self, /* ... */);
[ComponentApi("[static]some-resource-name.some-static-method")]
ValueTask</* return type */> SomeStaticMethod(/* ... */);
}
- Define member methods with the
[ComponentApi]
attribute applied to the resource type interface. The basic rules are the same as usual, but differ in the following points.- Specify the following names in the argument of
[ComponentApi]
.- Constructor:
[constructor]resource name
- Method:
[method]resource name.method name
- Static method:
[static]resource name.method name
- Constructor:
- For the constructor, the return type is
Owned<resource implementation type>
or an awaitable type that results in it. - For instance methods, specify
Borrowed<resource implementation type>
as the first argument. - For details, refer to the WIT specification.
- Specify the following names in the argument of
Footnotes
-
Component Model's character type is a Unicode Scalar Value and cannot be used with C#'s
char
. ↩