Go bindings

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:

{%includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/fidl/fuchsia.examples/types.test.fidl" region_tag="consts" %}

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 TypeGo Type
boolbool
int8int8
int16int16
int32int32
int64int64
uint8uint8
uint16uint16
uint32uint32
uint64uint64
float32float32
float64float64
array<T>:N[N]T
vector<T>:N[]T
vector<T>:N?*[]T
stringstring
string?*string
request<P>The generated server end type PInterfaceRequest, see Protocols
PThe generated client end type PInterface, see Protocols
handle:S,handle:S?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
handle,handle?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:

{%includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/fidl/fuchsia.examples/types.test.fidl" region_tag="consts" %}

FIDL generates a type alias for the underyling 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 a uint64. Always returns 0 for strict bits.
  • func (x FileMode) HasUnknownBits() bool: Returns whether this value contains any unknown bits. Always returns false for strict bits.

Example usage:

{%includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/fidl/go/fidl_packages/fidl_test.go" region_tag="bits" %}

Enums

Given the enum definition:

{%includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/fidl/fuchsia.examples/types.test.fidl" region_tag="enums" %}

FIDL generates a type alias for the underyling 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 returns false for strict enums.
  • func (x LocationType) String() string: Returns a human readable string of the enum.

Example usage:

{%includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/fidl/go/fidl_packages/fidl_test.go" region_tag="enums" %}

Structs

Given the struct declaration:

{%includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/fidl/fuchsia.examples/types.test.fidl" region_tag="structs" %}

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:

{%includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/fidl/go/fidl_packages/fidl_test.go" region_tag="structs" %}

Unions

Given the union definition:

{%includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/fidl/fuchsia.examples/types.test.fidl" region_tag="unions" %}

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) and func (_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:

{%includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/fidl/go/fidl_packages/fidl_test.go" region_tag="unions" %}

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:

{%includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/fidl/fuchsia.examples/types.test.fidl" region_tag="tables" %}

The FIDL toolchain generates a User struct that with presence fields for each non-reserved field:

type User struct {
  Age         uint8
  AgePresent  bool
  Name        string
  NamePresent bool
}

User provides the following methods:

  • func (u *User) HasAge() bool and func (u *User) HasName() bool: Checks for the presence of a field.
  • func (u *User) SetAge(age uint8) and func (u *User) SetName(name string): Field setters.
  • func (u *User) GetAge() uint8 and func (u *User) GetName() string: Field getters.
  • func (u *User) GetAgeWithDefault(_default uint8) uint8 and func (u *User) GetNameWithDefault(_default string) string: Field getters that return the specified default value if not present.
  • func (u *User) ClearAge() and func (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:

{%includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/fidl/go/fidl_packages/fidl_test.go" region_tag="tables" %}

Protocols

Given the protocol:

{%includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/fidl/fuchsia.examples/types.test.fidl" region_tag="protocols" %}

Note: The MakeMove method above returns a bool representing success, and a nullable response value. This is considered un-idiomatic, you should use an error type instead.

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 for OnOppponentMove which takes a Context 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 an OnOpponentMove 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(uint8 row, uint8 col) -> (GameState new_state) 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.