blob: db6023a532482100430b9e83f1053b738e853598 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package fidlgen
import (
"encoding/json"
"fmt"
"io/ioutil"
"sort"
"strconv"
"strings"
)
/*
This file contains types which describe FIDL protocols.
These types are intended to be directly deserialized from the FIDL protocol
JSON representation. The types are then passed directly to language-specific
generators which produce source code.
Note that these are different from a naive AST-based representation of
FIDL text. Before being transformed into JSON, FIDL sources are preprocessed
to generate metadata required by all of the backends, such as the size of
types. Importantly, this removes the need for language-specific backends to
implement field, name, or type resolution and analysis.
*/
// ReadJSONIr reads a JSON IR file.
func ReadJSONIr(filename string) (Root, error) {
bytes, err := ioutil.ReadFile(filename)
if err != nil {
return Root{}, fmt.Errorf("Error reading from %s: %w", filename, err)
}
return ReadJSONIrContent(bytes)
}
// ReadJSONIrContent reads JSON IR content.
func ReadJSONIrContent(bytes []byte) (Root, error) {
var root Root
if err := json.Unmarshal(bytes, &root); err != nil {
return root, fmt.Errorf("Error parsing JSON IR: %v", err)
}
// TODO(fxbug.dev/50195): This is for backward compatibility with fidlgen_dart in
// Topaz, and should be removed after fidlgen_dart code has been updated.
root.Interfaces = root.Protocols
return root, nil
}
type Identifier string
type LibraryIdentifier []Identifier
type CompoundIdentifier struct {
Library LibraryIdentifier
Name Identifier
Member Identifier
}
type EncodedLibraryIdentifier string
type EncodedCompoundIdentifier string
func (eli EncodedLibraryIdentifier) Parts() LibraryIdentifier {
return ParseLibraryName(eli)
}
func (eli EncodedLibraryIdentifier) PartsReversed() []string {
parts := eli.Parts()
partsReversed := make([]string, len(parts))
for i, part := range parts {
partsReversed[len(parts)-i-1] = string(part)
}
return partsReversed
}
func (eci EncodedCompoundIdentifier) Parts() CompoundIdentifier {
return ParseCompoundIdentifier(eci)
}
func (eci EncodedCompoundIdentifier) LibraryName() EncodedLibraryIdentifier {
parts := strings.SplitN(string(eci), "/", 2)
raw_library := ""
if len(parts) == 2 {
raw_library = parts[0]
}
return EncodedLibraryIdentifier(raw_library)
}
func ParseLibraryName(eli EncodedLibraryIdentifier) LibraryIdentifier {
raw_parts := strings.Split(string(eli), ".")
parts := make([]Identifier, len(raw_parts))
for i, raw_part := range raw_parts {
parts[i] = Identifier(raw_part)
}
return LibraryIdentifier(parts)
}
func ParseCompoundIdentifier(eci EncodedCompoundIdentifier) CompoundIdentifier {
parts := strings.SplitN(string(eci), "/", 2)
raw_library := ""
raw_name := parts[0]
if len(parts) == 2 {
raw_library = parts[0]
raw_name = parts[1]
}
library := ParseLibraryName(EncodedLibraryIdentifier(raw_library))
name_parts := strings.SplitN(raw_name, ".", 2)
name := Identifier(name_parts[0])
member := Identifier("")
if len(name_parts) == 2 {
member = Identifier(name_parts[1])
}
return CompoundIdentifier{library, name, member}
}
func EnsureLibrary(l EncodedLibraryIdentifier, eci EncodedCompoundIdentifier) EncodedCompoundIdentifier {
if strings.Index(string(eci), "/") != -1 {
return eci
}
new_eci := strings.Join([]string{string(l), "/", string(eci)}, "")
return EncodedCompoundIdentifier(new_eci)
}
type PrimitiveSubtype string
const (
Bool PrimitiveSubtype = "bool"
Int8 PrimitiveSubtype = "int8"
Int16 PrimitiveSubtype = "int16"
Int32 PrimitiveSubtype = "int32"
Int64 PrimitiveSubtype = "int64"
Uint8 PrimitiveSubtype = "uint8"
Uint16 PrimitiveSubtype = "uint16"
Uint32 PrimitiveSubtype = "uint32"
Uint64 PrimitiveSubtype = "uint64"
Float32 PrimitiveSubtype = "float32"
Float64 PrimitiveSubtype = "float64"
)
var unsignedSubtypes = map[PrimitiveSubtype]struct{}{
Uint8: {},
Uint16: {},
Uint32: {},
Uint64: {},
}
// IsSigned indicates whether this subtype represents a signed number such as
// `int16`, or `float32`.
func (typ PrimitiveSubtype) IsSigned() bool {
return !typ.IsUnsigned()
}
// IsUnsigned indicates whether this subtype represents an unsigned number such
// as `uint16`.
func (typ PrimitiveSubtype) IsUnsigned() bool {
_, ok := unsignedSubtypes[typ]
return ok
}
type HandleSubtype string
const (
Handle HandleSubtype = "handle"
Bti HandleSubtype = "bti"
Channel HandleSubtype = "channel"
Clock HandleSubtype = "clock"
DebugLog HandleSubtype = "debuglog"
Event HandleSubtype = "event"
Eventpair HandleSubtype = "eventpair"
Exception HandleSubtype = "exception"
Fifo HandleSubtype = "fifo"
Guest HandleSubtype = "guest"
Interrupt HandleSubtype = "interrupt"
Iommu HandleSubtype = "iommu"
Job HandleSubtype = "job"
Pager HandleSubtype = "pager"
PciDevice HandleSubtype = "pcidevice"
Pmt HandleSubtype = "pmt"
Port HandleSubtype = "port"
Process HandleSubtype = "process"
Profile HandleSubtype = "profile"
Resource HandleSubtype = "resource"
Socket HandleSubtype = "socket"
Stream HandleSubtype = "stream"
SuspendToken HandleSubtype = "suspendtoken"
Thread HandleSubtype = "thread"
Time HandleSubtype = "timer"
Vcpu HandleSubtype = "vcpu"
Vmar HandleSubtype = "vmar"
Vmo HandleSubtype = "vmo"
)
// Copied from third_party/go/src/syscall/zx/types.go
type ObjectType uint32 // zx_obj_type_t
const (
ObjectTypeNone = ObjectType(iota)
ObjectTypeProcess
ObjectTypeThread
ObjectTypeVmo
ObjectTypeChannel
ObjectTypeEvent
ObjectTypePort
_ // 7
_ // 8
ObjectTypeInterrupt
_ // 10
ObjectTypePciDevice
ObjectTypeLog
_ // 13
ObjectTypeSocket
ObjectTypeResource
ObjectTypeEventPair
ObjectTypeJob
ObjectTypeVmar
ObjectTypeFifo
ObjectTypeGuest
ObjectTypeVcpu
ObjectTypeTimer
ObjectTypeIommu
ObjectTypeBti
ObjectTypeProfile
ObjectTypePmt
ObjectTypeSuspendToken
ObjectTypePager
)
// TODO(fxbug.dev/45998): emit the numeric value of the subtype in fidlc
func ObjectTypeFromHandleSubtype(val HandleSubtype) ObjectType {
switch val {
case Bti:
return ObjectTypeBti
case Channel:
return ObjectTypeChannel
case DebugLog:
return ObjectTypeLog
case Event:
return ObjectTypeEvent
case Eventpair:
return ObjectTypeEventPair
case Fifo:
return ObjectTypeFifo
case Guest:
return ObjectTypeGuest
case Interrupt:
return ObjectTypeInterrupt
case Iommu:
return ObjectTypeIommu
case Job:
return ObjectTypeJob
case Pager:
return ObjectTypePager
case PciDevice:
return ObjectTypePciDevice
case Pmt:
return ObjectTypePmt
case Port:
return ObjectTypePort
case Process:
return ObjectTypeProcess
case Profile:
return ObjectTypeProfile
case Resource:
return ObjectTypeResource
case Socket:
return ObjectTypeSocket
case SuspendToken:
return ObjectTypeSuspendToken
case Thread:
return ObjectTypeThread
case Time:
return ObjectTypeTimer
case Vcpu:
return ObjectTypeVcpu
case Vmar:
return ObjectTypeVmar
case Vmo:
return ObjectTypeVmo
default:
return ObjectTypeNone
}
}
type HandleRights uint32
type LiteralKind string
const (
StringLiteral LiteralKind = "string"
NumericLiteral LiteralKind = "numeric"
TrueLiteral LiteralKind = "true"
FalseLiteral LiteralKind = "false"
DefaultLiteral LiteralKind = "default"
)
type Literal struct {
Kind LiteralKind `json:"kind"`
Value string `json:"value,omitempty"`
}
type ConstantKind string
const (
IdentifierConstant ConstantKind = "identifier"
LiteralConstant ConstantKind = "literal"
)
type Constant struct {
Kind ConstantKind `json:"kind"`
Identifier EncodedCompoundIdentifier `json:"identifier,omitempty"`
Literal Literal `json:"literal,omitempty"`
}
type TypeKind string
const (
ArrayType TypeKind = "array"
VectorType TypeKind = "vector"
StringType TypeKind = "string"
HandleType TypeKind = "handle"
RequestType TypeKind = "request"
PrimitiveType TypeKind = "primitive"
IdentifierType TypeKind = "identifier"
)
type Type struct {
Kind TypeKind
ElementType *Type
ElementCount *int
HandleSubtype HandleSubtype
HandleRights HandleRights
RequestSubtype EncodedCompoundIdentifier
PrimitiveSubtype PrimitiveSubtype
Identifier EncodedCompoundIdentifier
Nullable bool
}
// UnmarshalJSON customizes the JSON unmarshalling for Type.
func (t *Type) UnmarshalJSON(b []byte) error {
var obj map[string]*json.RawMessage
err := json.Unmarshal(b, &obj)
if err != nil {
return err
}
err = json.Unmarshal(*obj["kind"], &t.Kind)
if err != nil {
return err
}
switch t.Kind {
case ArrayType:
t.ElementType = &Type{}
err = json.Unmarshal(*obj["element_type"], t.ElementType)
if err != nil {
return err
}
err = json.Unmarshal(*obj["element_count"], &t.ElementCount)
if err != nil {
return err
}
case VectorType:
t.ElementType = &Type{}
err = json.Unmarshal(*obj["element_type"], t.ElementType)
if err != nil {
return err
}
if elementCount, ok := obj["maybe_element_count"]; ok {
err = json.Unmarshal(*elementCount, &t.ElementCount)
if err != nil {
return err
}
}
err = json.Unmarshal(*obj["nullable"], &t.Nullable)
if err != nil {
return err
}
case StringType:
if elementCount, ok := obj["maybe_element_count"]; ok {
err = json.Unmarshal(*elementCount, &t.ElementCount)
if err != nil {
return err
}
}
err = json.Unmarshal(*obj["nullable"], &t.Nullable)
if err != nil {
return err
}
case HandleType:
err = json.Unmarshal(*obj["subtype"], &t.HandleSubtype)
if err != nil {
return err
}
err = json.Unmarshal(*obj["rights"], &t.HandleRights)
if err != nil {
return err
}
err = json.Unmarshal(*obj["nullable"], &t.Nullable)
if err != nil {
return err
}
case RequestType:
err = json.Unmarshal(*obj["subtype"], &t.RequestSubtype)
if err != nil {
return err
}
err = json.Unmarshal(*obj["nullable"], &t.Nullable)
if err != nil {
return err
}
case PrimitiveType:
err = json.Unmarshal(*obj["subtype"], &t.PrimitiveSubtype)
if err != nil {
return err
}
case IdentifierType:
err = json.Unmarshal(*obj["identifier"], &t.Identifier)
if err != nil {
return err
}
err = json.Unmarshal(*obj["nullable"], &t.Nullable)
if err != nil {
return err
}
default:
return fmt.Errorf("Unknown type kind: %s", t.Kind)
}
return nil
}
type Attribute struct {
Name Identifier `json:"name"`
Value string `json:"value"`
}
// Attributes represents a list of attributes. It conveniently implements the
// `Annotated` protocol, such that it can be embedded into other node structs
// which are annotated.
type Attributes struct {
Attributes []Attribute `json:"maybe_attributes,omitempty"`
}
func (el Attributes) LookupAttribute(name Identifier) (Attribute, bool) {
for _, a := range el.Attributes {
if a.Name == name {
return a, true
}
}
return Attribute{}, false
}
func (el Attributes) HasAttribute(name Identifier) bool {
_, ok := el.LookupAttribute(name)
return ok
}
func (el Attributes) GetAttribute(name Identifier) Attribute {
attr, _ := el.LookupAttribute(name)
return attr
}
func (el Attributes) DocComments() []string {
doc, ok := el.LookupAttribute("Doc")
if !ok || doc.Value == "" {
return nil
}
return strings.Split(doc.Value[0:len(doc.Value)-1], "\n")
}
func (el Attributes) Transports() map[string]struct{} {
transports := make(map[string]struct{})
raw, ok := el.LookupAttribute("Transport")
if ok && raw.Value != "" {
for _, transport := range strings.Split(raw.Value, ",") {
transports[strings.TrimSpace(transport)] = struct{}{}
}
}
// No transport attribute => just Channel
if !ok {
transports["Channel"] = struct{}{}
}
return transports
}
// BindingsDenylistIncludes returns true if the comma-separated BindingsDenyList
// attribute includes targetLanguage (meaning the bindings for targetLanguage
// should not emit this declaration).
func (el Attributes) BindingsDenylistIncludes(targetLanguage string) bool {
raw, ok := el.LookupAttribute("BindingsDenylist")
if ok && raw.Value != "" {
for _, language := range strings.Split(raw.Value, ",") {
if strings.TrimSpace(language) == targetLanguage {
return true
}
}
}
return false
}
// TypeShape represents the shape of the type on the wire.
// See JSON IR schema, e.g. fidlc --json-schema
type TypeShape struct {
InlineSize int `json:"inline_size"`
Alignment int `json:"alignment"`
Depth int `json:"depth"`
MaxHandles int `json:"max_handles"`
MaxOutOfLine int `json:"max_out_of_line"`
HasPadding bool `json:"has_padding"`
HasFlexibleEnvelope bool `json:"has_flexible_envelope"`
}
// FieldShape represents the shape of the field on the wire.
// See JSON IR schema, e.g. fidlc --json-schema
type FieldShape struct {
Offset int `json:"offset"`
Padding int `json:"padding"`
}
// Union represents the declaration of a FIDL union.
type Union struct {
Attributes
Name EncodedCompoundIdentifier `json:"name"`
Members []UnionMember `json:"members"`
Strictness `json:"strict"`
Resourceness `json:"resource"`
TypeShapeV1 TypeShape `json:"type_shape_v1"`
}
// UnionMember represents the declaration of a field in a FIDL extensible
// union.
type UnionMember struct {
Attributes
Reserved bool `json:"reserved"`
Ordinal int `json:"ordinal"`
Type Type `json:"type"`
Name Identifier `json:"name"`
Offset int `json:"offset"`
MaxOutOfLine int `json:"max_out_of_line"`
}
// Table represents a declaration of a FIDL table.
type Table struct {
Attributes
Name EncodedCompoundIdentifier `json:"name"`
Members []TableMember `json:"members"`
Resourceness `json:"resource"`
TypeShapeV1 TypeShape `json:"type_shape_v1"`
}
// TableMember represents the declaration of a field in a FIDL table.
type TableMember struct {
Attributes
Reserved bool `json:"reserved"`
Type Type `json:"type"`
Name Identifier `json:"name"`
Ordinal int `json:"ordinal"`
MaybeDefaultValue *Constant `json:"maybe_default_value,omitempty"`
MaxOutOfLine int `json:"max_out_of_line"`
}
// byTableOrdinal is a wrapper type for sorting a []TableMember.
type byTableOrdinal []TableMember
func (s byTableOrdinal) Len() int {
return len(s)
}
func (s byTableOrdinal) Less(i, j int) bool {
return s[i].Ordinal < s[j].Ordinal
}
func (s byTableOrdinal) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
// SortedMembersNoReserved returns the table's members sorted by ordinal,
// excluding reserved members.
func (t *Table) SortedMembersNoReserved() []TableMember {
var members []TableMember
for _, member := range t.Members {
if !member.Reserved {
members = append(members, member)
}
}
sort.Sort(byTableOrdinal(members))
return members
}
// Struct represents a declaration of a FIDL struct.
type Struct struct {
Attributes
Name EncodedCompoundIdentifier `json:"name"`
Anonymous bool `json:"anonymous"`
Members []StructMember `json:"members"`
Resourceness `json:"resource"`
TypeShapeV1 TypeShape `json:"type_shape_v1"`
}
// StructMember represents the declaration of a field in a FIDL struct.
type StructMember struct {
Attributes
Type Type `json:"type"`
Name Identifier `json:"name"`
MaybeDefaultValue *Constant `json:"maybe_default_value,omitempty"`
MaxHandles int `json:"max_handles"`
FieldShapeV1 FieldShape `json:"field_shape_v1"`
}
// EmptyStructMember returns a StructMember that's suitable as the sole member
// of an empty struct.
func EmptyStructMember(name string) StructMember {
// Empty structs have a size of 1, so the uint8 struct member returned by this
// function can be used to pad the struct to the correct size.
return StructMember{
Type: Type{
Kind: PrimitiveType,
PrimitiveSubtype: Uint8,
},
Name: Identifier(name),
MaybeDefaultValue: &Constant{
Kind: "literal",
Identifier: "",
Literal: Literal{
Kind: "numeric",
Value: "0",
},
},
}
}
// Protocol represents the declaration of a FIDL protocol.
type Protocol struct {
Attributes
Name EncodedCompoundIdentifier `json:"name"`
Methods []Method `json:"methods"`
}
// TODO(fxbug.dev/50195): This is for backward compatibility with fidlgen_dart in
// Topaz, and should be removed after fidlgen_dart code has been updated.
type Interface = Protocol
func (d *Protocol) GetServiceName() string {
_, found := d.LookupAttribute("Discoverable")
if found {
ci := ParseCompoundIdentifier(d.Name)
var parts []string
for _, i := range ci.Library {
parts = append(parts, string(i))
}
parts = append(parts, string(ci.Name))
return fmt.Sprintf("\"%s\"", strings.Join(parts, "."))
}
return ""
}
// Service represents the declaration of a FIDL service.
type Service struct {
Attributes
Name EncodedCompoundIdentifier `json:"name"`
Members []ServiceMember `json:"members"`
}
func (s *Service) GetServiceName() string {
ci := ParseCompoundIdentifier(s.Name)
var parts []string
for _, i := range ci.Library {
parts = append(parts, string(i))
}
parts = append(parts, string(ci.Name))
return strings.Join(parts, ".")
}
// ServiceMember represents the declaration of a field in a FIDL service.
type ServiceMember struct {
Attributes
Name Identifier `json:"name"`
Type Type `json:"type"`
}
// Method represents the declaration of a FIDL method.
type Method struct {
Attributes
Ordinal uint64 `json:"ordinal"`
Name Identifier `json:"name"`
HasRequest bool `json:"has_request"`
Request []Parameter `json:"maybe_request,omitempty"`
RequestPayload EncodedCompoundIdentifier `json:"maybe_request_payload,omitempty"`
RequestTypeShapeV1 TypeShape `json:"maybe_request_type_shape_v1,omitempty"`
RequestPadding bool `json:"maybe_request_has_padding,omitempty"`
RequestFlexible bool `json:"experimental_maybe_request_has_flexible_envelope,omitempty"`
HasResponse bool `json:"has_response"`
Response []Parameter `json:"maybe_response,omitempty"`
ResponsePayload EncodedCompoundIdentifier `json:"maybe_response_payload,omitempty"`
ResponseTypeShapeV1 TypeShape `json:"maybe_response_type_shape_v1,omitempty"`
ResponsePadding bool `json:"maybe_response_has_padding,omitempty"`
ResponseFlexible bool `json:"experimental_maybe_response_has_flexible_envelope,omitempty"`
}
// IsTransitional returns whether this method has the `Transitional` attribute.
func (m *Method) IsTransitional() bool {
_, transitional := m.LookupAttribute("Transitional")
return transitional
}
// Parameter represents a parameter to a FIDL method.
type Parameter struct {
Type Type `json:"type"`
Name Identifier `json:"name"`
MaxHandles int `json:"max_handles"`
MaxOutOfLine int `json:"max_out_of_line"`
FieldShapeV1 FieldShape `json:"field_shape_v1"`
}
// Enum represents a FIDL declaration of an enum.
type Enum struct {
Attributes
Type PrimitiveSubtype `json:"type"`
Name EncodedCompoundIdentifier `json:"name"`
Members []EnumMember `json:"members"`
Strictness `json:"strict"`
RawUnknownValue int64OrUint64 `json:"maybe_unknown_value"`
}
// UnknownValueAsInt64 retrieves the unknown value. Succeeds only for signed
// flexible enums.
func (enum *Enum) UnknownValueAsInt64() (int64, error) {
if enum.IsStrict() {
return 0, fmt.Errorf("cannot retrieve unknown value of strict enum")
}
if enum.Type.IsUnsigned() {
return 0, fmt.Errorf("cannot retrieve signed unknown value of unsigned flexible enum")
}
return enum.RawUnknownValue.readInt64(), nil
}
// UnknownValueAsUint64 retrieves the unknown value. Succeeds only for unsigned
// flexible enums.
func (enum *Enum) UnknownValueAsUint64() (uint64, error) {
if enum.IsStrict() {
return 0, fmt.Errorf("cannot retrieve unknown value of strict enum")
}
if enum.Type.IsSigned() {
return 0, fmt.Errorf("cannot retrieve unsigned unknown value of signed flexible enum")
}
return enum.RawUnknownValue.readUint64(), nil
}
// UnknownValueForTmpl retrieves the signed or unsigned unknown value. Panics
// if called on a strict enum.
func (enum *Enum) UnknownValueForTmpl() interface{} {
if enum.Type.IsSigned() {
unknownValue, err := enum.UnknownValueAsInt64()
if err != nil {
panic(err)
}
return unknownValue
}
unknownValue, err := enum.UnknownValueAsUint64()
if err != nil {
panic(err)
}
return unknownValue
}
// EnumMember represents a single variant in a FIDL enum.
type EnumMember struct {
Attributes
Name Identifier `json:"name"`
Value Constant `json:"value"`
}
// IsUnknown indicates whether this member represents a custom unknown flexible
// enum member.
func (member *EnumMember) IsUnknown() bool {
return member.HasAttribute("Unknown")
}
// Bits represents a FIDL declaration of an bits.
type Bits struct {
Attributes
Type Type `json:"type"`
Name EncodedCompoundIdentifier `json:"name"`
Mask string `json:"mask"`
Members []BitsMember `json:"members"`
Strictness `json:"strict"`
}
// BitsMember represents a single variant in a FIDL bits.
type BitsMember struct {
Attributes
Name Identifier `json:"name"`
Value Constant `json:"value"`
}
// Const represents a FIDL declaration of a named constant.
type Const struct {
Attributes
Type Type `json:"type"`
Name EncodedCompoundIdentifier `json:"name"`
Value Constant `json:"value"`
}
// Strictness represents whether a FIDL object is strict or flexible. See
// <https://fuchsia.dev/fuchsia-src/development/languages/fidl/reference/ftp/ftp-033> for more
// information.
type Strictness bool
const (
IsFlexible Strictness = false
IsStrict Strictness = true
)
// IsStrict indicates whether this type is strict.
func (s Strictness) IsStrict() bool {
return s == IsStrict
}
// IsFlexible indicates whether this type is flexible.
func (s Strictness) IsFlexible() bool {
return s == IsFlexible
}
// Resourceness represents whether a FIDL object may contain any resource types,
// such as handles. See https://fuchsia.dev/fuchsia-src/contribute/governance/fidl/ftp/ftp-057
// for more information.
type Resourceness bool
const (
IsResourceType Resourceness = true
IsValueType Resourceness = false
)
// IsResourceType indicates whether this type is marked as a resource type
func (r Resourceness) IsResourceType() bool {
return r == IsResourceType
}
// IsValueType indicates whether this type is not marked as a resource type
func (r Resourceness) IsValueType() bool {
return r == IsValueType
}
type DeclType string
const (
ConstDeclType DeclType = "const"
BitsDeclType DeclType = "bits"
EnumDeclType DeclType = "enum"
ProtocolDeclType DeclType = "interface"
ServiceDeclType DeclType = "service"
StructDeclType DeclType = "struct"
TableDeclType DeclType = "table"
UnionDeclType DeclType = "union"
// TODO(fxbug.dev/50195): This is for backward compatibility with fidlgen_dart in
// Topaz, and should be removed after fidlgen_dart code has been updated.
InterfaceDeclType DeclType = "interface"
)
type DeclInfo struct {
Type DeclType `json:"kind"`
// Present for structs, tables, and unions.
*Resourceness `json:"resource,omitempty"`
}
type DeclMap map[EncodedCompoundIdentifier]DeclType
type DeclInfoMap map[EncodedCompoundIdentifier]DeclInfo
func (dt DeclType) IsPrimitive() bool {
switch dt {
case BitsDeclType, EnumDeclType:
return true
}
return false
}
// Library represents a FIDL dependency on a separate library.
type Library struct {
Name EncodedLibraryIdentifier `json:"name,omitempty"`
Decls DeclInfoMap `json:"declarations,omitempty"`
}
// Root is the top-level object for a FIDL library.
// It contains lists of all declarations and dependencies within the library.
type Root struct {
Name EncodedLibraryIdentifier `json:"name,omitempty"`
Consts []Const `json:"const_declarations,omitempty"`
Bits []Bits `json:"bits_declarations,omitempty"`
Enums []Enum `json:"enum_declarations,omitempty"`
Protocols []Protocol `json:"interface_declarations,omitempty"`
Services []Service `json:"service_declarations,omitempty"`
Structs []Struct `json:"struct_declarations,omitempty"`
Tables []Table `json:"table_declarations,omitempty"`
Unions []Union `json:"union_declarations,omitempty"`
DeclOrder []EncodedCompoundIdentifier `json:"declaration_order,omitempty"`
Decls DeclMap `json:"declarations,omitempty"`
Libraries []Library `json:"library_dependencies,omitempty"`
// TODO(fxbug.dev/50195): This is for backward compatibility with fidlgen_dart in
// Topaz, and should be removed after fidlgen_dart code has been updated.
Interfaces []Protocol
}
// DeclsWithDependencies returns a single DeclInfoMap containing the FIDL
// library's declarations and those of its dependencies.
func (r *Root) DeclsWithDependencies() DeclInfoMap {
resourceness := make(map[EncodedCompoundIdentifier]Resourceness, len(r.Structs)+len(r.Tables)+len(r.Unions))
for _, v := range r.Structs {
resourceness[v.Name] = v.Resourceness
}
for _, v := range r.Tables {
resourceness[v.Name] = v.Resourceness
}
for _, v := range r.Unions {
resourceness[v.Name] = v.Resourceness
}
decls := DeclInfoMap{}
for k, v := range r.Decls {
ptr := new(Resourceness)
*ptr = resourceness[k]
decls[k] = DeclInfo{Type: v, Resourceness: ptr}
}
for _, l := range r.Libraries {
for k, v := range l.Decls {
decls[EnsureLibrary(l.Name, k)] = v
}
}
return decls
}
// ForBindings filters out declarations that should be omitted in the given
// language bindings based on BindingsDenylist attributes. It returns a new Root
// and does not modify r.
func (r *Root) ForBindings(language string) Root {
res := Root{
Name: r.Name,
Libraries: r.Libraries,
Decls: make(DeclMap, len(r.Decls)),
}
for _, v := range r.Consts {
if !v.BindingsDenylistIncludes(language) {
res.Consts = append(res.Consts, v)
res.Decls[v.Name] = r.Decls[v.Name]
}
}
for _, v := range r.Bits {
if !v.BindingsDenylistIncludes(language) {
newV := v
newV.Members = nil
for _, m := range v.Members {
if !m.BindingsDenylistIncludes(language) {
newV.Members = append(newV.Members, m)
}
}
res.Bits = append(res.Bits, newV)
res.Decls[v.Name] = r.Decls[v.Name]
}
}
for _, v := range r.Enums {
if !v.BindingsDenylistIncludes(language) {
newV := v
newV.Members = nil
for _, m := range v.Members {
if !m.BindingsDenylistIncludes(language) {
newV.Members = append(newV.Members, m)
}
}
res.Enums = append(res.Enums, newV)
res.Decls[v.Name] = r.Decls[v.Name]
}
}
for _, v := range r.Protocols {
if !v.BindingsDenylistIncludes(language) {
newV := v
newV.Methods = nil
for _, m := range v.Methods {
if !m.BindingsDenylistIncludes(language) {
newV.Methods = append(newV.Methods, m)
}
}
res.Protocols = append(res.Protocols, newV)
res.Decls[v.Name] = r.Decls[v.Name]
}
}
for _, v := range r.Services {
if !v.BindingsDenylistIncludes(language) {
newV := v
newV.Members = nil
for _, m := range v.Members {
if !m.BindingsDenylistIncludes(language) {
newV.Members = append(newV.Members, m)
}
}
res.Services = append(res.Services, newV)
res.Decls[v.Name] = r.Decls[v.Name]
}
}
for _, v := range r.Structs {
if !v.BindingsDenylistIncludes(language) {
newV := v
newV.Members = nil
for _, m := range v.Members {
if !m.BindingsDenylistIncludes(language) {
newV.Members = append(newV.Members, m)
}
}
res.Structs = append(res.Structs, newV)
res.Decls[v.Name] = r.Decls[v.Name]
}
}
for _, v := range r.Tables {
if !v.BindingsDenylistIncludes(language) {
newV := v
newV.Members = nil
for _, m := range v.Members {
if !m.BindingsDenylistIncludes(language) {
newV.Members = append(newV.Members, m)
} else {
newV.Members = append(newV.Members, TableMember{
Attributes: m.Attributes,
Reserved: true,
Name: m.Name,
Ordinal: m.Ordinal,
})
}
}
res.Tables = append(res.Tables, newV)
res.Decls[v.Name] = r.Decls[v.Name]
}
}
for _, v := range r.Unions {
if !v.BindingsDenylistIncludes(language) {
newV := v
newV.Members = nil
for _, m := range v.Members {
if !m.BindingsDenylistIncludes(language) {
newV.Members = append(newV.Members, m)
} else {
newV.Members = append(newV.Members, UnionMember{
Attributes: m.Attributes,
Reserved: true,
Name: m.Name,
Ordinal: m.Ordinal,
})
}
}
res.Unions = append(res.Unions, newV)
res.Decls[v.Name] = r.Decls[v.Name]
}
}
for _, d := range r.DeclOrder {
if _, ok := res.Decls[d]; ok {
res.DeclOrder = append(res.DeclOrder, d)
}
}
return res
}
type int64OrUint64 struct {
i int64
u uint64
}
func (n *int64OrUint64) readInt64() int64 {
if n.i != 0 {
return n.i
}
return int64(n.u)
}
func (n *int64OrUint64) readUint64() uint64 {
if n.i != 0 {
return uint64(n.i)
}
return n.u
}
var _ json.Unmarshaler = (*int64OrUint64)(nil)
func (n *int64OrUint64) UnmarshalJSON(data []byte) error {
if u, err := strconv.ParseUint(string(data), 10, 64); err == nil {
n.u = u
return nil
}
if i, err := strconv.ParseInt(string(data), 10, 64); err == nil {
n.i = i
return nil
}
return fmt.Errorf("%s not representable as int64 or uint64", string(data))
}