[fidl] Initial support for extensible unions.
Implements extensible unions ("xunions") described in FTP-015. This
depends on the zircon xunion CL
<https://fuchsia-review.googlesource.com/c/zircon/+/237693>.
Test: fx build-zircon -A -H -l && fx build host_x64/fidl_cpp_host_unittests && $FUCHSIA_DIR/out/x64/host_x64/fidl_cpp_host_unittests
Test: fx build garnet/go/src/fidl && $FUCHSIA_DIR/garnet/go/src/fidl/compiler/backend/typestest/regen.sh
Change-Id: I446149066d46fa11c5a29a7daf342bd9bfc22c07
diff --git a/go/src/fidl/compiler/backend/cpp/generator.go b/go/src/fidl/compiler/backend/cpp/generator.go
index dfa9b57..1ff2841 100644
--- a/go/src/fidl/compiler/backend/cpp/generator.go
+++ b/go/src/fidl/compiler/backend/cpp/generator.go
@@ -33,6 +33,7 @@
template.Must(tmpls.Parse(templates.Table))
template.Must(tmpls.Parse(templates.TestBase))
template.Must(tmpls.Parse(templates.Union))
+ template.Must(tmpls.Parse(templates.XUnion))
return &FidlGenerator{
tmpls: tmpls,
}
diff --git a/go/src/fidl/compiler/backend/cpp/ir/ir.go b/go/src/fidl/compiler/backend/cpp/ir/ir.go
index 7f97ad3..a898aa7 100644
--- a/go/src/fidl/compiler/backend/cpp/ir/ir.go
+++ b/go/src/fidl/compiler/backend/cpp/ir/ir.go
@@ -26,6 +26,7 @@
type structKind struct{}
type tableKind struct{}
type unionKind struct{}
+type xunionKind struct{}
var Kinds = struct {
Const constKind
@@ -34,6 +35,7 @@
Struct structKind
Table tableKind
Union unionKind
+ XUnion xunionKind
}{}
type Decl interface{}
@@ -89,6 +91,28 @@
Offset int
}
+type XUnion struct {
+ types.Attributes
+ Namespace string
+ Name string
+ TableType string
+ Members []XUnionMember
+ Size int
+ MaxHandles int
+ MaxOutOfLine int
+ Kind xunionKind
+}
+
+type XUnionMember struct {
+ types.Attributes
+ Ordinal int
+ Type Type
+ Name string
+ StorageName string
+ TagName string
+ Offset int
+}
+
type Table struct {
types.Attributes
Namespace string
@@ -113,6 +137,7 @@
MethodHasName string
MethodClearName string
ValueUnionName string
+ ValueXUnionName string
}
type Struct struct {
@@ -294,6 +319,7 @@
"while": true,
"xor": true,
"xor_eq": true,
+ "xunion": true,
// names used in specific contexts e.g. union accessors
"which": true,
@@ -478,6 +504,8 @@
case types.TableDeclType:
fallthrough
case types.UnionDeclType:
+ fallthrough
+ case types.XUnionDeclType:
if val.Nullable {
r.Decl = fmt.Sprintf("::std::unique_ptr<%s>", t)
r.LLDecl = fmt.Sprintf("%s*", t)
@@ -743,12 +771,12 @@
func (c *compiler) compileUnionMember(val types.UnionMember) UnionMember {
n := changeIfReserved(val.Name, "")
return UnionMember{
- val.Attributes,
- c.compileType(val.Type),
- n,
- changeIfReserved(val.Name, "_"),
- fmt.Sprintf("k%s", common.ToUpperCamelCase(n)),
- val.Offset,
+ Attributes: val.Attributes,
+ Type: c.compileType(val.Type),
+ Name: n,
+ StorageName: changeIfReserved(val.Name, "_"),
+ TagName: fmt.Sprintf("k%s", common.ToUpperCamelCase(n)),
+ Offset: val.Offset,
}
}
@@ -772,6 +800,38 @@
return r
}
+func (c *compiler) compileXUnionMember(val types.XUnionMember) XUnionMember {
+ n := changeIfReserved(val.Name, "")
+ return XUnionMember{
+ Attributes: val.Attributes,
+ Ordinal: val.Ordinal,
+ Type: c.compileType(val.Type),
+ Name: n,
+ StorageName: changeIfReserved(val.Name, "_"),
+ TagName: fmt.Sprintf("k%s", common.ToUpperCamelCase(n)),
+ Offset: val.Offset,
+ }
+}
+
+func (c *compiler) compileXUnion(val types.XUnion) XUnion {
+ name := c.compileCompoundIdentifier(val.Name, "")
+ r := XUnion{
+ Attributes: val.Attributes,
+ Namespace: c.namespace,
+ Name: name,
+ TableType: fmt.Sprintf("%s_%sTable", c.symbolPrefix, name),
+ Size: val.Size,
+ MaxHandles: val.MaxHandles,
+ MaxOutOfLine: val.MaxOutOfLine,
+ }
+
+ for _, v := range val.Members {
+ r.Members = append(r.Members, c.compileXUnionMember(v))
+ }
+
+ return r
+}
+
func Compile(r types.Root) Root {
root := Root{}
library := types.ParseLibraryName(r.Name)
@@ -825,6 +885,11 @@
decls[v.Name] = &d
}
+ for _, v := range r.XUnions {
+ d := c.compileXUnion(v)
+ decls[v.Name] = &d
+ }
+
for _, v := range r.DeclOrder {
d := decls[v]
if d == nil {
diff --git a/go/src/fidl/compiler/backend/cpp/templates/header.tmpl.go b/go/src/fidl/compiler/backend/cpp/templates/header.tmpl.go
index 58d4e91..cfbe4fe 100644
--- a/go/src/fidl/compiler/backend/cpp/templates/header.tmpl.go
+++ b/go/src/fidl/compiler/backend/cpp/templates/header.tmpl.go
@@ -27,6 +27,7 @@
{{- if Eq .Kind Kinds.Struct }}{{ template "StructForwardDeclaration" . }}{{- end }}
{{- if Eq .Kind Kinds.Table }}{{ template "TableForwardDeclaration" . }}{{- end }}
{{- if Eq .Kind Kinds.Union }}{{ template "UnionForwardDeclaration" . }}{{- end }}
+{{- if Eq .Kind Kinds.XUnion }}{{ template "XUnionForwardDeclaration" . }}{{- end }}
{{- end }}
{{- range .Decls }}
@@ -35,6 +36,7 @@
{{- if Eq .Kind Kinds.Struct }}{{ template "StructDeclaration" . }}{{- end }}
{{- if Eq .Kind Kinds.Table }}{{ template "TableDeclaration" . }}{{- end }}
{{- if Eq .Kind Kinds.Union }}{{ template "UnionDeclaration" . }}{{- end }}
+{{- if Eq .Kind Kinds.XUnion }}{{ template "XUnionDeclaration" . }}{{- end }}
{{- end }}
{{- range .LibraryReversed }}
@@ -49,6 +51,7 @@
{{- if Eq .Kind Kinds.Struct }}{{ template "StructTraits" . }}{{- end }}
{{- if Eq .Kind Kinds.Table }}{{ template "TableTraits" . }}{{- end }}
{{- if Eq .Kind Kinds.Union }}{{ template "UnionTraits" . }}{{- end }}
+{{- if Eq .Kind Kinds.XUnion }}{{ template "XUnionTraits" . }}{{- end }}
{{- end -}}
} // namespace fidl
diff --git a/go/src/fidl/compiler/backend/cpp/templates/implementation.tmpl.go b/go/src/fidl/compiler/backend/cpp/templates/implementation.tmpl.go
index c0dfd76..d221a60 100644
--- a/go/src/fidl/compiler/backend/cpp/templates/implementation.tmpl.go
+++ b/go/src/fidl/compiler/backend/cpp/templates/implementation.tmpl.go
@@ -22,6 +22,7 @@
{{- if Eq .Kind Kinds.Interface }}{{ template "InterfaceDefinition" . }}{{- end }}
{{- if Eq .Kind Kinds.Struct }}{{ template "StructDefinition" . }}{{- end }}
{{- if Eq .Kind Kinds.Union }}{{ template "UnionDefinition" . }}{{- end }}
+{{- if Eq .Kind Kinds.XUnion }}{{ template "XUnionDefinition" . }}{{- end }}
{{- if Eq .Kind Kinds.Table }}{{ template "TableDefinition" . }}{{- end }}
{{- end }}
diff --git a/go/src/fidl/compiler/backend/cpp/templates/table.tmpl.go b/go/src/fidl/compiler/backend/cpp/templates/table.tmpl.go
index c56a3b8..c810969 100644
--- a/go/src/fidl/compiler/backend/cpp/templates/table.tmpl.go
+++ b/go/src/fidl/compiler/backend/cpp/templates/table.tmpl.go
@@ -80,6 +80,9 @@
{{- end }}
{{- range .Members }}
+ {{/* The raw values of a table field are placed inside a union to ensure
+ that they're not initialized (since table fields are optional by
+ default). Placement new must be used to initialize the value. */ -}}
union {{ .ValueUnionName }} {
{{ .ValueUnionName }}() {}
~{{ .ValueUnionName }}() {}
diff --git a/go/src/fidl/compiler/backend/cpp/templates/xunion.tmpl.go b/go/src/fidl/compiler/backend/cpp/templates/xunion.tmpl.go
new file mode 100644
index 0000000..ae8371f
--- /dev/null
+++ b/go/src/fidl/compiler/backend/cpp/templates/xunion.tmpl.go
@@ -0,0 +1,281 @@
+// 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 templates
+
+const XUnion = `
+{{- define "XUnionForwardDeclaration" }}
+class {{ .Name }};
+{{- end }}
+
+{{- define "XUnionDeclaration" }}
+{{range .DocComments}}
+//{{ . }}
+{{- end}}
+class {{ .Name }} {
+ public:
+ static const fidl_type_t* FidlType;
+
+ {{ .Name }}();
+ ~{{ .Name }}();
+
+ {{ .Name }}({{ .Name }}&&);
+ {{ .Name }}& operator=({{ .Name }}&&);
+
+ enum Tag : fidl_xunion_tag_t {
+ Empty = 0,
+ {{- range .Members }}
+ {{ .TagName }} = {{ .Ordinal }},
+ {{- end }}
+ };
+
+ static inline ::std::unique_ptr<{{ .Name }}> New() { return ::std::make_unique<{{ .Name }}>(); }
+
+ void Encode(::fidl::Encoder* encoder, size_t offset);
+ static void Decode(::fidl::Decoder* decoder, {{ .Name }}* value, size_t offset);
+ zx_status_t Clone({{ .Name }}* result) const;
+
+ bool empty() const { return tag_ == Tag::Empty; }
+
+ {{- range .Members }}
+
+ bool is_{{ .Name }}() const { return tag_ == {{ .Ordinal }}; }
+ {{range .DocComments}}
+ //{{ . }}
+ {{- end}}
+ {{ .Type.Decl }}& {{ .Name }}() {
+ EnsureStorageInitialized({{ .Ordinal }});
+ return {{ .StorageName }};
+ }
+ {{range .DocComments}}
+ //{{ . }}
+ {{- end}}
+ const {{ .Type.Decl }}& {{ .Name }}() const { return {{ .StorageName }}; }
+ void set_{{ .Name }}({{ .Type.Decl }} value);
+ {{- end }}
+
+ Tag Which() const { return Tag(tag_); }
+
+ private:
+ friend bool operator==(const {{ .Name }}& lhs, const {{ .Name }}& rhs);
+ void Destroy();
+ void EnsureStorageInitialized(::fidl_xunion_tag_t tag);
+
+ ::fidl_xunion_tag_t tag_ = Tag::Empty;
+ union {
+ {{- range .Members }}
+ {{ .Type.Decl }} {{ .StorageName }};
+ {{- end }}
+ };
+};
+
+bool operator==(const {{ .Name }}& lhs, const {{ .Name }}& rhs);
+inline bool operator!=(const {{ .Name }}& lhs, const {{ .Name }}& rhs) {
+ return !(lhs == rhs);
+}
+
+inline zx_status_t Clone(const {{ .Namespace }}::{{ .Name }}& value,
+ {{ .Namespace }}::{{ .Name }}* result) {
+ return value.Clone(result);
+}
+
+using {{ .Name }}Ptr = ::std::unique_ptr<{{ .Name }}>;
+{{- end }}
+
+{{- define "XUnionDefinition" }}
+extern "C" const fidl_type_t {{ .TableType }};
+const fidl_type_t* {{ .Name }}::FidlType = &{{ .TableType }};
+
+{{ .Name }}::{{ .Name }}() {}
+
+{{ .Name }}::~{{ .Name }}() {
+ Destroy();
+}
+
+{{ .Name }}::{{ .Name }}({{ .Name }}&& other) : tag_(other.tag_) {
+ switch (tag_) {
+ {{- range .Members }}
+ case {{ .Ordinal }}:
+ {{- if .Type.Dtor }}
+ new (&{{ .StorageName }}) {{ .Type.Decl }}();
+ {{- end }}
+ {{ .StorageName }} = std::move(other.{{ .StorageName }});
+ break;
+ {{- end }}
+ default:
+ break;
+ }
+}
+
+{{ .Name }}& {{ .Name }}::operator=({{ .Name }}&& other) {
+ if (this != &other) {
+ Destroy();
+ tag_ = other.tag_;
+ switch (tag_) {
+ {{- range .Members }}
+ case {{ .Ordinal }}:
+ {{- if .Type.Dtor }}
+ new (&{{ .StorageName }}) {{ .Type.Decl }}();
+ {{- end }}
+ {{ .StorageName }} = std::move(other.{{ .StorageName }});
+ break;
+ {{- end }}
+ default:
+ break;
+ }
+ }
+ return *this;
+}
+
+void {{ .Name }}::Encode(::fidl::Encoder* encoder, size_t offset) {
+ const size_t length_before = encoder->CurrentLength();
+ const size_t handles_before = encoder->CurrentHandleCount();
+
+ size_t envelope_offset = 0;
+
+ switch (tag_) {
+ {{- range .Members }}
+ case {{ .Ordinal }}: {
+ envelope_offset = encoder->Alloc(::fidl::CodingTraits<{{ .Type.Decl }}>::encoded_size);
+ ::fidl::Encode(encoder, &{{ .StorageName }}, envelope_offset);
+ break;
+ }
+ {{- end }}
+ case Tag::Empty:
+ default:
+ break;
+ }
+
+ {{/* Note that encoder->GetPtr() must be called after every call to
+ encoder->Alloc(), since encoder.bytes_ could be re-sized and moved.
+ */ -}}
+
+ fidl_xunion_t* xunion = encoder->GetPtr<fidl_xunion_t>(offset);
+ assert(xunion->envelope.presence == FIDL_ALLOC_ABSENT);
+
+ if (envelope_offset) {
+ xunion->tag = tag_;
+ xunion->envelope.num_bytes = encoder->CurrentLength() - length_before;
+ xunion->envelope.num_handles = encoder->CurrentHandleCount() - handles_before;
+ xunion->envelope.presence = FIDL_ALLOC_PRESENT;
+ }
+}
+
+void {{ .Name }}::Decode(::fidl::Decoder* decoder, {{ .Name }}* value, size_t offset) {
+ fidl_xunion_t* xunion = decoder->GetPtr<fidl_xunion_t>(offset);
+
+ if (!xunion->envelope.data) {
+ value->EnsureStorageInitialized(Tag::Empty);
+ return;
+ }
+
+ value->EnsureStorageInitialized(xunion->tag);
+
+ const size_t envelope_offset = decoder->GetOffset(xunion->envelope.data);
+
+ switch (value->tag_) {
+ {{- range .Members }}
+ case {{ .Ordinal }}:
+ {{- if .Type.Dtor }}
+ new (&value->{{ .StorageName }}) {{ .Type.Decl }}();
+ {{- end }}
+ ::fidl::Decode(decoder, &value->{{ .StorageName }}, envelope_offset);
+ break;
+ {{- end }}
+ default:
+ {{/* The decoder doesn't have a schema for this tag, so it simply does
+ nothing. The generated code doesn't need to update the offsets to
+ "skip" the secondary object nor claim handles, since BufferWalker does
+ that. */ -}}
+ break;
+ }
+}
+
+zx_status_t {{ .Name }}::Clone({{ .Name }}* result) const {
+ result->Destroy();
+ result->tag_ = tag_;
+ switch (tag_) {
+ {{- range .Members }}
+ case {{ .Ordinal }}:
+ {{- if .Type.Dtor }}
+ new (&result->{{ .StorageName }}) {{ .Type.Decl }}();
+ {{- end }}
+ return ::fidl::Clone({{ .StorageName }}, &result->{{ .StorageName }});
+ {{- end }}
+ default:
+ return ZX_OK;
+ }
+}
+
+bool operator==(const {{ .Name }}& lhs, const {{ .Name }}& rhs) {
+ if (lhs.tag_ != rhs.tag_) {
+ return false;
+ }
+ switch (lhs.tag_) {
+ {{- range .Members }}
+ case {{ .Ordinal }}:
+ return ::fidl::Equals(lhs.{{ .StorageName }}, rhs.{{ .StorageName }});
+ {{- end }}
+ case {{ .Name }}::Tag::Empty:
+ return true;
+ default:
+ return false;
+ }
+}
+
+{{- range $member := .Members }}
+
+void {{ $.Name }}::set_{{ .Name }}({{ .Type.Decl }} value) {
+ EnsureStorageInitialized({{ .Ordinal }});
+ {{ .StorageName }} = std::move(value);
+}
+
+{{- end }}
+
+void {{ .Name }}::Destroy() {
+ switch (tag_) {
+ {{- range .Members }}
+ case {{ .Ordinal }}:
+ {{- if .Type.Dtor }}
+ {{ .StorageName }}.{{ .Type.Dtor }}();
+ {{- end }}
+ break;
+ {{- end }}
+ default:
+ break;
+ }
+ tag_ = Tag::Empty;
+}
+
+void {{ .Name }}::EnsureStorageInitialized(::fidl_xunion_tag_t tag) {
+ if (tag_ != tag) {
+ Destroy();
+ tag_ = tag;
+ switch (tag_) {
+ {{- range .Members }}
+ {{- if .Type.Dtor }}
+ case {{ .Ordinal }}:
+ new (&{{ .StorageName }}) {{ .Type.Decl }}();
+ break;
+ {{- end }}
+ {{- end }}
+ default:
+ break;
+ }
+ }
+}
+
+{{- end }}
+
+{{- define "XUnionTraits" }}
+template <>
+struct CodingTraits<{{ .Namespace }}::{{ .Name }}>
+ : public EncodableCodingTraits<{{ .Namespace }}::{{ .Name }}, {{ .Size }}> {};
+
+inline zx_status_t Clone(const {{ .Namespace }}::{{ .Name }}& value,
+ {{ .Namespace }}::{{ .Name }}* result) {
+ return {{ .Namespace }}::Clone(value, result);
+}
+{{- end }}
+`
diff --git a/go/src/fidl/compiler/backend/types/types.go b/go/src/fidl/compiler/backend/types/types.go
index a76b8df..4e82e12 100644
--- a/go/src/fidl/compiler/backend/types/types.go
+++ b/go/src/fidl/compiler/backend/types/types.go
@@ -329,6 +329,28 @@
MaxOutOfLine int `json:"max_out_of_line"`
}
+// XUnion represents the declaration of a FIDL extensible union.
+type XUnion struct {
+ Attributes
+ Name EncodedCompoundIdentifier `json:"name"`
+ Members []XUnionMember `json:"members"`
+ Size int `json:"size"`
+ Alignment int `json:"alignment"`
+ MaxHandles int `json:"max_handles"`
+ MaxOutOfLine int `json:"max_out_of_line"`
+}
+
+// XUnionMember represents the declaration of a field in a FIDL extensible
+// xunion.
+type XUnionMember struct {
+ Attributes
+ 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
@@ -478,6 +500,7 @@
StructDeclType = "struct"
TableDeclType = "table"
UnionDeclType = "union"
+ XUnionDeclType = "xunion"
)
type DeclMap map[EncodedCompoundIdentifier]DeclType
@@ -498,6 +521,7 @@
Structs []Struct `json:"struct_declarations,omitempty"`
Tables []Table `json:"table_declarations,omitempty"`
Unions []Union `json:"union_declarations,omitempty"`
+ XUnions []XUnion `json:"xunion_declarations,omitempty"`
DeclOrder []EncodedCompoundIdentifier `json:"declaration_order,omitempty"`
Decls DeclMap `json:"declarations,omitempty"`
Libraries []Library `json:"library_dependencies,omitempty"`
diff --git a/go/src/fidl/compiler/backend/typestest/doc_comments.fidl.json b/go/src/fidl/compiler/backend/typestest/doc_comments.fidl.json
index 5a3b1c4..f4916be 100644
--- a/go/src/fidl/compiler/backend/typestest/doc_comments.fidl.json
+++ b/go/src/fidl/compiler/backend/typestest/doc_comments.fidl.json
@@ -160,6 +160,7 @@
"max_handles": 0
}
],
+ "xunion_declarations": [],
"declaration_order": [
"test.name/Interface",
"test.name/Struct",
diff --git a/go/src/fidl/compiler/backend/typestest/empty_struct.fidl.json b/go/src/fidl/compiler/backend/typestest/empty_struct.fidl.json
index 590debd..0910a82 100644
--- a/go/src/fidl/compiler/backend/typestest/empty_struct.fidl.json
+++ b/go/src/fidl/compiler/backend/typestest/empty_struct.fidl.json
@@ -18,6 +18,7 @@
],
"table_declarations": [],
"union_declarations": [],
+ "xunion_declarations": [],
"declaration_order": [
"test.name/Empty"
],
diff --git a/go/src/fidl/compiler/backend/typestest/ordinal_switch.fidl.json b/go/src/fidl/compiler/backend/typestest/ordinal_switch.fidl.json
index 0490203..c254758 100644
--- a/go/src/fidl/compiler/backend/typestest/ordinal_switch.fidl.json
+++ b/go/src/fidl/compiler/backend/typestest/ordinal_switch.fidl.json
@@ -54,6 +54,7 @@
"struct_declarations": [],
"table_declarations": [],
"union_declarations": [],
+ "xunion_declarations": [],
"declaration_order": [
"test.name/SwitchingOrdinals"
],
diff --git a/go/src/fidl/compiler/backend/typestest/tables.fidl.json b/go/src/fidl/compiler/backend/typestest/tables.fidl.json
index 620ea48..3ea1bd7 100644
--- a/go/src/fidl/compiler/backend/typestest/tables.fidl.json
+++ b/go/src/fidl/compiler/backend/typestest/tables.fidl.json
@@ -146,6 +146,7 @@
}
],
"union_declarations": [],
+ "xunion_declarations": [],
"declaration_order": [
"test.name/OlderSimpleTable",
"test.name/NewerSimpleTable",
diff --git a/go/src/fidl/compiler/backend/typestest/union.fidl.json b/go/src/fidl/compiler/backend/typestest/union.fidl.json
index 198ceea..f6ffc53 100644
--- a/go/src/fidl/compiler/backend/typestest/union.fidl.json
+++ b/go/src/fidl/compiler/backend/typestest/union.fidl.json
@@ -55,6 +55,7 @@
"max_handles": 0
}
],
+ "xunion_declarations": [],
"declaration_order": [
"test.name/Union"
],
diff --git a/go/src/fidl/compiler/backend/typestest/xunion.fidl b/go/src/fidl/compiler/backend/typestest/xunion.fidl
new file mode 100644
index 0000000..53058bb
--- /dev/null
+++ b/go/src/fidl/compiler/backend/typestest/xunion.fidl
@@ -0,0 +1,15 @@
+library test.name;
+
+xunion OlderSimpleUnion {
+ int64 i;
+ float32 f;
+};
+
+xunion NewerSimpleUnion {
+ // float f; // removed
+
+ int64 i; // unchanged
+
+ string s; // added
+ vector<string> v; // added
+};
diff --git a/go/src/fidl/compiler/backend/typestest/xunion.fidl.json b/go/src/fidl/compiler/backend/typestest/xunion.fidl.json
new file mode 100644
index 0000000..e39396a
--- /dev/null
+++ b/go/src/fidl/compiler/backend/typestest/xunion.fidl.json
@@ -0,0 +1,103 @@
+{
+ "version": "0.0.1",
+ "name": "test.name",
+ "library_dependencies": [],
+ "const_declarations": [],
+ "enum_declarations": [],
+ "interface_declarations": [],
+ "struct_declarations": [],
+ "table_declarations": [],
+ "union_declarations": [],
+ "xunion_declarations": [
+ {
+ "name": "test.name/OlderSimpleUnion",
+ "members": [
+ {
+ "ordinal": 1026732503,
+ "type": {
+ "kind": "primitive",
+ "subtype": "int64"
+ },
+ "name": "i",
+ "size": 8,
+ "max_out_of_line": 0,
+ "alignment": 8,
+ "offset": 0
+ },
+ {
+ "ordinal": 1362546558,
+ "type": {
+ "kind": "primitive",
+ "subtype": "float32"
+ },
+ "name": "f",
+ "size": 4,
+ "max_out_of_line": 0,
+ "alignment": 4,
+ "offset": 0
+ }
+ ],
+ "size": 24,
+ "max_out_of_line": 8,
+ "alignment": 8,
+ "max_handles": 0
+ },
+ {
+ "name": "test.name/NewerSimpleUnion",
+ "members": [
+ {
+ "ordinal": 693944286,
+ "type": {
+ "kind": "primitive",
+ "subtype": "int64"
+ },
+ "name": "i",
+ "size": 8,
+ "max_out_of_line": 0,
+ "alignment": 8,
+ "offset": 0
+ },
+ {
+ "ordinal": 473666119,
+ "type": {
+ "kind": "string",
+ "nullable": false
+ },
+ "name": "s",
+ "size": 16,
+ "max_out_of_line": 4294967295,
+ "alignment": 8,
+ "offset": 0
+ },
+ {
+ "ordinal": 1815655055,
+ "type": {
+ "kind": "vector",
+ "element_type": {
+ "kind": "string",
+ "nullable": false
+ },
+ "nullable": false
+ },
+ "name": "v",
+ "size": 16,
+ "max_out_of_line": 4294967295,
+ "alignment": 8,
+ "offset": 0
+ }
+ ],
+ "size": 24,
+ "max_out_of_line": 4294967295,
+ "alignment": 8,
+ "max_handles": 0
+ }
+ ],
+ "declaration_order": [
+ "test.name/OlderSimpleUnion",
+ "test.name/NewerSimpleUnion"
+ ],
+ "declarations": {
+ "test.name/OlderSimpleUnion": "xunion",
+ "test.name/NewerSimpleUnion": "xunion"
+ }
+}
diff --git a/go/src/fidl/compiler/backend/typestest/xunion.fidl.json.cc.golden b/go/src/fidl/compiler/backend/typestest/xunion.fidl.json.cc.golden
new file mode 100644
index 0000000..21ed401
--- /dev/null
+++ b/go/src/fidl/compiler/backend/typestest/xunion.fidl.json.cc.golden
@@ -0,0 +1,351 @@
+// WARNING: This file is machine generated by fidlgen.
+
+#include <xunion.fidl.json.h>
+
+#include "lib/fidl/cpp/internal/implementation.h"
+namespace test {
+namespace name {
+
+extern "C" const fidl_type_t test_name_OlderSimpleUnionTable;
+const fidl_type_t* OlderSimpleUnion::FidlType = &test_name_OlderSimpleUnionTable;
+
+OlderSimpleUnion::OlderSimpleUnion() {}
+
+OlderSimpleUnion::~OlderSimpleUnion() {
+ Destroy();
+}
+
+OlderSimpleUnion::OlderSimpleUnion(OlderSimpleUnion&& other) : tag_(other.tag_) {
+ switch (tag_) {
+ case 1026732503:
+ i_ = std::move(other.i_);
+ break;
+ case 1362546558:
+ f_ = std::move(other.f_);
+ break;
+ default:
+ break;
+ }
+}
+
+OlderSimpleUnion& OlderSimpleUnion::operator=(OlderSimpleUnion&& other) {
+ if (this != &other) {
+ Destroy();
+ tag_ = other.tag_;
+ switch (tag_) {
+ case 1026732503:
+ i_ = std::move(other.i_);
+ break;
+ case 1362546558:
+ f_ = std::move(other.f_);
+ break;
+ default:
+ break;
+ }
+ }
+ return *this;
+}
+
+void OlderSimpleUnion::Encode(::fidl::Encoder* encoder, size_t offset) {
+ const size_t length_before = encoder->CurrentLength();
+ const size_t handles_before = encoder->CurrentHandleCount();
+
+ size_t envelope_offset = 0;
+
+ switch (tag_) {
+ case 1026732503: {
+ envelope_offset = encoder->Alloc(::fidl::CodingTraits<int64_t>::encoded_size);
+ ::fidl::Encode(encoder, &i_, envelope_offset);
+ break;
+ }
+ case 1362546558: {
+ envelope_offset = encoder->Alloc(::fidl::CodingTraits<float>::encoded_size);
+ ::fidl::Encode(encoder, &f_, envelope_offset);
+ break;
+ }
+ case Tag::Empty:
+ default:
+ break;
+ }
+
+ fidl_xunion_t* xunion = encoder->GetPtr<fidl_xunion_t>(offset);
+ assert(xunion->envelope.presence == FIDL_ALLOC_ABSENT);
+
+ if (envelope_offset) {
+ xunion->tag = tag_;
+ xunion->envelope.num_bytes = encoder->CurrentLength() - length_before;
+ xunion->envelope.num_handles = encoder->CurrentHandleCount() - handles_before;
+ xunion->envelope.presence = FIDL_ALLOC_PRESENT;
+ }
+}
+
+void OlderSimpleUnion::Decode(::fidl::Decoder* decoder, OlderSimpleUnion* value, size_t offset) {
+ fidl_xunion_t* xunion = decoder->GetPtr<fidl_xunion_t>(offset);
+
+ if (!xunion->envelope.data) {
+ value->EnsureStorageInitialized(Tag::Empty);
+ return;
+ }
+
+ value->EnsureStorageInitialized(xunion->tag);
+
+ const size_t envelope_offset = decoder->GetOffset(xunion->envelope.data);
+
+ switch (value->tag_) {
+ case 1026732503:
+ ::fidl::Decode(decoder, &value->i_, envelope_offset);
+ break;
+ case 1362546558:
+ ::fidl::Decode(decoder, &value->f_, envelope_offset);
+ break;
+ default:
+ break;
+ }
+}
+
+zx_status_t OlderSimpleUnion::Clone(OlderSimpleUnion* result) const {
+ result->Destroy();
+ result->tag_ = tag_;
+ switch (tag_) {
+ case 1026732503:
+ return ::fidl::Clone(i_, &result->i_);
+ case 1362546558:
+ return ::fidl::Clone(f_, &result->f_);
+ default:
+ return ZX_OK;
+ }
+}
+
+bool operator==(const OlderSimpleUnion& lhs, const OlderSimpleUnion& rhs) {
+ if (lhs.tag_ != rhs.tag_) {
+ return false;
+ }
+ switch (lhs.tag_) {
+ case 1026732503:
+ return ::fidl::Equals(lhs.i_, rhs.i_);
+ case 1362546558:
+ return ::fidl::Equals(lhs.f_, rhs.f_);
+ case OlderSimpleUnion::Tag::Empty:
+ return true;
+ default:
+ return false;
+ }
+}
+
+void OlderSimpleUnion::set_i(int64_t value) {
+ EnsureStorageInitialized(1026732503);
+ i_ = std::move(value);
+}
+
+void OlderSimpleUnion::set_f(float value) {
+ EnsureStorageInitialized(1362546558);
+ f_ = std::move(value);
+}
+
+void OlderSimpleUnion::Destroy() {
+ switch (tag_) {
+ case 1026732503:
+ break;
+ case 1362546558:
+ break;
+ default:
+ break;
+ }
+ tag_ = Tag::Empty;
+}
+
+void OlderSimpleUnion::EnsureStorageInitialized(::fidl_xunion_tag_t tag) {
+ if (tag_ != tag) {
+ Destroy();
+ tag_ = tag;
+ switch (tag_) {
+ default:
+ break;
+ }
+ }
+}
+extern "C" const fidl_type_t test_name_NewerSimpleUnionTable;
+const fidl_type_t* NewerSimpleUnion::FidlType = &test_name_NewerSimpleUnionTable;
+
+NewerSimpleUnion::NewerSimpleUnion() {}
+
+NewerSimpleUnion::~NewerSimpleUnion() {
+ Destroy();
+}
+
+NewerSimpleUnion::NewerSimpleUnion(NewerSimpleUnion&& other) : tag_(other.tag_) {
+ switch (tag_) {
+ case 693944286:
+ i_ = std::move(other.i_);
+ break;
+ case 473666119:
+ s_ = std::move(other.s_);
+ break;
+ case 1815655055:
+ v_ = std::move(other.v_);
+ break;
+ default:
+ break;
+ }
+}
+
+NewerSimpleUnion& NewerSimpleUnion::operator=(NewerSimpleUnion&& other) {
+ if (this != &other) {
+ Destroy();
+ tag_ = other.tag_;
+ switch (tag_) {
+ case 693944286:
+ i_ = std::move(other.i_);
+ break;
+ case 473666119:
+ s_ = std::move(other.s_);
+ break;
+ case 1815655055:
+ v_ = std::move(other.v_);
+ break;
+ default:
+ break;
+ }
+ }
+ return *this;
+}
+
+void NewerSimpleUnion::Encode(::fidl::Encoder* encoder, size_t offset) {
+ const size_t length_before = encoder->CurrentLength();
+ const size_t handles_before = encoder->CurrentHandleCount();
+
+ size_t envelope_offset = 0;
+
+ switch (tag_) {
+ case 693944286: {
+ envelope_offset = encoder->Alloc(::fidl::CodingTraits<int64_t>::encoded_size);
+ ::fidl::Encode(encoder, &i_, envelope_offset);
+ break;
+ }
+ case 473666119: {
+ envelope_offset = encoder->Alloc(::fidl::CodingTraits<::std::string>::encoded_size);
+ ::fidl::Encode(encoder, &s_, envelope_offset);
+ break;
+ }
+ case 1815655055: {
+ envelope_offset = encoder->Alloc(::fidl::CodingTraits<::std::vector<::std::string>>::encoded_size);
+ ::fidl::Encode(encoder, &v_, envelope_offset);
+ break;
+ }
+ case Tag::Empty:
+ default:
+ break;
+ }
+
+ fidl_xunion_t* xunion = encoder->GetPtr<fidl_xunion_t>(offset);
+ assert(xunion->envelope.presence == FIDL_ALLOC_ABSENT);
+
+ if (envelope_offset) {
+ xunion->tag = tag_;
+ xunion->envelope.num_bytes = encoder->CurrentLength() - length_before;
+ xunion->envelope.num_handles = encoder->CurrentHandleCount() - handles_before;
+ xunion->envelope.presence = FIDL_ALLOC_PRESENT;
+ }
+}
+
+void NewerSimpleUnion::Decode(::fidl::Decoder* decoder, NewerSimpleUnion* value, size_t offset) {
+ fidl_xunion_t* xunion = decoder->GetPtr<fidl_xunion_t>(offset);
+
+ if (!xunion->envelope.data) {
+ value->EnsureStorageInitialized(Tag::Empty);
+ return;
+ }
+
+ value->EnsureStorageInitialized(xunion->tag);
+
+ const size_t envelope_offset = decoder->GetOffset(xunion->envelope.data);
+
+ switch (value->tag_) {
+ case 693944286:
+ ::fidl::Decode(decoder, &value->i_, envelope_offset);
+ break;
+ case 473666119:
+ ::fidl::Decode(decoder, &value->s_, envelope_offset);
+ break;
+ case 1815655055:
+ ::fidl::Decode(decoder, &value->v_, envelope_offset);
+ break;
+ default:
+ break;
+ }
+}
+
+zx_status_t NewerSimpleUnion::Clone(NewerSimpleUnion* result) const {
+ result->Destroy();
+ result->tag_ = tag_;
+ switch (tag_) {
+ case 693944286:
+ return ::fidl::Clone(i_, &result->i_);
+ case 473666119:
+ return ::fidl::Clone(s_, &result->s_);
+ case 1815655055:
+ return ::fidl::Clone(v_, &result->v_);
+ default:
+ return ZX_OK;
+ }
+}
+
+bool operator==(const NewerSimpleUnion& lhs, const NewerSimpleUnion& rhs) {
+ if (lhs.tag_ != rhs.tag_) {
+ return false;
+ }
+ switch (lhs.tag_) {
+ case 693944286:
+ return ::fidl::Equals(lhs.i_, rhs.i_);
+ case 473666119:
+ return ::fidl::Equals(lhs.s_, rhs.s_);
+ case 1815655055:
+ return ::fidl::Equals(lhs.v_, rhs.v_);
+ case NewerSimpleUnion::Tag::Empty:
+ return true;
+ default:
+ return false;
+ }
+}
+
+void NewerSimpleUnion::set_i(int64_t value) {
+ EnsureStorageInitialized(693944286);
+ i_ = std::move(value);
+}
+
+void NewerSimpleUnion::set_s(::std::string value) {
+ EnsureStorageInitialized(473666119);
+ s_ = std::move(value);
+}
+
+void NewerSimpleUnion::set_v(::std::vector<::std::string> value) {
+ EnsureStorageInitialized(1815655055);
+ v_ = std::move(value);
+}
+
+void NewerSimpleUnion::Destroy() {
+ switch (tag_) {
+ case 693944286:
+ break;
+ case 473666119:
+ break;
+ case 1815655055:
+ break;
+ default:
+ break;
+ }
+ tag_ = Tag::Empty;
+}
+
+void NewerSimpleUnion::EnsureStorageInitialized(::fidl_xunion_tag_t tag) {
+ if (tag_ != tag) {
+ Destroy();
+ tag_ = tag;
+ switch (tag_) {
+ default:
+ break;
+ }
+ }
+}
+} // namespace name
+} // namespace test
diff --git a/go/src/fidl/compiler/backend/typestest/xunion.fidl.json.go.golden b/go/src/fidl/compiler/backend/typestest/xunion.fidl.json.go.golden
new file mode 100644
index 0000000..145cd5d
--- /dev/null
+++ b/go/src/fidl/compiler/backend/typestest/xunion.fidl.json.go.golden
@@ -0,0 +1,8 @@
+// WARNING: This file is machine generated by fidlgen.
+
+package name
+
+
+
+
+
diff --git a/go/src/fidl/compiler/backend/typestest/xunion.fidl.json.h.golden b/go/src/fidl/compiler/backend/typestest/xunion.fidl.json.h.golden
new file mode 100644
index 0000000..1a55ce3
--- /dev/null
+++ b/go/src/fidl/compiler/backend/typestest/xunion.fidl.json.h.golden
@@ -0,0 +1,184 @@
+// WARNING: This file is machine generated by fidlgen.
+
+#pragma once
+
+#include "lib/fidl/cpp/internal/header.h"
+
+
+namespace test {
+namespace name {
+
+class OlderSimpleUnion;
+class NewerSimpleUnion;
+
+class OlderSimpleUnion {
+ public:
+ static const fidl_type_t* FidlType;
+
+ OlderSimpleUnion();
+ ~OlderSimpleUnion();
+
+ OlderSimpleUnion(OlderSimpleUnion&&);
+ OlderSimpleUnion& operator=(OlderSimpleUnion&&);
+
+ enum Tag : fidl_xunion_tag_t {
+ Empty = 0,
+ kI = 1026732503,
+ kF = 1362546558,
+ };
+
+ static inline ::std::unique_ptr<OlderSimpleUnion> New() { return ::std::make_unique<OlderSimpleUnion>(); }
+
+ void Encode(::fidl::Encoder* encoder, size_t offset);
+ static void Decode(::fidl::Decoder* decoder, OlderSimpleUnion* value, size_t offset);
+ zx_status_t Clone(OlderSimpleUnion* result) const;
+
+ bool empty() const { return tag_ == Tag::Empty; }
+
+ bool is_i() const { return tag_ == 1026732503; }
+
+ int64_t& i() {
+ EnsureStorageInitialized(1026732503);
+ return i_;
+ }
+
+ const int64_t& i() const { return i_; }
+ void set_i(int64_t value);
+
+ bool is_f() const { return tag_ == 1362546558; }
+
+ float& f() {
+ EnsureStorageInitialized(1362546558);
+ return f_;
+ }
+
+ const float& f() const { return f_; }
+ void set_f(float value);
+
+ Tag Which() const { return Tag(tag_); }
+
+ private:
+ friend bool operator==(const OlderSimpleUnion& lhs, const OlderSimpleUnion& rhs);
+ void Destroy();
+ void EnsureStorageInitialized(::fidl_xunion_tag_t tag);
+
+ ::fidl_xunion_tag_t tag_ = Tag::Empty;
+ union {
+ int64_t i_;
+ float f_;
+ };
+};
+
+bool operator==(const OlderSimpleUnion& lhs, const OlderSimpleUnion& rhs);
+inline bool operator!=(const OlderSimpleUnion& lhs, const OlderSimpleUnion& rhs) {
+ return !(lhs == rhs);
+}
+
+inline zx_status_t Clone(const ::test::name::OlderSimpleUnion& value,
+ ::test::name::OlderSimpleUnion* result) {
+ return value.Clone(result);
+}
+
+using OlderSimpleUnionPtr = ::std::unique_ptr<OlderSimpleUnion>;
+
+class NewerSimpleUnion {
+ public:
+ static const fidl_type_t* FidlType;
+
+ NewerSimpleUnion();
+ ~NewerSimpleUnion();
+
+ NewerSimpleUnion(NewerSimpleUnion&&);
+ NewerSimpleUnion& operator=(NewerSimpleUnion&&);
+
+ enum Tag : fidl_xunion_tag_t {
+ Empty = 0,
+ kI = 693944286,
+ kS = 473666119,
+ kV = 1815655055,
+ };
+
+ static inline ::std::unique_ptr<NewerSimpleUnion> New() { return ::std::make_unique<NewerSimpleUnion>(); }
+
+ void Encode(::fidl::Encoder* encoder, size_t offset);
+ static void Decode(::fidl::Decoder* decoder, NewerSimpleUnion* value, size_t offset);
+ zx_status_t Clone(NewerSimpleUnion* result) const;
+
+ bool empty() const { return tag_ == Tag::Empty; }
+
+ bool is_i() const { return tag_ == 693944286; }
+
+ int64_t& i() {
+ EnsureStorageInitialized(693944286);
+ return i_;
+ }
+
+ const int64_t& i() const { return i_; }
+ void set_i(int64_t value);
+
+ bool is_s() const { return tag_ == 473666119; }
+
+ ::std::string& s() {
+ EnsureStorageInitialized(473666119);
+ return s_;
+ }
+
+ const ::std::string& s() const { return s_; }
+ void set_s(::std::string value);
+
+ bool is_v() const { return tag_ == 1815655055; }
+
+ ::std::vector<::std::string>& v() {
+ EnsureStorageInitialized(1815655055);
+ return v_;
+ }
+
+ const ::std::vector<::std::string>& v() const { return v_; }
+ void set_v(::std::vector<::std::string> value);
+
+ Tag Which() const { return Tag(tag_); }
+
+ private:
+ friend bool operator==(const NewerSimpleUnion& lhs, const NewerSimpleUnion& rhs);
+ void Destroy();
+ void EnsureStorageInitialized(::fidl_xunion_tag_t tag);
+
+ ::fidl_xunion_tag_t tag_ = Tag::Empty;
+ union {
+ int64_t i_;
+ ::std::string s_;
+ ::std::vector<::std::string> v_;
+ };
+};
+
+bool operator==(const NewerSimpleUnion& lhs, const NewerSimpleUnion& rhs);
+inline bool operator!=(const NewerSimpleUnion& lhs, const NewerSimpleUnion& rhs) {
+ return !(lhs == rhs);
+}
+
+inline zx_status_t Clone(const ::test::name::NewerSimpleUnion& value,
+ ::test::name::NewerSimpleUnion* result) {
+ return value.Clone(result);
+}
+
+using NewerSimpleUnionPtr = ::std::unique_ptr<NewerSimpleUnion>;
+} // namespace name
+} // namespace test
+namespace fidl {
+
+template <>
+struct CodingTraits<::test::name::OlderSimpleUnion>
+ : public EncodableCodingTraits<::test::name::OlderSimpleUnion, 24> {};
+
+inline zx_status_t Clone(const ::test::name::OlderSimpleUnion& value,
+ ::test::name::OlderSimpleUnion* result) {
+ return ::test::name::Clone(value, result);
+}
+template <>
+struct CodingTraits<::test::name::NewerSimpleUnion>
+ : public EncodableCodingTraits<::test::name::NewerSimpleUnion, 24> {};
+
+inline zx_status_t Clone(const ::test::name::NewerSimpleUnion& value,
+ ::test::name::NewerSimpleUnion* result) {
+ return ::test::name::Clone(value, result);
+}} // namespace fidl
diff --git a/go/src/fidl/compiler/backend/typestest/xunion.fidl.json.llcpp.cpp.golden b/go/src/fidl/compiler/backend/typestest/xunion.fidl.json.llcpp.cpp.golden
new file mode 100644
index 0000000..610416c
--- /dev/null
+++ b/go/src/fidl/compiler/backend/typestest/xunion.fidl.json.llcpp.cpp.golden
@@ -0,0 +1,9 @@
+// WARNING: This file is machine generated by fidlgen.
+
+#include <xunion.fidl.json.llcpp.h>
+
+namespace test {
+namespace name {
+
+} // namespace name
+} // namespace test
diff --git a/go/src/fidl/compiler/backend/typestest/xunion.fidl.json.llcpp.h.golden b/go/src/fidl/compiler/backend/typestest/xunion.fidl.json.llcpp.h.golden
new file mode 100644
index 0000000..582c8dd
--- /dev/null
+++ b/go/src/fidl/compiler/backend/typestest/xunion.fidl.json.llcpp.h.golden
@@ -0,0 +1,23 @@
+// WARNING: This file is machine generated by fidlgen.
+
+#pragma once
+
+#include <lib/fidl/internal.h>
+#include <lib/fidl/cpp/vector_view.h>
+#include <lib/fidl/cpp/string_view.h>
+#include <lib/fidl/llcpp/array_wrapper.h>
+#include <lib/fidl/llcpp/coding.h>
+#include <lib/fidl/llcpp/traits.h>
+
+#include <zircon/fidl.h>
+
+namespace test {
+namespace name {
+
+
+} // namespace name
+} // namespace test
+
+namespace fidl {
+
+} // namespace fidl
diff --git a/go/src/fidl/compiler/backend/typestest/xunion.fidl.json.rs.golden b/go/src/fidl/compiler/backend/typestest/xunion.fidl.json.rs.golden
new file mode 100644
index 0000000..7b9c869
--- /dev/null
+++ b/go/src/fidl/compiler/backend/typestest/xunion.fidl.json.rs.golden
@@ -0,0 +1,15 @@
+// WARNING: This file is machine generated by fidlgen.
+
+#![feature(futures_api, pin, arbitrary_self_types, nll)]
+#![allow(warnings)]
+
+extern crate fuchsia_async;
+extern crate fuchsia_zircon as zx;
+#[macro_use]
+extern crate fidl;
+#[macro_use]
+extern crate futures;
+use fidl::encoding::{Encodable, Decodable};
+use futures::{Future, Stream, StreamExt};
+use std::ops::Deref;
+
diff --git a/go/src/fidl/compiler/backend/typestest/xunion.fidl.json_test_base.h.golden b/go/src/fidl/compiler/backend/typestest/xunion.fidl.json_test_base.h.golden
new file mode 100644
index 0000000..ebc6e21
--- /dev/null
+++ b/go/src/fidl/compiler/backend/typestest/xunion.fidl.json_test_base.h.golden
@@ -0,0 +1,11 @@
+// WARNING: This file is machine generated by fidlgen.
+
+#pragma once
+
+
+namespace test {
+namespace name {
+namespace testing {
+} // namespace testing
+} // namespace name
+} // namespace test
diff --git a/public/lib/fidl/cpp/BUILD.gn b/public/lib/fidl/cpp/BUILD.gn
index 5a88e32..7cb2d53 100644
--- a/public/lib/fidl/cpp/BUILD.gn
+++ b/public/lib/fidl/cpp/BUILD.gn
@@ -241,3 +241,10 @@
]
}
}
+
+# group("host_tests") {
+# deps = [
+# ":fidl_cpp_host_unittests($host_toolchain)",
+# ]
+# testonly = true
+# }
diff --git a/public/lib/fidl/cpp/fidl_test.fidl b/public/lib/fidl/cpp/fidl_test.fidl
index bfc37bc..83307c8 100644
--- a/public/lib/fidl/cpp/fidl_test.fidl
+++ b/public/lib/fidl/cpp/fidl_test.fidl
@@ -21,17 +21,17 @@
};
struct EmptyStructSandwich {
- string before;
- Empty e;
- string after;
+ string before;
+ Empty e;
+ string after;
};
union SimpleUnion {
- int32 i32;
- int64 i64;
- Int64Struct s;
- Int64Struct? os;
- string str;
+ int32 i32;
+ int64 i64;
+ Int64Struct s;
+ Int64Struct? os;
+ string str;
};
table SimpleTable {
@@ -60,3 +60,15 @@
6: int64 z;
7: reserved;
};
+
+xunion SampleXUnion {
+ int32 i;
+ SimpleUnion su;
+ SimpleTable st;
+};
+
+struct XUnionContainer {
+ string before;
+ SampleXUnion? xu;
+ string after;
+};
diff --git a/public/lib/fidl/cpp/roundtrip_test.cc b/public/lib/fidl/cpp/roundtrip_test.cc
index 3830466..43fa481 100644
--- a/public/lib/fidl/cpp/roundtrip_test.cc
+++ b/public/lib/fidl/cpp/roundtrip_test.cc
@@ -18,14 +18,14 @@
template <class Output, class Input>
Output RoundTrip(const Input& input) {
- const ::fidl::FidlField fake_input_interface_fields[] = {
- ::fidl::FidlField(Input::FidlType, 16),
+ const ::fidl::FidlStructField fake_input_interface_fields[] = {
+ ::fidl::FidlStructField(Input::FidlType, 16),
};
const fidl_type_t fake_input_interface_struct{
::fidl::FidlCodedStruct(fake_input_interface_fields, 1,
16 + CodingTraits<Input>::encoded_size, "Input")};
- const ::fidl::FidlField fake_output_interface_fields[] = {
- ::fidl::FidlField(Output::FidlType, 16),
+ const ::fidl::FidlStructField fake_output_interface_fields[] = {
+ ::fidl::FidlStructField(Output::FidlType, 16),
};
const fidl_type_t fake_output_interface_struct{::fidl::FidlCodedStruct(
fake_output_interface_fields, 1, 16 + CodingTraits<Output>::encoded_size,
@@ -35,6 +35,7 @@
auto ofs = enc.Alloc(CodingTraits<Input>::encoded_size);
fidl::Clone(input).Encode(&enc, ofs);
auto msg = enc.GetMessage();
+
const char* err_msg = nullptr;
EXPECT_EQ(ZX_OK, msg.Validate(&fake_input_interface_struct, &err_msg))
<< err_msg;
@@ -57,14 +58,14 @@
for (size_t i = 0; i < actual_size && i < expected_size; i++) {
if (actual[i] != expected[i]) {
pass = false;
- std::cout << "element[" << i << "]: "
- << "actual=" << +actual[i] << " "
- << "expected=" << +expected[i] << "\n";
+ std::cout << std::dec << "element[" << i << "]: " << std::hex
+ << "actual=0x" << +actual[i] << " "
+ << "expected=0x" << +expected[i] << "\n";
}
}
if (actual_size != expected_size) {
pass = false;
- std::cout << "element[...]: "
+ std::cout << std::dec << "element[...]: "
<< "actual.size=" << +actual_size << " "
<< "expected.size=" << +expected_size << "\n";
}
@@ -87,36 +88,50 @@
SimpleTable input;
auto expected = std::vector<uint8_t>{
- 0, 0, 0, 0, 0, 0, 0, 0, // max ordinal
- 255, 255, 255, 255, 255, 255, 255, 255, // alloc present
+ 0, 0, 0, 0, 0, 0, 0, 0, // max ordinal
+ 255, 255, 255, 255, 255, 255, 255, 255, // alloc present
};
EXPECT_TRUE(ValueToBytes(input, expected));
}
+std::vector<uint8_t> kSimpleTable_X_42_Y_67 = std::vector<uint8_t>{
+ 5, 0, 0, 0,
+ 0, 0, 0, 0, // max ordinal
+ 255, 255, 255, 255,
+ 255, 255, 255, 255, // alloc present
+ 8, 0, 0, 0,
+ 0, 0, 0, 0, // envelope 1: num bytes / num handles
+ 255, 255, 255, 255,
+ 255, 255, 255, 255, // alloc present
+ 0, 0, 0, 0,
+ 0, 0, 0, 0, // envelope 2: num bytes / num handles
+ 0, 0, 0, 0,
+ 0, 0, 0, 0, // no alloc
+ 0, 0, 0, 0,
+ 0, 0, 0, 0, // envelope 3: num bytes / num handles
+ 0, 0, 0, 0,
+ 0, 0, 0, 0, // no alloc
+ 0, 0, 0, 0,
+ 0, 0, 0, 0, // envelope 4: num bytes / num handles
+ 0, 0, 0, 0,
+ 0, 0, 0, 0, // no alloc
+ 8, 0, 0, 0,
+ 0, 0, 0, 0, // envelope 5: num bytes / num handles
+ 255, 255, 255, 255,
+ 255, 255, 255, 255, // alloc present
+ 42, 0, 0, 0,
+ 0, 0, 0, 0, // field X
+ 67, 0, 0, 0,
+ 0, 0, 0, 0, // field Y
+};
+
TEST(SimpleTable, CheckBytesWithXY) {
SimpleTable input;
input.set_x(42);
input.set_y(67);
- auto expected = std::vector<uint8_t>{
- 5, 0, 0, 0, 0, 0, 0, 0, // max ordinal
- 255, 255, 255, 255, 255, 255, 255, 255, // alloc present
- 8, 0, 0, 0, 0, 0, 0, 0, // envelope 1: num bytes / num handles
- 255, 255, 255, 255, 255, 255, 255, 255, // alloc present
- 0, 0, 0, 0, 0, 0, 0, 0, // envelope 2: num bytes / num handles
- 0, 0, 0, 0, 0, 0, 0, 0, // no alloc
- 0, 0, 0, 0, 0, 0, 0, 0, // envelope 3: num bytes / num handles
- 0, 0, 0, 0, 0, 0, 0, 0, // no alloc
- 0, 0, 0, 0, 0, 0, 0, 0, // envelope 4: num bytes / num handles
- 0, 0, 0, 0, 0, 0, 0, 0, // no alloc
- 8, 0, 0, 0, 0, 0, 0, 0, // envelope 5: num bytes / num handles
- 255, 255, 255, 255, 255, 255, 255, 255, // alloc present
- 42, 0, 0, 0, 0, 0, 0, 0, // field X
- 67, 0, 0, 0, 0, 0, 0, 0, // field Y
- };
-
- EXPECT_TRUE(ValueToBytes(input, expected));
+ EXPECT_TRUE(ValueToBytes(input, kSimpleTable_X_42_Y_67));
}
TEST(SimpleTable, SerializeAndDeserialize) {
@@ -153,41 +168,186 @@
Empty input;
auto expected = std::vector<uint8_t>{
- 0, // empty struct zero field
- 0, 0, 0, 0, 0, 0, 0, // 7 bytes of padding after empty struct, to align to 64 bits
+ 0, // empty struct zero field
+ 0, 0, 0, 0, 0, 0, 0, // 7 bytes of padding
};
EXPECT_TRUE(ValueToBytes(input, expected));
}
TEST(EmptyStructSandwich, SerializeAndDeserialize) {
EmptyStructSandwich input{
- .before = "before",
- .after = "after",
+ .before = "before",
+ .after = "after",
};
EXPECT_EQ(input, RoundTrip<EmptyStructSandwich>(input));
}
TEST(EmptyStructSandwich, CheckBytes) {
- EmptyStructSandwich input{
- .before = "before",
- .after = "after"
- };
+ EmptyStructSandwich input{.before = "before", .after = "after"};
auto expected = std::vector<uint8_t>{
- 6, 0, 0, 0, 0, 0, 0, 0, // length of "before"
- 255, 255, 255, 255, 255, 255, 255, 255, // "before" is present
- 0, // empty struct zero field
- 0, 0, 0, 0, 0, 0, 0, // 7 bytes of padding after empty struct, to align to 64 bits
- 5, 0, 0, 0, 0, 0, 0, 0, // length of "world"
- 255, 255, 255, 255, 255, 255, 255, 255, // "after" is present
- 'b', 'e', 'f', 'o', 'r', 'e', // "before" string
- 0, 0, // 2 bytes of padding after "before", to align to 64 bits
- 'a', 'f', 't', 'e', 'r', // "after" string
- 0, 0, 0, // 3 bytes of padding after "after", to align to 64 bits
+ 6, 0, 0, 0, 0, 0, 0, 0, // length of "before"
+ 255, 255, 255, 255, 255, 255, 255, 255, // "before" is present
+ 0, // empty struct zero field
+ 0, 0, 0, 0, 0, 0, 0, // 7 bytes of padding
+ 5, 0, 0, 0, 0, 0, 0, 0, // length of "world"
+ 255, 255, 255, 255, 255, 255, 255, 255, // "after" is present
+ 'b', 'e', 'f', 'o', 'r', 'e', // "before" string
+ 0, 0, // 2 bytes of padding
+ 'a', 'f', 't', 'e', 'r', // "after" string
+ 0, 0, 0, // 3 bytes of padding
};
EXPECT_TRUE(ValueToBytes(input, expected));
}
+TEST(XUnion, Empty) {
+ SampleXUnion input;
+
+ auto expected = std::vector<uint8_t>{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // xunion discriminator + padding
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // num bytes + num handles
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // envelope data is absent
+ };
+ EXPECT_TRUE(ValueToBytes(input, expected));
+}
+
+TEST(XUnion, Int32) {
+ SampleXUnion input;
+ input.set_i(0xdeadbeef);
+
+ auto expected = std::vector<uint8_t>{
+ 0xa5, 0x47, 0xdf, 0x29, 0x00, 0x00, 0x00, 0x00, // xunion discriminator + padding
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // num bytes + num handles
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // envelope data is present
+ 0xef, 0xbe, 0xad, 0xde, 0x00, 0x00, 0x00, 0x00, // envelope content (0xdeadbeef) + padding
+ };
+ EXPECT_TRUE(ValueToBytes(input, expected));
+}
+
+TEST(XUnion, SimpleUnion) {
+ SimpleUnion su;
+ su.set_str("hello");
+
+ SampleXUnion input;
+ input.set_su(std::move(su));
+
+ auto expected = std::vector<uint8_t>{
+ 0x53, 0x76, 0x31, 0x6f, 0x00, 0x00, 0x00, 0x00, // xunion discriminator + padding
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // num bytes + num handles
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // envelope data is present
+ // secondary object 0
+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // union discriminant + padding
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // string size
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // string pointer is present
+ // secondary object 1
+ 'h', 'e', 'l', 'l', 'o', 0x00, 0x00, 0x00, // string: "hello"
+ };
+
+ EXPECT_TRUE(ValueToBytes(input, expected));
+}
+
+TEST(XUnion, SimpleTable) {
+ SimpleTable st;
+ st.set_x(42);
+ st.set_y(67);
+
+ SampleXUnion input;
+ input.set_st(std::move(st));
+
+ auto expected = std::vector<uint8_t>{
+ 0xdd, 0x2c, 0x65, 0x30, 0x00, 0x00, 0x00, 0x00, // xunion discriminator + padding
+ 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // num bytes + num handles
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // envelope data is present
+ // <table data follows>
+ };
+ expected.insert(expected.end(), kSimpleTable_X_42_Y_67.cbegin(),
+ kSimpleTable_X_42_Y_67.cend());
+
+ EXPECT_TRUE(ValueToBytes(input, expected));
+}
+
+TEST(XUnion, SerializeAndDeserializeEmpty) {
+ SampleXUnion input;
+
+ EXPECT_EQ(input, RoundTrip<SampleXUnion>(input));
+}
+
+TEST(XUnion, SerializeAndDeserializeInt32) {
+ SampleXUnion input;
+ input.set_i(0xdeadbeef);
+
+ EXPECT_EQ(input, RoundTrip<SampleXUnion>(input));
+}
+
+TEST(XUnion, SerializeAndDeserializeSimpleUnion) {
+ SimpleUnion su;
+ su.set_str("hello");
+
+ SampleXUnion input;
+ input.set_su(std::move(su));
+
+ EXPECT_EQ(input, RoundTrip<SampleXUnion>(input));
+}
+
+TEST(XUnion, SerializeAndDeserializeSimpleTable) {
+ SimpleTable st;
+ st.set_x(42);
+ st.set_y(67);
+
+ SampleXUnion input;
+ input.set_st(std::move(st));
+
+ EXPECT_EQ(input, RoundTrip<SampleXUnion>(input));
+}
+
+TEST(XUnionContainer, XUnionPointer) {
+ auto xu = std::make_unique<SampleXUnion>();
+ xu->set_i(0xdeadbeef);
+
+ XUnionContainer input;
+ input.before = "before";
+ input.after = "after";
+ input.xu = std::move(xu);
+
+ auto expected = std::vector<uint8_t>{
+ 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // "before" length
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // "before" presence
+
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // xunion is present
+
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // "after" length
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // "before" presence
+
+ // secondary object 1: "before"
+ 'b', 'e', 'f', 'o', 'r', 'e', 0x00, 0x00,
+
+ // secondary object 2: xunion
+ 0xa5, 0x47, 0xdf, 0x29, 0x00, 0x00, 0x00, 0x00, // xunion discriminator + padding
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // num bytes + num handles
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // envelope data is present
+
+ // secondary object 3: xunion content
+ 0xef, 0xbe, 0xad, 0xde, 0x00, 0x00, 0x00, 0x00, // xunion envelope content (0xdeadbeef) + padding
+
+ // secondary object 4: "after"
+ 'a', 'f', 't', 'e', 'r', 0x00, 0x00, 0x00,
+ };
+
+ EXPECT_TRUE(ValueToBytes(input, expected));
+}
+
+TEST(XUnionContainer, SerializeAndDeserialize) {
+ auto xu = std::make_unique<SampleXUnion>();
+ xu->set_i(0xdeadbeef);
+
+ XUnionContainer input;
+ input.before = "before";
+ input.after = "after";
+ input.xu = std::move(xu);
+
+ EXPECT_EQ(input, RoundTrip<XUnionContainer>(input));
+}
+
} // namespace
} // namespace misc
diff --git a/public/lib/fidl/cpp/test/fidl_types.cc b/public/lib/fidl/cpp/test/fidl_types.cc
index bfd7699..b73987d 100644
--- a/public/lib/fidl/cpp/test/fidl_types.cc
+++ b/public/lib/fidl/cpp/test/fidl_types.cc
@@ -28,10 +28,10 @@
alignas(FIDL_ALIGNMENT) char data[6];
};
-static const fidl::FidlField unbounded_nonnullable_string_fields[] = {
- fidl::FidlField(&unbounded_nonnullable_string,
- offsetof(unbounded_nonnullable_string_message_layout,
- inline_struct.string)),
+static const fidl::FidlStructField unbounded_nonnullable_string_fields[] = {
+ fidl::FidlStructField(&unbounded_nonnullable_string,
+ offsetof(unbounded_nonnullable_string_message_layout,
+ inline_struct.string)),
};