[fidl][dart] Support for bits declarations
Change-Id: I7db7c690ab0b0030be67ecb2836d8514bc72ff0a
diff --git a/bin/fidl_bindings_test/fidl/BUILD.gn b/bin/fidl_bindings_test/fidl/BUILD.gn
index bf7364f..75cd6f9 100644
--- a/bin/fidl_bindings_test/fidl/BUILD.gn
+++ b/bin/fidl_bindings_test/fidl/BUILD.gn
@@ -8,7 +8,7 @@
name = "fidl.examples.bindingstest"
sources = [
- "bindings_test.fidl",
- "conformance.fidl",
+ "bindings_test.test.fidl",
+ "conformance.test.fidl",
]
}
diff --git a/bin/fidl_bindings_test/fidl/bindings_test.fidl b/bin/fidl_bindings_test/fidl/bindings_test.test.fidl
similarity index 93%
rename from bin/fidl_bindings_test/fidl/bindings_test.fidl
rename to bin/fidl_bindings_test/fidl/bindings_test.test.fidl
index 9324fc6..af5555b 100644
--- a/bin/fidl_bindings_test/fidl/bindings_test.fidl
+++ b/bin/fidl_bindings_test/fidl/bindings_test.test.fidl
@@ -28,6 +28,12 @@
vector<uint8> baz;
};
+bits ExampleBits {
+ MEMBER_A = 2;
+ MEMBER_B = 4;
+ MEMBER_C = 8;
+};
+
[Discoverable]
protocol TestServer {
OneWayNoArgs();
@@ -49,6 +55,9 @@
OneWayExampleXunion(ExampleXunion value);
ReceivedOneWayExampleXunion() -> (ExampleXunion received);
+ OneWayExampleBits(ExampleBits value);
+ ReceivedOneWayExampleBits() -> (ExampleBits received);
+
SendEmptyEvent();
-> EmptyEvent();
diff --git a/bin/fidl_bindings_test/fidl/conformance.fidl b/bin/fidl_bindings_test/fidl/conformance.test.fidl
similarity index 100%
rename from bin/fidl_bindings_test/fidl/conformance.fidl
rename to bin/fidl_bindings_test/fidl/conformance.test.fidl
diff --git a/bin/fidl_bindings_test/server/lib/main.dart b/bin/fidl_bindings_test/server/lib/main.dart
index b43d11c..d78b859 100644
--- a/bin/fidl_bindings_test/server/lib/main.dart
+++ b/bin/fidl_bindings_test/server/lib/main.dart
@@ -78,6 +78,18 @@
return _oneWayExampleXunion;
}
+ ExampleBits _oneWayExampleBits;
+
+ @override
+ Future<void> oneWayExampleBits(ExampleBits value) async {
+ _oneWayExampleBits = value;
+ }
+
+ @override
+ Future<ExampleBits> receivedOneWayExampleBits() async {
+ return _oneWayExampleBits;
+ }
+
@override
Future<void> twoWayNoArgs() async {}
diff --git a/bin/fidl_bindings_test/test/test/oneway_test.dart b/bin/fidl_bindings_test/test/test/oneway_test.dart
index 7ce68ed..13c1dea 100644
--- a/bin/fidl_bindings_test/test/test/oneway_test.dart
+++ b/bin/fidl_bindings_test/test/test/oneway_test.dart
@@ -104,5 +104,19 @@
expect(received.bar, equals(null));
expect(received.baz, unorderedEquals(primes));
});
+
+ test('bits with single bit', () async {
+ await server.proxy.oneWayExampleBits(ExampleBits.memberB);
+ final received = await server.proxy.receivedOneWayExampleBits();
+ expect(received, equals(ExampleBits.memberB));
+ });
+
+ test('bits with multiple bits', () async {
+ await server.proxy.oneWayExampleBits(
+ ExampleBits.memberB | ExampleBits.memberC);
+ final received = await server.proxy.receivedOneWayExampleBits();
+ expect(received, equals(
+ ExampleBits.memberB | ExampleBits.memberC));
+ });
});
}
diff --git a/bin/fidl_bindings_test/test/test/tostring_test.dart b/bin/fidl_bindings_test/test/test/tostring_test.dart
new file mode 100644
index 0000000..94e5a6d
--- /dev/null
+++ b/bin/fidl_bindings_test/test/test/tostring_test.dart
@@ -0,0 +1,20 @@
+// Copyright 2019 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.
+
+import 'package:test/test.dart';
+import 'package:fidl_fidl_examples_bindingstest/fidl_async.dart';
+
+void main() {
+ print('toString-test');
+ group('bits', () {
+ test('single bit', () {
+ expect(ExampleBits.memberC.toString(), equals(r'ExampleBits.memberC'));
+ });
+ test('multiple bits', () {
+ expect(
+ (ExampleBits.memberC | ExampleBits.memberA).toString(),
+ equals(r'ExampleBits.memberA | ExampleBits.memberC'));
+ });
+ });
+}
diff --git a/bin/fidlgen_dart/backend/generator.go b/bin/fidlgen_dart/backend/generator.go
index 6163457..ab14300 100644
--- a/bin/fidlgen_dart/backend/generator.go
+++ b/bin/fidlgen_dart/backend/generator.go
@@ -61,6 +61,7 @@
tmpls := template.New("DartTemplates")
template.Must(tmpls.Parse(templates.Const))
template.Must(tmpls.Parse(templates.Enum))
+ template.Must(tmpls.Parse(templates.Bits))
template.Must(tmpls.Parse(templates.Interface))
template.Must(tmpls.Parse(templates.Library))
template.Must(tmpls.Parse(templates.Struct))
diff --git a/bin/fidlgen_dart/backend/ir/ir.go b/bin/fidlgen_dart/backend/ir/ir.go
index 72769ff..3f1c37f 100644
--- a/bin/fidlgen_dart/backend/ir/ir.go
+++ b/bin/fidlgen_dart/backend/ir/ir.go
@@ -54,6 +54,22 @@
Documented
}
+// Bits represents a bits declaration.
+type Bits struct {
+ Name string
+ Members []BitsMember
+ TypeSymbol string
+ TypeExpr string
+ Documented
+}
+
+// BitsMember represents a member of a bits declaration.
+type BitsMember struct {
+ Name string
+ Value string
+ Documented
+}
+
// Union represents a union declaration.
type Union struct {
Name string
@@ -201,6 +217,7 @@
Imports []Import
Consts []Const
Enums []Enum
+ Bits []Bits
Interfaces []Interface
Structs []Struct
Tables []Table
@@ -211,8 +228,10 @@
type context map[string]bool
var (
+ // Name of a bits member
+ bitsMemberContext = make(context)
// Name of an enum member
- enumMemberContext context = make(context)
+ enumMemberContext = make(context)
// Name of a struct member
structMemberContext = make(context)
// Name of a table member
@@ -233,9 +252,12 @@
)
func init() {
- var allContexts = []context{enumMemberContext, structMemberContext, tableMemberContext,
- unionMemberContext, unionMemberTagContext, constantContext, declarationContext,
- methodContext, parameterContext}
+ var allContexts = []context{
+ enumMemberContext, structMemberContext, tableMemberContext,
+ unionMemberContext, unionMemberTagContext, constantContext,
+ declarationContext, methodContext, parameterContext,
+ bitsMemberContext,
+ }
var reservedWords = map[string][]context{
"assert": allContexts,
@@ -251,7 +273,7 @@
"default": allContexts,
"do": allContexts,
"double": []context{structMemberContext, tableMemberContext},
- "dynamic": []context{enumMemberContext, methodContext, unionMemberContext, constantContext, tableMemberContext, structMemberContext},
+ "dynamic": []context{bitsMemberContext, enumMemberContext, methodContext, unionMemberContext, constantContext, tableMemberContext, structMemberContext},
"else": allContexts,
"enum": allContexts,
"extends": allContexts,
@@ -259,13 +281,13 @@
"final": allContexts,
"finally": allContexts,
"for": allContexts,
- "hashCode": []context{methodContext, enumMemberContext, unionMemberContext, structMemberContext, tableMemberContext},
+ "hashCode": []context{methodContext, bitsMemberContext, enumMemberContext, unionMemberContext, structMemberContext, tableMemberContext},
"noSuchMethod": []context{methodContext, enumMemberContext, unionMemberContext, structMemberContext, tableMemberContext},
"runtimeType": []context{methodContext, enumMemberContext, unionMemberContext, structMemberContext, tableMemberContext},
"index": []context{unionMemberTagContext},
"if": allContexts,
"in": allContexts,
- "int": []context{enumMemberContext, methodContext, unionMemberContext, constantContext, tableMemberContext, structMemberContext},
+ "int": []context{bitsMemberContext, enumMemberContext, methodContext, unionMemberContext, constantContext, tableMemberContext, structMemberContext},
"is": allContexts,
"List": []context{declarationContext},
"Map": []context{declarationContext},
@@ -282,7 +304,7 @@
"switch": allContexts,
"this": allContexts,
"throw": allContexts,
- "toString": []context{methodContext, enumMemberContext, structMemberContext, tableMemberContext, unionMemberContext},
+ "toString": []context{methodContext, bitsMemberContext, enumMemberContext, structMemberContext, tableMemberContext, unionMemberContext},
"true": allContexts,
"try": allContexts,
"values": []context{unionMemberTagContext},
@@ -690,6 +712,8 @@
fallthrough
case types.EnumDeclType:
fallthrough
+ case types.BitsDeclType:
+ fallthrough
case types.StructDeclType:
fallthrough
case types.TableDeclType:
@@ -774,6 +798,29 @@
return e
}
+func (c *compiler) compileBits(val types.Bits) Bits {
+ ci := types.ParseCompoundIdentifier(val.Name)
+ n := c.compileUpperCamelCompoundIdentifier(ci, "", declarationContext)
+ if val.Type.Kind != types.PrimitiveType {
+ panic("unexpected, only primitives are allowed for bits declarations")
+ }
+ subtype := val.Type.PrimitiveSubtype
+ b := Bits{
+ Name: n,
+ TypeSymbol: c.typeSymbolForCompoundIdentifier(ci),
+ TypeExpr: fmt.Sprintf("$fidl.BitsType<%s>(type: %s, ctor: %s._ctor)", n, typeExprForPrimitiveSubtype(subtype), n),
+ Documented: docString(val),
+ }
+ for _, v := range val.Members {
+ b.Members = append(b.Members, BitsMember{
+ Name: c.compileLowerCamelIdentifier(v.Name, bitsMemberContext),
+ Value: c.compileConstant(v.Value, nil),
+ Documented: docString(v),
+ })
+ }
+ return b
+}
+
func (c *compiler) compileParameter(paramName types.Identifier, paramType types.Type, offset int) Parameter {
var (
t = c.compileType(paramType)
@@ -1138,6 +1185,10 @@
root.Enums = append(root.Enums, c.compileEnum(v))
}
+ for _, v := range r.Bits {
+ root.Bits = append(root.Bits, c.compileBits(v))
+ }
+
for _, v := range r.Interfaces {
root.Interfaces = append(root.Interfaces, c.compileInterface(v))
}
diff --git a/bin/fidlgen_dart/backend/templates/bits.tmpl.go b/bin/fidlgen_dart/backend/templates/bits.tmpl.go
new file mode 100644
index 0000000..03d620c
--- /dev/null
+++ b/bin/fidlgen_dart/backend/templates/bits.tmpl.go
@@ -0,0 +1,53 @@
+// Copyright 2019 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
+
+// Bits is the template for bits declarations.
+const Bits = `
+{{- define "BitsDeclaration" -}}
+{{- range .Doc }}
+///{{ . -}}
+{{- end }}
+class {{ .Name }} extends $fidl.Bits {
+{{- range .Members }}
+ {{- range .Doc }}
+ ///{{ . -}}
+ {{- end }}
+ static const {{ $.Name }} {{ .Name }} = {{ $.Name }}._({{ .Value }});
+{{- end }}
+
+ const {{ .Name }}._(this.$value);
+
+ {{ .Name }} operator |({{ .Name }} other) {
+ return {{ .Name }}._($value | other.$value);
+ }
+
+ @override
+ final int $value;
+
+ @override
+ String toString() {
+ if ($value == null) {
+ return null;
+ }
+ List<String> parts = [];
+{{- range .Members }}
+ if ($value & {{ .Value }} != 0) {
+ parts.add(r'{{ $.Name }}.{{ .Name }}');
+ }
+{{- end }}
+ if (parts.isEmpty) {
+ return r'{{ $.Name }}.$none';
+ } else {
+ return parts.join(" | ");
+ }
+ }
+
+ static {{ .Name }} _ctor(int v) => {{ .Name }}._(v);
+}
+
+const $fidl.BitsType<{{ .Name }}> {{ .TypeSymbol }} = {{ .TypeExpr }};
+{{ end }}
+`
diff --git a/bin/fidlgen_dart/backend/templates/library.tmpl.go b/bin/fidlgen_dart/backend/templates/library.tmpl.go
index f7a410b..ffe05ec 100644
--- a/bin/fidlgen_dart/backend/templates/library.tmpl.go
+++ b/bin/fidlgen_dart/backend/templates/library.tmpl.go
@@ -59,6 +59,9 @@
{{ range $enum := .Enums -}}
{{ template "EnumDeclaration" $enum }}
{{ end -}}
+{{ range $bits := .Bits -}}
+{{ template "BitsDeclaration" $bits }}
+{{ end -}}
{{ range $union := .Unions -}}
{{ template "UnionDeclaration" $union }}
{{ end -}}
@@ -143,6 +146,9 @@
{{ range $enum := .Enums -}}
{{ template "EnumDeclaration" $enum }}
{{ end -}}
+{{ range $bits := .Bits -}}
+{{ template "BitsDeclaration" $bits }}
+{{ end -}}
{{ range $union := .Unions -}}
{{ template "UnionDeclaration" $union }}
{{ end -}}
diff --git a/bin/fidlgen_dart/goldens/bits.test.test.fidl.json_async.dart.golden b/bin/fidlgen_dart/goldens/bits.test.test.fidl.json_async.dart.golden
index e541d9b..613eabd 100644
--- a/bin/fidlgen_dart/goldens/bits.test.test.fidl.json_async.dart.golden
+++ b/bin/fidlgen_dart/goldens/bits.test.test.fidl.json_async.dart.golden
@@ -45,5 +45,43 @@
// ignore_for_file: unnecessary_lambdas
// ignore_for_file: comment_references
+class MyBits extends $fidl.Bits {
+ static const MyBits myFirstBit = MyBits._(1);
+ static const MyBits myOtherBit = MyBits._(2);
+
+ const MyBits._(this.$value);
+
+ MyBits operator |(MyBits other) {
+ return MyBits._($value | other.$value);
+ }
+
+ @override
+ final int $value;
+
+ @override
+ String toString() {
+ if ($value == null) {
+ return null;
+ }
+ List<String> parts = [];
+ if ($value & 1 != 0) {
+ parts.add(r'MyBits.myFirstBit');
+ }
+ if ($value & 2 != 0) {
+ parts.add(r'MyBits.myOtherBit');
+ }
+ if (parts.isEmpty) {
+ return r'MyBits.$none';
+ } else {
+ return parts.join(" | ");
+ }
+ }
+
+ static MyBits _ctor(int v) => MyBits._(v);
+}
+
+const $fidl.BitsType<MyBits> kMyBits_Type =
+ $fidl.BitsType<MyBits>(type: $fidl.Uint32Type(), ctor: MyBits._ctor);
+
// ignore: unused_element, avoid_private_typedef_functions
typedef _VoidCallback = void Function();
diff --git a/bin/fidlgen_dart/goldens/bits.test.test.fidl.json_sync.dart.golden b/bin/fidlgen_dart/goldens/bits.test.test.fidl.json_sync.dart.golden
index 2750514..96f4d7d 100644
--- a/bin/fidlgen_dart/goldens/bits.test.test.fidl.json_sync.dart.golden
+++ b/bin/fidlgen_dart/goldens/bits.test.test.fidl.json_sync.dart.golden
@@ -39,3 +39,41 @@
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: prefer_generic_function_type_aliases
// ignore_for_file: prefer_equal_for_default_values
+
+class MyBits extends $fidl.Bits {
+ static const MyBits myFirstBit = MyBits._(1);
+ static const MyBits myOtherBit = MyBits._(2);
+
+ const MyBits._(this.$value);
+
+ MyBits operator |(MyBits other) {
+ return MyBits._($value | other.$value);
+ }
+
+ @override
+ final int $value;
+
+ @override
+ String toString() {
+ if ($value == null) {
+ return null;
+ }
+ List<String> parts = [];
+ if ($value & 1 != 0) {
+ parts.add(r'MyBits.myFirstBit');
+ }
+ if ($value & 2 != 0) {
+ parts.add(r'MyBits.myOtherBit');
+ }
+ if (parts.isEmpty) {
+ return r'MyBits.$none';
+ } else {
+ return parts.join(" | ");
+ }
+ }
+
+ static MyBits _ctor(int v) => MyBits._(v);
+}
+
+const $fidl.BitsType<MyBits> kMyBits_Type =
+ $fidl.BitsType<MyBits>(type: $fidl.Uint32Type(), ctor: MyBits._ctor);
diff --git a/bin/fidlgen_dart/goldens/tables.test.fidl.json b/bin/fidlgen_dart/goldens/tables.test.fidl.json
index 4a72da7..a61086a 100644
--- a/bin/fidlgen_dart/goldens/tables.test.fidl.json
+++ b/bin/fidlgen_dart/goldens/tables.test.fidl.json
@@ -49,15 +49,30 @@
},
{
"ordinal": 2,
- "reserved": true
+ "reserved": true,
+ "location": {
+ "filename": "garnet/go/src/fidl/compiler/backend/typestest/tables.test.fidl",
+ "line": 8,
+ "column": 5
+ }
},
{
"ordinal": 3,
- "reserved": true
+ "reserved": true,
+ "location": {
+ "filename": "garnet/go/src/fidl/compiler/backend/typestest/tables.test.fidl",
+ "line": 9,
+ "column": 5
+ }
},
{
"ordinal": 4,
- "reserved": true
+ "reserved": true,
+ "location": {
+ "filename": "garnet/go/src/fidl/compiler/backend/typestest/tables.test.fidl",
+ "line": 10,
+ "column": 5
+ }
},
{
"ordinal": 5,
@@ -111,7 +126,12 @@
},
{
"ordinal": 2,
- "reserved": true
+ "reserved": true,
+ "location": {
+ "filename": "garnet/go/src/fidl/compiler/backend/typestest/tables.test.fidl",
+ "line": 16,
+ "column": 5
+ }
}
],
"size": 16,
@@ -147,15 +167,30 @@
},
{
"ordinal": 2,
- "reserved": true
+ "reserved": true,
+ "location": {
+ "filename": "garnet/go/src/fidl/compiler/backend/typestest/tables.test.fidl",
+ "line": 21,
+ "column": 5
+ }
},
{
"ordinal": 3,
- "reserved": true
+ "reserved": true,
+ "location": {
+ "filename": "garnet/go/src/fidl/compiler/backend/typestest/tables.test.fidl",
+ "line": 22,
+ "column": 5
+ }
},
{
"ordinal": 4,
- "reserved": true
+ "reserved": true,
+ "location": {
+ "filename": "garnet/go/src/fidl/compiler/backend/typestest/tables.test.fidl",
+ "line": 23,
+ "column": 5
+ }
},
{
"ordinal": 5,
@@ -195,7 +230,12 @@
},
{
"ordinal": 7,
- "reserved": true
+ "reserved": true,
+ "location": {
+ "filename": "garnet/go/src/fidl/compiler/backend/typestest/tables.test.fidl",
+ "line": 26,
+ "column": 5
+ }
}
],
"size": 16,
diff --git a/public/dart/fidl/BUILD.gn b/public/dart/fidl/BUILD.gn
index a9139f6..e2fa12c 100644
--- a/public/dart/fidl/BUILD.gn
+++ b/public/dart/fidl/BUILD.gn
@@ -13,6 +13,7 @@
sources = [
"fidl.dart",
+ "src/bits.dart",
"src/codec.dart",
"src/enum.dart",
"src/error.dart",
diff --git a/public/dart/fidl/lib/fidl.dart b/public/dart/fidl/lib/fidl.dart
index 90bf1b0..d569fe0 100644
--- a/public/dart/fidl/lib/fidl.dart
+++ b/public/dart/fidl/lib/fidl.dart
@@ -7,6 +7,7 @@
/// classes implemented by generated FIDL code. It is often used directly in
/// author code to retrieve type definitions (e.g. InterfaceHandle,
/// InterfaceRequest, etc.) for interacting with certain FIDL services.
+export 'src/bits.dart';
export 'src/codec.dart';
export 'src/enum.dart';
export 'src/error.dart';
diff --git a/public/dart/fidl/lib/src/bits.dart b/public/dart/fidl/lib/src/bits.dart
new file mode 100644
index 0000000..6ac12e5
--- /dev/null
+++ b/public/dart/fidl/lib/src/bits.dart
@@ -0,0 +1,26 @@
+// Copyright 2019 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.
+
+// ignore_for_file: public_member_api_docs
+
+// Bits represents a bit field, i.e. no bit set, one bit set, or multiple bit
+// set.
+abstract class Bits {
+ const Bits();
+
+ int get $value;
+
+ @override
+ bool operator ==(dynamic other) {
+ if (other is Bits) {
+ return $value == other.$value;
+ }
+ return false;
+ }
+
+ @override
+ int get hashCode => $value.hashCode;
+}
+
+typedef BitsFactory<T> = T Function(int value);
diff --git a/public/dart/fidl/lib/src/types.dart b/public/dart/fidl/lib/src/types.dart
index 7c732ec..4bf9b55 100644
--- a/public/dart/fidl/lib/src/types.dart
+++ b/public/dart/fidl/lib/src/types.dart
@@ -7,6 +7,7 @@
import 'package:zircon/zircon.dart';
+import 'bits.dart';
import 'codec.dart';
import 'enum.dart';
import 'error.dart';
@@ -963,6 +964,29 @@
}
}
+class BitsType<T extends Bits> extends FidlType<T> {
+ const BitsType({
+ this.type,
+ this.ctor,
+ });
+
+ final FidlType<int> type;
+ final BitsFactory<T> ctor;
+
+ @override
+ int get encodedSize => type.encodedSize;
+
+ @override
+ void encode(Encoder encoder, T value, int offset) {
+ type.encode(encoder, value.$value, offset);
+ }
+
+ @override
+ T decode(Decoder decoder, int offset) {
+ return ctor(type.decode(decoder, offset));
+ }
+}
+
class MethodType extends FidlType<Null> {
const MethodType({
this.request,