Libraries
Given the library
declaration:
library fuchsia.examples;
Bindings code is generated into a examples
Go package, which is obtained by
taking the last component of the FIDL library name.
The package can be imported using the path:
import "fidl/fuchsia/examples"
Constants
Constants are generated as a const
block. For example, the
following constants:
const BOARD_SIZE uint8 = 9;
const NAME string = "Tic-Tac-Toe";
Are generated as:
const (
BoardSize uint8 = 9
Name string = "Tic-Tac-Toe"
)
The correspondence between FIDL primitive types and Go types is outlined in built-in types.
Fields
This section describes how the FIDL toolchain converts FIDL types to native types in Go. These types can appear as members in an aggregate type or as parameters to a protocol method.
Built-in types
The FIDL types are converted to Go types based on the following table.
FIDL Type | Go Type |
---|---|
bool |
bool |
int8 |
int8 |
int16 |
int16 |
int32 |
int32 |
int64 |
int64 |
uint8 |
uint8 |
uint16 |
uint16 |
uint32 |
uint32 |
uint64 |
uint64 |
float32 |
float32 |
float64 |
float64 |
array<T, N> |
[N]T |
vector<T>:N |
[]T |
vector<T>:N? |
*[]T |
string |
string |
string:optional |
*string |
server_end:P |
The generated server end type PInterfaceRequest , see Protocols |
client_end:P |
The generated client end type PInterface , see Protocols |
zx.Handle:S ,zx.Handle:<S, optional> |
The equivalent handle type is used if it is supported by the Go runtime (e.g. zx.VMO , zx.Channel , and zx.Event ). Otherwise, zx.Handle is used |
zx.Handle ,zx.Handle:optional |
zx.Handle |
User defined types
In Go, a user defined type (bits, enum, constant, struct, union, or table) is
referred to using the generated type (see Type Definitions).
The nullable version of a user defined type T
is referred to using a pointer
to the generated type: *T
.
Type definitions
Note that in this section, the example generated Go code is not a representation of the exact code that is generated by FIDL. For example, generated structs may include non-exported fields that cannot be inspected with reflection.
Bits
Given the bits definition:
const BOARD_SIZE uint8 = 9;
const NAME string = "Tic-Tac-Toe";
FIDL generates a type alias for the underlying type (or uint32
if not
specified) and constants for each bits member:
type FileMode uint16
const (
FileModeRead FileMode = 1
FileModeWrite FileMode = 2
FileModeExecute FileMode = 4
FileMode_Mask FileMode = 7
)
The FileMode_Mask
value is a bitmask that contains every bits member defined
in the FIDL schema.
In addition, it provides the following methods for FileMode
:
func (x FileMode) String() string
: Returns a human readable string of the bits.func (x FileMode) GetUnknownBits() uint64
: Returns a value that contains only the unknown members from this bits value, as auint64
. Always returns 0 for strict bits.func (x FileMode) HasUnknownBits() bool
: Returns whether this value contains any unknown bits. Always returnsfalse
for strict bits.func (x FileMode) InvertBits() FileMode
: Inverts all known bits. All unknown bits are set to false.func (x FileMode) ClearBits(mask FileMode) FileMode
: Modifies the bitfield such that all bits set in the mask are unset.func (x FileMode) HasBits(mask FileMode) bool
: Validates that all flipped bits in the mask are set.
Example usage:
func ExampleFileMode() {
fmt.Println(examples.FileModeRead.String())
fmt.Println(examples.FileModeWrite | examples.FileModeExecute)
// Output:
// Read
// Write|Execute
}
Enums
Given the enum definition:
type LocationType = strict enum {
MUSEUM = 1;
AIRPORT = 2;
RESTAURANT = 3;
};
FIDL generates a type alias for the underlying type (or uint32
if not
specified) and constants for each enum member:
type LocationType uint32
const (
LocationTypeMuseum LocationType = 1
LocationTypeAirport LocationType = 2
LocationTypeRestaurant LocationType = 3
)
If LocationType
is flexible, it will have an unknown
placeholder member as well:
LocationType_Unknown LocationType = 0x7fffffff
If the enum has a member tagged with the [Unknown]
attribute,
the generated unknown variable will have the same value as the tagged unknown
member.
LocationType
provides the following methods:
func (x LocationType) IsUnknown() bool
: Returns whether this enum value is unknown. Always returnsfalse
for strict enums.func (x LocationType) String() string
: Returns a human readable string of the enum.
Example usage:
func ExampleLocationType() {
fmt.Println(examples.LocationTypeMuseum.String())
// Output: Museum
}
Structs
Given the struct declaration:
type Color = struct {
id uint32;
@allow_deprecated_struct_defaults
name string:MAX_STRING_LENGTH = "red";
};
The FIDL toolchain generates a Color
struct with matching fields:
type Color struct {
Id uint32
Name string
}
The Go bindings do not currently support default values on struct fields.
Example usage:
func ExampleColor() {
red := examples.Color{Id: 1, Name: "ruby"}
fmt.Println(red.Id)
fmt.Println(red.Name)
// Output:
// 1
// ruby
}
Unions
Given the union definition:
type JsonValue = strict union {
1: int_value int32;
2: string_value string:MAX_STRING_LENGTH;
};
FIDL generates an alias and associated constants representing the union tag:
type I_jsonValueTag uint64
const (
JsonValueIntValue = 2
JsonValueStringValue = 3
)
As well as a JsonValue
struct with fields for the tag and each
variant of the union:
type JsonValue struct {
I_jsonValueTag
IntValue int32
StringValue string
}
JsonValue
provides the following methods:
func (_m *JsonValue) Which() I_jsonValueTag
: Returns the union tag.func (_m *JsonValue) SetIntValue(intValue int32)
andfunc (_m *JsonValue) SetStringValue(stringValue string)
: Sets the union to contain a specific variant, updating the tag accordingly.
If JsonValue
is flexible, it will have the following
additional methods:
func (_m *JsonValue) GetUnknownData() fidl.UnknownData
: Returns the raw bytes and handles of the unknown data. The slice of handles is returned in traversal order, and is guaranteed to be empty if the union is a resource type.
The FIDL toolchain also generates factory functions for constructing instances
of JsonValue
:
func JsonValueWithIntValue(intValue int32) JsonValue
func JsonValueWithStringValue(stringValue string) JsonValue
Example usage:
func ExampleJsonValue() {
val := examples.JsonValueWithStringValue("hi")
fmt.Println(val.Which() == examples.JsonValueStringValue)
fmt.Println(val.StringValue)
val.SetIntValue(1)
fmt.Println(val.Which() == examples.JsonValueIntValue)
fmt.Println(val.IntValue)
// Output:
// true
// hi
// true
// 1
}
Flexible unions and unknown variants
Flexible unions have an extra variant in the generated tag class:
const (
JsonValue_unknownData = 0
// other tags omitted...
)
When a FIDL message containing a union with an unknown variant is decoded into
JsonValue
, .Which()
will return JsonValue_unknownData
.
Encoding a union with an unknown variant writes the unknown data and the original ordinal back onto the wire.
Strict unions fail when decoding an unknown variant. Flexible unions that are value types fail when decoding an unknown variant with handles.
Tables
Given the following table definition:
type User = table {
1: age uint8;
2: name string:MAX_STRING_LENGTH;
};
The FIDL toolchain generates a User
struct that with presence fields for each
field:
type User struct {
Age uint8
AgePresent bool
Name string
NamePresent bool
}
User
provides the following methods:
func (u *User) HasAge() bool
andfunc (u *User) HasName() bool
: Checks for the presence of a field.func (u *User) SetAge(age uint8)
andfunc (u *User) SetName(name string)
: Field setters.func (u *User) GetAge() uint8
andfunc (u *User) GetName() string
: Field getters.func (u *User) GetAgeWithDefault(_default uint8) uint8
andfunc (u *User) GetNameWithDefault(_default string) string
: Field getters that return the specified default value if not present.func (u *User) ClearAge()
andfunc (u *User) ClearName()
: Clears the presence of a field.func (u *User) HasUnknownData() bool
: Checks for the presence of any unknown fields.func (u *User) GetUnknownData() map[uint64]fidl.UnknownData
: Returns a map from ordinal to bytes and handles for any unknown fields. The list of handles is returned in traversal order, and is guaranteed to be empty if the table is a value type.
Example usage:
func ExampleUser() {
var user examples.User
fmt.Println(user.HasAge(), user.HasName())
user.SetAge(30)
user.SetName("John")
fmt.Println(user.GetAge(), user.GetName())
user.ClearAge()
user.ClearName()
fmt.Println(user.HasAge(), user.HasName())
fmt.Println(user.GetNameWithDefault("Unknown"))
// Output:
// false false
// 30 John
// false false
// Unknown
}
Inline layouts
The generated Go code uses the the name reserved by fidlc
for
inline layouts.
Protocols
Given the protocol:
closed protocol TicTacToe {
strict StartGame(struct {
start_first bool;
});
strict MakeMove(struct {
row uint8;
col uint8;
}) -> (struct {
success bool;
new_state box<GameState>;
});
strict -> OnOpponentMove(struct {
new_state GameState;
});
};
FIDL generates a TicTacToeWithCtx
interface, which is used by clients when
proxying calls to the server, and by the server for implementing the protocol:
type TicTacToeWithCtx interface {
StartGame(ctx_ fidl.Context, startFirst bool) error
MakeMove(ctx_ fidl.Context, row uint8, col uint8) (bool, *GameState, error)
}
Each method will take a Context
as the first argument, followed by the request
parameters. Fire and forget methods return error
, and two way methods return
the response parameters followed by an error
.
The entry point to interacting with the TicTacToe
protocol is the following
function:
func NewTicTacToeWithCtxInterfaceRequest() (TicTacToeWithCtxInterfaceRequest, *TicTacToeWithCtxInterface, error)
This function creates a channel and returns a TicTacToeWithCtxInterfaceRequest
bound to one end of the channel, representing the server end, and a
TicTacToeWithCtxInterface
, bound to the other end, representing the client
end. These are explained in the client and server
sections.
Client
The client end of a channel used to communicate over the TicTacToe
protocol
is the TicTacToeWithCtxInterface
. It implements the TicTacToeWithCtx
interface described in Protocols as well as methods for handling
events. Note that in this implementation, two way method calls are
synchronous and block until the response is received.
An example of a Go FIDL client can be found in //examples/fidl/go/client.
Server
Implementing a server for this FIDL protocol involves providing a concrete
implementation of the TicTacToeWithCtx
interface.
The bindings generate a TicTacToeWithCtxInterfaceRequest
type, used to
represent the server end of the channel communicating over the TicTacToe
protocol. It provides the following methods:
func (c EchoWithCtxInterfaceRequest) ToChannel() zx.Channel
: Convert the interface request back to an untyped channel.
An example of a Go FIDL server can be found in //examples/fidl/go/server.
Events
Client
TicTacToeWithCtxInterface
provides methods for handling events:
func (p *TicTacToeWithCtxInterface) ExpectOnOpponentMove(ctx_ fidl.Context) (GameState, error)
: Event handler forOnOppponentMove
, which takes aContext
and returns the event parameters.
Calling any of the event handler methods will read the next buffered event or block until one is received - the caller is expected to drain the event buffer promptly to avoid unbounded buffering in the FIDL bindings. If the next event matches the method that was called, its parameters are returned. Otherwise, an error is returned. It is up to the client to ensure that the order of received events matches the order of the handled events.
Server
Servers can send events by using the TicTacToeEventProxy
, which provides
methods for each event in the protocol:
func (p *TicTacToeEventProxy) OnOpponentMove(newState GameState) error
: Send anOnOpponentMove
event.
Creating a TicTacToeEventProxy
requires access to a channel to the client.
The Go server example shows how to obtain an
EventProxy
on the server side.
Results
The Go bindings do not have any special handling for methods with error types.
Given the method with an error type:
protocol TicTacToe {
MakeMove(struct {
row uint8;
col uint8;
}) -> (struct {
new_state GameState;
}) error MoveError;
};
The method signature for MakeMove
on the TicTacToeWithCtx
interface is:
MakeMove(ctx_ fidl.Context, row uint8, col uint8) (TicTacToeMakeMoveResult, error)
TicTacToeMakeMoveResult
is generated as a union with two variants:
Err
, which is a MoveError
, and Response
, which is a
TicTacToeMakeMoveResponse
.
TicTacToeMakeMoveResponse
is generated as a struct with fields
corresponding to a successful response's parameters. In this case it contains a
single NewState
field of type GameState
.
Protocol composition
FIDL does not have a concept of inheritance, and generates full code as described above for all composed protocols. In other words, the code generated for
protocol A {
Foo();
};
protocol B {
compose A;
Bar();
};
Provides the same API as the code generated for:
protocol A {
Foo();
};
protocol B {
Foo();
Bar();
};
The generated code is identical except for the method ordinals.
Protocol and method attributes
Transitional
In order to support the @transitional
attribute in Go, FIDL generates a
TicTacToeWithCtxTransitionalBase
type, which provides default implementations
for every method marked as @transitional
. Server implementations that embed
TicTacToeWithCtxTransitionalBase
will continue to build a new transitional
method is added.
Discoverable
When marked as @discoverable
, the generated InterfaceRequest
type (in this
example TicTacToeWithCtxInterfaceRequest
) implements fidl.ServiceRequest
,
which allows the server end to be used in service discovery.
In addition, FIDL generates a TicTacToeName
constant that contains the
protocol name.