Version 2.17.0-103.0.dev
Merge commit '49d7f5056f8934922ab5cd3a7635a1748f6db052' into 'dev'
diff --git a/pkg/_fe_analyzer_shared/benchmark/macros/serialization_benchmark.dart b/pkg/_fe_analyzer_shared/benchmark/macros/serialization_benchmark.dart
new file mode 100644
index 0000000..550e718
--- /dev/null
+++ b/pkg/_fe_analyzer_shared/benchmark/macros/serialization_benchmark.dart
@@ -0,0 +1,311 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:convert';
+import 'dart:io';
+import 'dart:isolate';
+import 'dart:typed_data';
+
+import 'package:_fe_analyzer_shared/src/macros/executor_shared/serialization.dart';
+
+void main() async {
+ for (var serializationMode in [
+ SerializationMode.jsonClient,
+ SerializationMode.byteDataClient
+ ]) {
+ await withSerializationMode(serializationMode, () async {
+ await _isolateSpawnBenchmarks();
+ await _isolateSpawnUriBenchmarks();
+ await _separateProcessBenchmarks();
+ });
+ }
+}
+
+Future<void> _isolateSpawnBenchmarks() async {
+ void Function(SendPort) childIsolateFn(SerializationMode mode) =>
+ (SendPort sendPort) => withSerializationMode(mode, () {
+ var isolateReceivePort = ReceivePort();
+ isolateReceivePort.listen((data) {
+ deserialize(data);
+ var result = serialize();
+ result = result is Uint8List
+ ? TransferableTypedData.fromList([result])
+ : result;
+ sendPort.send(result);
+ });
+ sendPort.send(isolateReceivePort.sendPort);
+ });
+
+ Completer? responseCompleter;
+ late SendPort sendPort;
+
+ var receivePort = ReceivePort();
+
+ var isolate = await Isolate.spawn(
+ childIsolateFn(serializationMode), receivePort.sendPort);
+
+ final sendPortCompleter = Completer<SendPort>();
+ receivePort.listen((data) {
+ if (!sendPortCompleter.isCompleted) {
+ sendPortCompleter.complete(data);
+ } else {
+ responseCompleter!.complete(data);
+ }
+ });
+ sendPort = await sendPortCompleter.future;
+
+ // warmup
+ for (var i = 0; i < 100; i++) {
+ responseCompleter = Completer();
+ var result = serialize();
+ result =
+ result is Uint8List ? TransferableTypedData.fromList([result]) : result;
+ sendPort.send(result);
+ deserialize(await responseCompleter.future);
+ }
+ // measure
+ var watch = Stopwatch()..start();
+ for (var i = 0; i < 100; i++) {
+ responseCompleter = Completer();
+ var result = serialize();
+ result =
+ result is Uint8List ? TransferableTypedData.fromList([result]) : result;
+ sendPort.send(result);
+ deserialize(await responseCompleter.future);
+ }
+ print('Isolate.spawn + $serializationMode: ${watch.elapsed}');
+
+ receivePort.close();
+ isolate.kill();
+}
+
+Future<void> _isolateSpawnUriBenchmarks() async {
+ Completer? responseCompleter;
+ late SendPort sendPort;
+
+ var receivePort = ReceivePort();
+
+ var isolate = await Isolate.spawnUri(
+ Uri.dataFromString(childProgram(serializationMode)),
+ [],
+ receivePort.sendPort);
+
+ final sendPortCompleter = Completer<SendPort>();
+ receivePort.listen((data) {
+ if (!sendPortCompleter.isCompleted) {
+ sendPortCompleter.complete(data);
+ } else {
+ responseCompleter!.complete(data);
+ }
+ });
+ sendPort = await sendPortCompleter.future;
+
+ // warmup
+ for (var i = 0; i < 100; i++) {
+ responseCompleter = Completer();
+ var result = serialize();
+ result =
+ result is Uint8List ? TransferableTypedData.fromList([result]) : result;
+ sendPort.send(result);
+ deserialize(await responseCompleter.future);
+ }
+ // measure
+ var watch = Stopwatch()..start();
+ for (var i = 0; i < 100; i++) {
+ responseCompleter = Completer();
+ var result = serialize();
+ result =
+ result is Uint8List ? TransferableTypedData.fromList([result]) : result;
+ sendPort.send(result);
+ deserialize(await responseCompleter.future);
+ }
+ print('Isolate.spawnUri + $serializationMode: ${watch.elapsed}');
+
+ receivePort.close();
+ isolate.kill();
+}
+
+Future<void> _separateProcessBenchmarks() async {
+ Completer? responseCompleter;
+
+ var tmpDir = Directory.systemTemp.createTempSync('serialize_bench');
+ try {
+ var file = File(tmpDir.uri.resolve('main.dart').toFilePath());
+ file.writeAsStringSync(childProgram(serializationMode));
+ var process = await Process.start(Platform.resolvedExecutable, [
+ '--packages=' + (await Isolate.packageConfig)!.toFilePath(),
+ file.path,
+ ]);
+
+ var listeners = <StreamSubscription>[
+ process.stderr.listen((event) {
+ print('stderr: ${utf8.decode(event)}');
+ }),
+ process.stdout.listen((data) {
+ responseCompleter!.complete(data);
+ }),
+ ];
+
+ // warmup
+ for (var i = 0; i < 100; i++) {
+ responseCompleter = Completer();
+ var result = serialize();
+ if (result is List<int>) {
+ process.stdin.add(result);
+ } else {
+ process.stdin.writeln(jsonEncode(result));
+ }
+ deserialize(await responseCompleter.future);
+ }
+ // measure
+ var watch = Stopwatch()..start();
+ for (var i = 0; i < 100; i++) {
+ responseCompleter = Completer();
+ var result = serialize();
+ if (result is List<int>) {
+ process.stdin.add(result);
+ } else {
+ process.stdin.writeln(jsonEncode(result));
+ }
+ deserialize(await responseCompleter.future);
+ }
+ print('Separate process + $serializationMode: ${watch.elapsed}');
+
+ listeners.forEach((l) => l.cancel());
+ process.kill();
+ } catch (e, s) {
+ print('Error running benchmark \n$e\n\n$s');
+ } finally {
+ tmpDir.deleteSync(recursive: true);
+ }
+}
+
+String childProgram(SerializationMode mode) => '''
+ import 'dart:convert';
+ import 'dart:io';
+ import 'dart:isolate';
+ import 'dart:typed_data';
+
+ import 'package:_fe_analyzer_shared/src/macros/executor_shared/serialization.dart';
+
+ void main(_, [SendPort? sendPort]) {
+ var mode = $mode;
+ withSerializationMode(mode, () {
+ if (sendPort != null) {
+ var isolateReceivePort = ReceivePort();
+ isolateReceivePort.listen((data) {
+ deserialize(data);
+ var result = serialize();
+ result = result is Uint8List
+ ? TransferableTypedData.fromList([result])
+ : result;
+ sendPort.send(result);
+ });
+ sendPort.send(isolateReceivePort.sendPort);
+ } else {
+ // We allow one empty line to work around some weird data.
+ var allowEmpty = true;
+ stdin.listen((data) {
+ if (mode == SerializationMode.jsonClient || mode == SerializationMode.jsonServer) {
+ var json = utf8.decode(data).trimRight();
+ // On exit we tend to get extra empty lines sometimes?
+ if (json.isEmpty && allowEmpty) {
+ allowEmpty = false;
+ return;
+ }
+ deserialize(jsonDecode(json));
+ stdout.write(jsonEncode(serialize()));
+ } else {
+ deserialize(data);
+ stdout.add(serialize() as List<int>);
+ }
+ });
+ }
+ });
+ }
+
+ Object? serialize() {
+ var serializer = serializerFactory();
+ for (var i = 0; i < 100; i++) {
+ serializer.addInt(i * 100);
+ serializer.addString('foo' * i);
+ serializer.addBool(i % 2 == 0);
+ serializer.startList();
+ for (var j = 0; j < 10; j++) {
+ serializer.addDouble(i * 5);
+ }
+ serializer.endList();
+ serializer.addNull();
+ }
+ return serializer.result;
+ }
+
+ void deserialize(Object? result) {
+ result = result is TransferableTypedData
+ ? result.materialize().asUint8List()
+ : result;
+ var deserializer = deserializerFactory(result);
+ while (deserializer.moveNext()) {
+ deserializer
+ ..expectInt()
+ ..moveNext()
+ ..expectString()
+ ..moveNext()
+ ..expectBool()
+ ..moveNext()
+ ..expectList();
+ while (deserializer.moveNext()) {
+ deserializer.expectDouble();
+ }
+ deserializer
+ ..moveNext()
+ ..checkNull();
+ }
+ }''';
+
+Object? serialize() {
+ var serializer = serializerFactory();
+ for (var i = -50; i < 50; i++) {
+ serializer.addInt(i % 2 * 100);
+ serializer.addString('foo' * i);
+ serializer.addBool(i < 0);
+ serializer.startList();
+ for (var j = 0.0; j < 10; j++) {
+ serializer.addDouble(i * j);
+ }
+ serializer.endList();
+ serializer.addNull();
+ }
+ return serializer.result;
+}
+
+void deserialize(Object? result) {
+ result = result is TransferableTypedData
+ ? result.materialize().asUint8List()
+ : result;
+ if (serializationMode == SerializationMode.jsonClient ||
+ serializationMode == SerializationMode.jsonServer) {
+ if (result is List<int>) {
+ result = jsonDecode(utf8.decode(result));
+ }
+ }
+ var deserializer = deserializerFactory(result);
+ while (deserializer.moveNext()) {
+ deserializer
+ ..expectInt()
+ ..moveNext()
+ ..expectString()
+ ..moveNext()
+ ..expectBool()
+ ..moveNext()
+ ..expectList();
+ while (deserializer.moveNext()) {
+ deserializer.expectDouble();
+ }
+ deserializer
+ ..moveNext()
+ ..checkNull();
+ }
+}
diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/bootstrap.dart b/pkg/_fe_analyzer_shared/lib/src/macros/bootstrap.dart
index 635c67b..f423fcf 100644
--- a/pkg/_fe_analyzer_shared/lib/src/macros/bootstrap.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/macros/bootstrap.dart
@@ -55,17 +55,18 @@
/// Local function that sends requests and returns responses using [sendPort].
Future<Response> sendRequest(Request request) => _sendRequest(request, sendPort);
- withSerializationMode(SerializationMode.client, () {
+ /// TODO: More directly support customizable serialization types.
+ withSerializationMode(SerializationMode.jsonClient, () {
ReceivePort receivePort = new ReceivePort();
sendPort.send(receivePort.sendPort);
receivePort.listen((message) async {
- var deserializer = JsonDeserializer(message as Iterable<Object?>)
+ var deserializer = deserializerFactory(message)
..moveNext();
- int zoneId = deserializer.expectNum();
+ int zoneId = deserializer.expectInt();
deserializer..moveNext();
- var type = MessageType.values[deserializer.expectNum()];
- var serializer = JsonSerializer();
+ var type = MessageType.values[deserializer.expectInt()];
+ var serializer = serializerFactory();
switch (type) {
case MessageType.instantiateMacroRequest:
var request = new InstantiateMacroRequest.deserialize(deserializer, zoneId);
@@ -248,8 +249,8 @@
Future<Response> _sendRequest(Request request, SendPort sendPort) {
Completer<Response> completer = Completer();
_responseCompleters[request.id] = completer;
- JsonSerializer serializer = JsonSerializer();
- serializer.addNum(request.serializationZoneId);
+ Serializer serializer = serializerFactory();
+ serializer.addInt(request.serializationZoneId);
request.serialize(serializer);
sendPort.send(serializer.result);
return completer.future;
diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/executor.dart b/pkg/_fe_analyzer_shared/lib/src/macros/executor.dart
index 7238af4..94b8930 100644
--- a/pkg/_fe_analyzer_shared/lib/src/macros/executor.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/macros/executor.dart
@@ -132,7 +132,7 @@
static Object? _deserializeArg(Deserializer deserializer,
{bool alreadyMoved = false}) {
if (!alreadyMoved) deserializer.moveNext();
- _ArgumentKind kind = _ArgumentKind.values[deserializer.expectNum()];
+ _ArgumentKind kind = _ArgumentKind.values[deserializer.expectInt()];
switch (kind) {
case _ArgumentKind.nil:
return null;
@@ -142,9 +142,12 @@
case _ArgumentKind.bool:
deserializer.moveNext();
return deserializer.expectBool();
- case _ArgumentKind.num:
+ case _ArgumentKind.int:
deserializer.moveNext();
- return deserializer.expectNum();
+ return deserializer.expectInt();
+ case _ArgumentKind.double:
+ deserializer.moveNext();
+ return deserializer.expectDouble();
case _ArgumentKind.list:
deserializer.moveNext();
deserializer.expectList();
@@ -184,22 +187,26 @@
static void _serializeArg(Object? arg, Serializer serializer) {
if (arg == null) {
- serializer.addNum(_ArgumentKind.nil.index);
+ serializer.addInt(_ArgumentKind.nil.index);
} else if (arg is String) {
serializer
- ..addNum(_ArgumentKind.string.index)
+ ..addInt(_ArgumentKind.string.index)
..addString(arg);
- } else if (arg is num) {
+ } else if (arg is int) {
serializer
- ..addNum(_ArgumentKind.num.index)
- ..addNum(arg);
+ ..addInt(_ArgumentKind.int.index)
+ ..addInt(arg);
+ } else if (arg is double) {
+ serializer
+ ..addInt(_ArgumentKind.double.index)
+ ..addDouble(arg);
} else if (arg is bool) {
serializer
- ..addNum(_ArgumentKind.bool.index)
+ ..addInt(_ArgumentKind.bool.index)
..addBool(arg);
} else if (arg is List) {
serializer
- ..addNum(_ArgumentKind.list.index)
+ ..addInt(_ArgumentKind.list.index)
..startList();
for (Object? item in arg) {
_serializeArg(item, serializer);
@@ -207,7 +214,7 @@
serializer.endList();
} else if (arg is Map) {
serializer
- ..addNum(_ArgumentKind.map.index)
+ ..addInt(_ArgumentKind.map.index)
..startList();
for (MapEntry<Object?, Object?> entry in arg.entries) {
_serializeArg(entry.key, serializer);
@@ -311,4 +318,4 @@
}
/// Used for serializing and deserializing arguments.
-enum _ArgumentKind { string, bool, num, list, map, nil }
+enum _ArgumentKind { string, bool, double, int, list, map, nil }
diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/introspection_impls.dart b/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/introspection_impls.dart
index baf884d..ebf86e2 100644
--- a/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/introspection_impls.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/introspection_impls.dart
@@ -19,9 +19,7 @@
void serialize(Serializer serializer) {
super.serialize(serializer);
// Client side we don't encode anything but the ID.
- if (serializationMode == SerializationMode.client) {
- return;
- }
+ if (serializationMode.isClient) return;
serializer.addString(name);
}
@@ -37,9 +35,7 @@
void serialize(Serializer serializer) {
super.serialize(serializer);
// Client side we don't encode anything but the ID.
- if (serializationMode == SerializationMode.client) {
- return;
- }
+ if (serializationMode.isClient) return;
serializer.addBool(isNullable);
}
@@ -76,9 +72,7 @@
void serialize(Serializer serializer) {
super.serialize(serializer);
// Client side we don't encode anything but the ID.
- if (serializationMode == SerializationMode.client) {
- return;
- }
+ if (serializationMode.isClient) return;
identifier.serialize(serializer);
serializer.startList();
@@ -138,9 +132,7 @@
void serialize(Serializer serializer) {
super.serialize(serializer);
// Client side we don't encode anything but the ID.
- if (serializationMode == SerializationMode.client) {
- return;
- }
+ if (serializationMode.isClient) return;
returnType.serialize(serializer);
@@ -173,9 +165,7 @@
void serialize(Serializer serializer) {
super.serialize(serializer);
// Client side we don't encode anything but the ID.
- if (serializationMode == SerializationMode.client) {
- return;
- }
+ if (serializationMode.isClient) return;
identifier.serialize(serializer);
}
@@ -207,9 +197,7 @@
void serialize(Serializer serializer) {
super.serialize(serializer);
// Client side we don't encode anything but the ID.
- if (serializationMode == SerializationMode.client) {
- return;
- }
+ if (serializationMode.isClient) return;
serializer.addBool(isNamed);
serializer.addBool(isRequired);
@@ -241,9 +229,7 @@
void serialize(Serializer serializer) {
super.serialize(serializer);
// Client side we don't encode anything but the ID.
- if (serializationMode == SerializationMode.client) {
- return;
- }
+ if (serializationMode.isClient) return;
TypeAnnotationImpl? bound = this.bound;
if (bound == null) {
@@ -308,9 +294,7 @@
void serialize(Serializer serializer) {
super.serialize(serializer);
// Client side we don't encode anything but the ID.
- if (serializationMode == SerializationMode.client) {
- return;
- }
+ if (serializationMode.isClient) return;
serializer
..addBool(isAbstract)
@@ -380,9 +364,7 @@
void serialize(Serializer serializer) {
super.serialize(serializer);
// Client side we don't encode anything but the ID.
- if (serializationMode == SerializationMode.client) {
- return;
- }
+ if (serializationMode.isClient) return;
definingClass.serialize(serializer);
}
@@ -433,9 +415,7 @@
void serialize(Serializer serializer) {
super.serialize(serializer);
// Client side we don't encode anything but the ID.
- if (serializationMode == SerializationMode.client) {
- return;
- }
+ if (serializationMode.isClient) return;
serializer.addBool(isFactory);
}
@@ -471,9 +451,7 @@
void serialize(Serializer serializer) {
super.serialize(serializer);
// Client side we don't encode anything but the ID.
- if (serializationMode == SerializationMode.client) {
- return;
- }
+ if (serializationMode.isClient) return;
serializer
..addBool(isExternal)
@@ -513,9 +491,7 @@
void serialize(Serializer serializer) {
super.serialize(serializer);
// Client side we don't encode anything but the ID.
- if (serializationMode == SerializationMode.client) {
- return;
- }
+ if (serializationMode.isClient) return;
definingClass.serialize(serializer);
}
@@ -535,9 +511,7 @@
void serialize(Serializer serializer) {
super.serialize(serializer);
// Client side we don't encode anything but the ID.
- if (serializationMode == SerializationMode.client) {
- return;
- }
+ if (serializationMode.isClient) return;
serializer..startList();
for (TypeParameterDeclarationImpl param in typeParameters) {
@@ -585,9 +559,7 @@
void serialize(Serializer serializer) {
super.serialize(serializer);
// Client side we don't encode anything but the ID.
- if (serializationMode == SerializationMode.client) {
- return;
- }
+ if (serializationMode.isClient) return;
serializer.startList();
for (TypeAnnotationImpl interface in interfaces) {
@@ -628,9 +600,7 @@
void serialize(Serializer serializer) {
super.serialize(serializer);
// Client side we don't encode anything but the ID.
- if (serializationMode == SerializationMode.client) {
- return;
- }
+ if (serializationMode.isClient) return;
aliasedType.serialize(serializer);
}
diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/protocol.dart b/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/protocol.dart
index f3a3bf7..50a6743 100644
--- a/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/protocol.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/protocol.dart
@@ -28,13 +28,13 @@
/// The [serializationZoneId] is a part of the header and needs to be parsed
/// before deserializing objects, and then passed in here.
Request.deserialize(Deserializer deserializer, this.serializationZoneId)
- : id = (deserializer..moveNext()).expectNum();
+ : id = (deserializer..moveNext()).expectInt();
/// The [serializationZoneId] needs to be separately serialized before the
/// rest of the object. This is not done by the instances themselves but by
/// the macro implementations.
@mustCallSuper
- void serialize(Serializer serializer) => serializer.addNum(id);
+ void serialize(Serializer serializer) => serializer.addInt(id);
static int _next = 0;
}
@@ -81,7 +81,7 @@
factory SerializableResponse.deserialize(
Deserializer deserializer, int serializationZoneId) {
deserializer.moveNext();
- MessageType responseType = MessageType.values[deserializer.expectNum()];
+ MessageType responseType = MessageType.values[deserializer.expectInt()];
Serializable? response;
String? error;
String? stackTrace;
@@ -126,15 +126,15 @@
response: response,
error: error,
stackTrace: stackTrace,
- requestId: (deserializer..moveNext()).expectNum(),
+ requestId: (deserializer..moveNext()).expectInt(),
serializationZoneId: serializationZoneId);
}
void serialize(Serializer serializer) {
serializer
- ..addNum(serializationZoneId)
- ..addNum(MessageType.response.index)
- ..addNum(responseType.index);
+ ..addInt(serializationZoneId)
+ ..addInt(MessageType.response.index)
+ ..addInt(responseType.index);
switch (responseType) {
case MessageType.error:
serializer.addString(error!.toString());
@@ -143,7 +143,7 @@
default:
response.serializeNullable(serializer);
}
- serializer.addNum(requestId);
+ serializer.addInt(requestId);
}
}
@@ -203,7 +203,7 @@
@override
void serialize(Serializer serializer) {
serializer
- ..addNum(MessageType.loadMacroRequest.index)
+ ..addInt(MessageType.loadMacroRequest.index)
..addString(library.toString())
..addString(name);
super.serialize(serializer);
@@ -230,16 +230,16 @@
: macroClass = new MacroClassIdentifierImpl.deserialize(deserializer),
constructorName = (deserializer..moveNext()).expectString(),
arguments = new Arguments.deserialize(deserializer),
- instanceId = (deserializer..moveNext()).expectNum(),
+ instanceId = (deserializer..moveNext()).expectInt(),
super.deserialize(deserializer, serializationZoneId);
@override
void serialize(Serializer serializer) {
- serializer.addNum(MessageType.instantiateMacroRequest.index);
+ serializer.addInt(MessageType.instantiateMacroRequest.index);
macroClass.serialize(serializer);
serializer.addString(constructorName);
arguments.serialize(serializer);
- serializer.addNum(instanceId);
+ serializer.addInt(instanceId);
super.serialize(serializer);
}
}
@@ -262,7 +262,7 @@
super.deserialize(deserializer, serializationZoneId);
void serialize(Serializer serializer) {
- serializer.addNum(MessageType.executeTypesPhaseRequest.index);
+ serializer.addInt(MessageType.executeTypesPhaseRequest.index);
macro.serialize(serializer);
declaration.serialize(serializer);
@@ -295,7 +295,7 @@
super.deserialize(deserializer, serializationZoneId);
void serialize(Serializer serializer) {
- serializer.addNum(MessageType.executeDeclarationsPhaseRequest.index);
+ serializer.addInt(MessageType.executeDeclarationsPhaseRequest.index);
macro.serialize(serializer);
declaration.serialize(serializer);
typeResolver.serialize(serializer);
@@ -332,7 +332,7 @@
super.deserialize(deserializer, serializationZoneId);
void serialize(Serializer serializer) {
- serializer.addNum(MessageType.executeDefinitionsPhaseRequest.index);
+ serializer.addInt(MessageType.executeDefinitionsPhaseRequest.index);
macro.serialize(serializer);
declaration.serialize(serializer);
typeResolver.serialize(serializer);
@@ -361,7 +361,7 @@
super.deserialize(deserializer, serializationZoneId);
void serialize(Serializer serializer) {
- serializer.addNum(MessageType.resolveTypeRequest.index);
+ serializer.addInt(MessageType.resolveTypeRequest.index);
typeAnnotationCode.serialize(serializer);
typeResolver.serialize(serializer);
super.serialize(serializer);
@@ -386,7 +386,7 @@
super.deserialize(deserializer, serializationZoneId);
void serialize(Serializer serializer) {
- serializer.addNum(MessageType.isExactlyTypeRequest.index);
+ serializer.addInt(MessageType.isExactlyTypeRequest.index);
leftType.serialize(serializer);
rightType.serialize(serializer);
super.serialize(serializer);
@@ -411,7 +411,7 @@
super.deserialize(deserializer, serializationZoneId);
void serialize(Serializer serializer) {
- serializer.addNum(MessageType.isSubtypeOfRequest.index);
+ serializer.addInt(MessageType.isSubtypeOfRequest.index);
leftType.serialize(serializer);
rightType.serialize(serializer);
super.serialize(serializer);
@@ -440,7 +440,7 @@
@override
void serialize(Serializer serializer) {
- serializer.addNum(requestKind.index);
+ serializer.addInt(requestKind.index);
classDeclaration.serialize(serializer);
classIntrospector.serialize(serializer);
super.serialize(serializer);
@@ -466,7 +466,7 @@
@override
void serialize(Serializer serializer) {
- serializer.addNum(MessageType.declarationOfRequest.index);
+ serializer.addInt(MessageType.declarationOfRequest.index);
identifier.serialize(serializer);
typeDeclarationResolver.serialize(serializer);
super.serialize(serializer);
diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/remote_instance.dart b/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/remote_instance.dart
index 7ba94f8..3940b7e 100644
--- a/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/remote_instance.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/remote_instance.dart
@@ -57,16 +57,12 @@
/// [SerializationMode.client], so that only an ID is sent.
@mustCallSuper
void serialize(Serializer serializer) {
- serializer.addNum(id);
- switch (serializationMode) {
- case SerializationMode.client:
- // We only send the ID from the client side.
- return;
- case SerializationMode.server:
- serializer.addNum(kind.index);
- _remoteInstanceCache[id] = this;
- return;
- }
+ serializer.addInt(id);
+ // We only send the ID from the client side.
+ if (serializationMode.isClient) return;
+
+ serializer.addInt(kind.index);
+ _remoteInstanceCache[id] = this;
}
@override
diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/response_impls.dart b/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/response_impls.dart
index 2e1d0cc..3686842 100644
--- a/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/response_impls.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/response_impls.dart
@@ -164,12 +164,12 @@
}
MacroInstanceIdentifierImpl.deserialize(Deserializer deserializer)
- : id = (deserializer..moveNext()).expectNum(),
- _interfaces = (deserializer..moveNext()).expectNum();
+ : id = (deserializer..moveNext()).expectInt(),
+ _interfaces = (deserializer..moveNext()).expectInt();
void serialize(Serializer serializer) => serializer
- ..addNum(id)
- ..addNum(_interfaces);
+ ..addInt(id)
+ ..addInt(_interfaces);
operator ==(other) => other is MacroInstanceIdentifierImpl && id == other.id;
diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/serialization.dart b/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/serialization.dart
index 89bbf59..8adf1a1 100644
--- a/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/serialization.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/serialization.dart
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'dart:async';
+import 'dart:typed_data';
import 'remote_instance.dart';
@@ -11,11 +12,15 @@
///
/// In [SerializationMode.server], sets up a remote instance cache to use when
/// deserializing remote instances back to their original instance.
-T withSerializationMode<T>(SerializationMode mode, T Function() fn) =>
+T withSerializationMode<T>(
+ SerializationMode mode,
+ T Function() fn, {
+ Serializer Function()? serializerFactory,
+ Deserializer Function(Object? data)? deserializerFactory,
+}) =>
runZoned(fn, zoneValues: {
#serializationMode: mode,
- if (mode == SerializationMode.server)
- remoteInstanceZoneKey: <int, RemoteInstance>{}
+ if (!mode.isClient) remoteInstanceZoneKey: <int, RemoteInstance>{}
});
/// Serializable interface
@@ -30,19 +35,28 @@
void addString(String value);
/// Serializes a nullable [String].
- void addNullableString(String? value);
+ void addNullableString(String? value) =>
+ value == null ? addNull() : addString(value);
- /// Serializes a [num].
- void addNum(num value);
+ /// Serializes a [double].
+ void addDouble(double value);
- /// Serializes a nullable [num].
- void addNullableNum(num? value);
+ /// Serializes a nullable [double].
+ void addNullableDouble(double? value) =>
+ value == null ? addNull() : addDouble(value);
+
+ /// Serializes an [int].
+ void addInt(int value);
+
+ /// Serializes a nullable [int].
+ void addNullableInt(int? value) => value == null ? addNull() : addInt(value);
/// Serializes a [bool].
void addBool(bool value);
/// Serializes a nullable [bool].
- void addNullableBool(bool? value);
+ void addNullableBool(bool? value) =>
+ value == null ? addNull() : addBool(value);
/// Serializes a `null` literal.
void addNull();
@@ -52,6 +66,9 @@
/// Used to signal the end of an arbitrary length list of items.
void endList();
+
+ /// Returns the resulting serialized object.
+ Object? get result;
}
/// A pull based object deserialization interface.
@@ -67,19 +84,25 @@
bool expectBool();
/// Reads the current value as a nullable [bool].
- bool? expectNullableBool();
+ bool? expectNullableBool() => checkNull() ? null : expectBool();
- /// Reads the current value as a non-nullable [String].
- T expectNum<T extends num>();
+ /// Reads the current value as a non-nullable [double].
+ double expectDouble();
- /// Reads the current value as a nullable [num].
- num? expectNullableNum();
+ /// Reads the current value as a nullable [double].
+ double? expectNullableDouble() => checkNull() ? null : expectDouble();
+
+ /// Reads the current value as a non-nullable [int].
+ int expectInt();
+
+ /// Reads the current value as a nullable [int].
+ int? expectNullableInt() => checkNull() ? null : expectInt();
/// Reads the current value as a non-nullable [String].
String expectString();
/// Reads the current value as a nullable [String].
- String? expectNullableString();
+ String? expectNullableString() => checkNull() ? null : expectString();
/// Asserts that the current item is the start of a list.
///
@@ -121,6 +144,7 @@
/// Returns the result as an unmodifiable [Iterable].
///
/// Asserts that all [List] entries have not been closed with [endList].
+ @override
Iterable<Object?> get result {
assert(_path.length == 1);
return _result;
@@ -132,9 +156,14 @@
void addNullableBool(bool? value) => _path.last.add(value);
@override
- void addNum(num value) => _path.last.add(value);
+ void addDouble(double value) => _path.last.add(value);
@override
- void addNullableNum(num? value) => _path.last.add(value);
+ void addNullableDouble(double? value) => _path.last.add(value);
+
+ @override
+ void addInt(int value) => _path.last.add(value);
+ @override
+ void addNullableInt(int? value) => _path.last.add(value);
@override
void addString(String value) => _path.last.add(value);
@@ -182,9 +211,14 @@
bool? expectNullableBool() => _expectValue();
@override
- T expectNum<T extends num>() => _expectValue();
+ double expectDouble() => _expectValue();
@override
- num? expectNullableNum() => _expectValue();
+ double? expectNullableDouble() => _expectValue();
+
+ @override
+ int expectInt() => _expectValue();
+ @override
+ int? expectNullableInt() => _expectValue();
@override
String expectString() => _expectValue();
@@ -218,6 +252,308 @@
}
}
+class ByteDataSerializer extends Serializer {
+ final BytesBuilder _builder = new BytesBuilder();
+
+ // Re-usable 8 byte list and view for encoding doubles.
+ final Uint8List _eightByteList = new Uint8List(8);
+ late final ByteData _eightByteListData =
+ new ByteData.sublistView(_eightByteList);
+
+ @override
+ void addBool(bool value) => _builder
+ .addByte(value ? DataKind.boolTrue.index : DataKind.boolFalse.index);
+
+ @override
+ void addDouble(double value) {
+ _eightByteListData.setFloat64(0, value);
+ _builder
+ ..addByte(DataKind.float64.index)
+ ..add(_eightByteList);
+ }
+
+ @override
+ void addNull() => _builder.addByte(DataKind.nil.index);
+
+ @override
+ void addInt(int value) {
+ if (value >= 0x0) {
+ if (value + DataKind.values.length <= 0xff) {
+ _builder..addByte(value + DataKind.values.length);
+ } else if (value <= 0xff) {
+ _builder
+ ..addByte(DataKind.uint8.index)
+ ..addByte(value);
+ } else if (value <= 0xffff) {
+ _builder
+ ..addByte(DataKind.uint16.index)
+ ..addByte(value >> 8)
+ ..addByte(value);
+ } else if (value <= 0xffffffff) {
+ _builder
+ ..addByte(DataKind.uint32.index)
+ ..addByte(value >> 24)
+ ..addByte(value >> 16)
+ ..addByte(value >> 8)
+ ..addByte(value);
+ } else {
+ _builder
+ ..addByte(DataKind.uint64.index)
+ ..addByte(value >> 56)
+ ..addByte(value >> 48)
+ ..addByte(value >> 40)
+ ..addByte(value >> 32)
+ ..addByte(value >> 24)
+ ..addByte(value >> 16)
+ ..addByte(value >> 8)
+ ..addByte(value);
+ }
+ } else {
+ if (value >= -0x80) {
+ _builder
+ ..addByte(DataKind.int8.index)
+ ..addByte(value);
+ } else if (value >= -0x8000) {
+ _builder
+ ..addByte(DataKind.int16.index)
+ ..addByte(value >> 8)
+ ..addByte(value);
+ } else if (value >= -0x8000000) {
+ _builder
+ ..addByte(DataKind.int32.index)
+ ..addByte(value >> 24)
+ ..addByte(value >> 16)
+ ..addByte(value >> 8)
+ ..addByte(value);
+ } else {
+ _builder
+ ..addByte(DataKind.int64.index)
+ ..addByte(value >> 56)
+ ..addByte(value >> 48)
+ ..addByte(value >> 40)
+ ..addByte(value >> 32)
+ ..addByte(value >> 24)
+ ..addByte(value >> 16)
+ ..addByte(value >> 8)
+ ..addByte(value);
+ }
+ }
+ }
+
+ @override
+ void addString(String value) {
+ for (int i = 0; i < value.length; i++) {
+ if (value.codeUnitAt(i) > 0xff) {
+ _addTwoByteString(value);
+ return;
+ }
+ }
+ _addOneByteString(value);
+ }
+
+ void _addOneByteString(String value) {
+ _builder.addByte(DataKind.oneByteString.index);
+ addInt(value.length);
+ for (int i = 0; i < value.length; i++) {
+ _builder.addByte(value.codeUnitAt(i));
+ }
+ }
+
+ void _addTwoByteString(String value) {
+ _builder.addByte(DataKind.twoByteString.index);
+ addInt(value.length);
+ for (int i = 0; i < value.length; i++) {
+ int codeUnit = value.codeUnitAt(i);
+ switch (Endian.host) {
+ case Endian.little:
+ _builder
+ ..addByte(codeUnit)
+ ..addByte(codeUnit >> 8);
+ break;
+ case Endian.big:
+ _builder
+ ..addByte(codeUnit >> 8)
+ ..addByte(codeUnit);
+ break;
+ }
+ }
+ }
+
+ @override
+ void endList() => _builder.addByte(DataKind.endList.index);
+
+ @override
+ void startList() => _builder.addByte(DataKind.startList.index);
+
+ @override
+ Uint8List get result => _builder.takeBytes();
+}
+
+class ByteDataDeserializer extends Deserializer {
+ final ByteData _bytes;
+ int _byteOffset = 0;
+ int? _byteOffsetIncrement = 0;
+
+ ByteDataDeserializer(this._bytes);
+
+ /// Reads the next [DataKind] and advances [_byteOffset].
+ DataKind _readKind([int offset = 0]) {
+ int value = _bytes.getUint8(_byteOffset + offset);
+ if (value < DataKind.values.length) {
+ return DataKind.values[value];
+ } else {
+ return DataKind.directEncodedUint8;
+ }
+ }
+
+ @override
+ bool checkNull() {
+ _byteOffsetIncrement = 1;
+ return _readKind() == DataKind.nil;
+ }
+
+ @override
+ bool expectBool() {
+ DataKind kind = _readKind();
+ _byteOffsetIncrement = 1;
+ if (kind == DataKind.boolTrue) {
+ return true;
+ } else if (kind == DataKind.boolFalse) {
+ return false;
+ } else {
+ throw new StateError('Expected a bool but found a $kind');
+ }
+ }
+
+ @override
+ double expectDouble() {
+ DataKind kind = _readKind();
+ if (kind != DataKind.float64) {
+ throw new StateError('Expected a double but found a $kind');
+ }
+ _byteOffsetIncrement = 9;
+ return _bytes.getFloat64(_byteOffset + 1);
+ }
+
+ @override
+ int expectInt() => _expectInt(0);
+
+ int _expectInt(int offset) {
+ DataKind kind = _readKind(offset);
+ if (kind == DataKind.directEncodedUint8) {
+ _byteOffsetIncrement = offset + 1;
+ return _bytes.getUint8(_byteOffset + offset) - DataKind.values.length;
+ }
+ offset += 1;
+ int result;
+ switch (kind) {
+ case DataKind.int8:
+ result = _bytes.getInt8(_byteOffset + offset);
+ _byteOffsetIncrement = 1 + offset;
+ break;
+ case DataKind.int16:
+ result = _bytes.getInt16(_byteOffset + offset);
+ _byteOffsetIncrement = 2 + offset;
+ break;
+ case DataKind.int32:
+ result = _bytes.getInt32(_byteOffset + offset);
+ _byteOffsetIncrement = 4 + offset;
+ break;
+ case DataKind.int64:
+ result = _bytes.getInt64(_byteOffset + offset);
+ _byteOffsetIncrement = 8 + offset;
+ break;
+ case DataKind.uint8:
+ result = _bytes.getUint8(_byteOffset + offset);
+ _byteOffsetIncrement = 1 + offset;
+ break;
+ case DataKind.uint16:
+ result = _bytes.getUint16(_byteOffset + offset);
+ _byteOffsetIncrement = 2 + offset;
+ break;
+ case DataKind.uint32:
+ result = _bytes.getUint32(_byteOffset + offset);
+ _byteOffsetIncrement = 4 + offset;
+ break;
+ case DataKind.uint64:
+ result = _bytes.getUint64(_byteOffset + offset);
+ _byteOffsetIncrement = 8 + offset;
+ break;
+ default:
+ throw new StateError('Expected an int but found a $kind');
+ }
+ return result;
+ }
+
+ @override
+ void expectList() {
+ DataKind kind = _readKind();
+ if (kind != DataKind.startList) {
+ throw new StateError('Expected the start to a list but found a $kind');
+ }
+ _byteOffsetIncrement = 1;
+ }
+
+ @override
+ String expectString() {
+ DataKind kind = _readKind();
+ int length = _expectInt(1);
+ int offset = _byteOffsetIncrement! + _byteOffset;
+ if (kind == DataKind.oneByteString) {
+ _byteOffsetIncrement = _byteOffsetIncrement! + length;
+ return new String.fromCharCodes(
+ _bytes.buffer.asUint8List(offset, length));
+ } else if (kind == DataKind.twoByteString) {
+ length = length * 2;
+ _byteOffsetIncrement = _byteOffsetIncrement! + length;
+ Uint8List bytes =
+ new Uint8List.fromList(_bytes.buffer.asUint8List(offset, length));
+ return new String.fromCharCodes(bytes.buffer.asUint16List());
+ } else {
+ throw new StateError('Expected a string but found a $kind');
+ }
+ }
+
+ @override
+ bool moveNext() {
+ int? increment = _byteOffsetIncrement;
+ _byteOffsetIncrement = null;
+ if (increment == null) {
+ throw new StateError("Can't move until consuming the current element");
+ }
+ _byteOffset += increment;
+ if (_byteOffset >= _bytes.lengthInBytes) {
+ return false;
+ } else if (_readKind() == DataKind.endList) {
+ // You don't explicitly consume list end markers.
+ _byteOffsetIncrement = 1;
+ return false;
+ } else {
+ return true;
+ }
+ }
+}
+
+enum DataKind {
+ nil,
+ boolTrue,
+ boolFalse,
+ directEncodedUint8, // Encoded in the kind byte.
+ startList,
+ endList,
+ int8,
+ int16,
+ int32,
+ int64,
+ uint8,
+ uint16,
+ uint32,
+ uint64,
+ float64,
+ oneByteString,
+ twoByteString,
+}
+
/// Must be set using `withSerializationMode` before doing any serialization or
/// deserialization.
SerializationMode get serializationMode {
@@ -230,9 +566,50 @@
return mode;
}
+/// Returns the current deserializer factory for the zone.
+Deserializer Function(Object?) get deserializerFactory {
+ switch (serializationMode) {
+ case SerializationMode.byteDataClient:
+ case SerializationMode.byteDataServer:
+ return (Object? message) => new ByteDataDeserializer(
+ new ByteData.sublistView(message as Uint8List));
+ case SerializationMode.jsonClient:
+ case SerializationMode.jsonServer:
+ return (Object? message) =>
+ new JsonDeserializer(message as Iterable<Object?>);
+ }
+}
+
+/// Returns the current serializer factory for the zone.
+Serializer Function() get serializerFactory {
+ switch (serializationMode) {
+ case SerializationMode.byteDataClient:
+ case SerializationMode.byteDataServer:
+ return () => new ByteDataSerializer();
+ case SerializationMode.jsonClient:
+ case SerializationMode.jsonServer:
+ return () => new JsonSerializer();
+ }
+}
+
/// Some objects are serialized differently on the client side versus the server
-/// side. This indicates the different modes.
+/// side. This indicates the different modes, as well as the format used.
enum SerializationMode {
- server,
- client,
+ byteDataClient,
+ byteDataServer,
+ jsonServer,
+ jsonClient,
+}
+
+extension IsClient on SerializationMode {
+ bool get isClient {
+ switch (this) {
+ case SerializationMode.byteDataClient:
+ case SerializationMode.jsonClient:
+ return true;
+ case SerializationMode.byteDataServer:
+ case SerializationMode.jsonServer:
+ return false;
+ }
+ }
}
diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/serialization_extensions.dart b/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/serialization_extensions.dart
index 191509f..5a6df71 100644
--- a/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/serialization_extensions.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/serialization_extensions.dart
@@ -6,58 +6,59 @@
extension DeserializerExtensions on Deserializer {
T expectRemoteInstance<T>() {
- int id = expectNum();
- switch (serializationMode) {
- case SerializationMode.client:
+ int id = expectInt();
+
+ // Server side we just return the cached remote instance by ID.
+ if (!serializationMode.isClient) {
+ return RemoteInstance.cached(id) as T;
+ }
+
+ moveNext();
+ RemoteInstanceKind kind = RemoteInstanceKind.values[expectInt()];
+ switch (kind) {
+ case RemoteInstanceKind.classIntrospector:
+ case RemoteInstanceKind.namedStaticType:
+ case RemoteInstanceKind.staticType:
+ case RemoteInstanceKind.typeDeclarationResolver:
+ case RemoteInstanceKind.typeResolver:
+ // These are simple wrappers, just pass in the kind
+ return new RemoteInstanceImpl(id: id, kind: kind) as T;
+ case RemoteInstanceKind.classDeclaration:
moveNext();
- RemoteInstanceKind kind = RemoteInstanceKind.values[expectNum()];
- switch (kind) {
- case RemoteInstanceKind.classIntrospector:
- case RemoteInstanceKind.namedStaticType:
- case RemoteInstanceKind.staticType:
- case RemoteInstanceKind.typeDeclarationResolver:
- case RemoteInstanceKind.typeResolver:
- // These are simple wrappers, just pass in the kind
- return new RemoteInstanceImpl(id: id, kind: kind) as T;
- case RemoteInstanceKind.classDeclaration:
- moveNext();
- return _expectClassDeclaration(id) as T;
- case RemoteInstanceKind.constructorDeclaration:
- moveNext();
- return _expectConstructorDeclaration(id) as T;
- case RemoteInstanceKind.fieldDeclaration:
- moveNext();
- return _expectFieldDeclaration(id) as T;
- case RemoteInstanceKind.functionDeclaration:
- moveNext();
- return _expectFunctionDeclaration(id) as T;
- case RemoteInstanceKind.functionTypeAnnotation:
- moveNext();
- return _expectFunctionTypeAnnotation(id) as T;
- case RemoteInstanceKind.identifier:
- moveNext();
- return _expectIdentifier(id) as T;
- case RemoteInstanceKind.methodDeclaration:
- moveNext();
- return _expectMethodDeclaration(id) as T;
- case RemoteInstanceKind.namedTypeAnnotation:
- moveNext();
- return _expectNamedTypeAnnotation(id) as T;
- case RemoteInstanceKind.parameterDeclaration:
- moveNext();
- return _expectParameterDeclaration(id) as T;
- case RemoteInstanceKind.typeAliasDeclaration:
- moveNext();
- return _expectTypeAliasDeclaration(id) as T;
- case RemoteInstanceKind.typeParameterDeclaration:
- moveNext();
- return _expectTypeParameterDeclaration(id) as T;
- case RemoteInstanceKind.variableDeclaration:
- moveNext();
- return _expectVariableDeclaration(id) as T;
- }
- case SerializationMode.server:
- return RemoteInstance.cached(id) as T;
+ return _expectClassDeclaration(id) as T;
+ case RemoteInstanceKind.constructorDeclaration:
+ moveNext();
+ return _expectConstructorDeclaration(id) as T;
+ case RemoteInstanceKind.fieldDeclaration:
+ moveNext();
+ return _expectFieldDeclaration(id) as T;
+ case RemoteInstanceKind.functionDeclaration:
+ moveNext();
+ return _expectFunctionDeclaration(id) as T;
+ case RemoteInstanceKind.functionTypeAnnotation:
+ moveNext();
+ return _expectFunctionTypeAnnotation(id) as T;
+ case RemoteInstanceKind.identifier:
+ moveNext();
+ return _expectIdentifier(id) as T;
+ case RemoteInstanceKind.methodDeclaration:
+ moveNext();
+ return _expectMethodDeclaration(id) as T;
+ case RemoteInstanceKind.namedTypeAnnotation:
+ moveNext();
+ return _expectNamedTypeAnnotation(id) as T;
+ case RemoteInstanceKind.parameterDeclaration:
+ moveNext();
+ return _expectParameterDeclaration(id) as T;
+ case RemoteInstanceKind.typeAliasDeclaration:
+ moveNext();
+ return _expectTypeAliasDeclaration(id) as T;
+ case RemoteInstanceKind.typeParameterDeclaration:
+ moveNext();
+ return _expectTypeParameterDeclaration(id) as T;
+ case RemoteInstanceKind.variableDeclaration:
+ moveNext();
+ return _expectVariableDeclaration(id) as T;
}
}
@@ -222,7 +223,7 @@
expectList();
List<Object> parts = [];
while (moveNext()) {
- _CodePartKind partKind = _CodePartKind.values[expectNum()];
+ _CodePartKind partKind = _CodePartKind.values[expectInt()];
moveNext();
switch (partKind) {
case _CodePartKind.code:
@@ -240,7 +241,7 @@
}
T expectCode<T extends Code>() {
- CodeKind kind = CodeKind.values[expectNum()];
+ CodeKind kind = CodeKind.values[expectInt()];
switch (kind) {
case CodeKind.raw:
@@ -309,7 +310,7 @@
extension SerializeCode on Code {
void serialize(Serializer serializer) {
- serializer.addNum(kind.index);
+ serializer.addInt(kind.index);
switch (kind) {
case CodeKind.namedTypeAnnotation:
NamedTypeAnnotationCode self = this as NamedTypeAnnotationCode;
@@ -366,13 +367,13 @@
for (Object part in parts) {
if (part is String) {
serializer
- ..addNum(_CodePartKind.string.index)
+ ..addInt(_CodePartKind.string.index)
..addString(part);
} else if (part is Code) {
- serializer.addNum(_CodePartKind.code.index);
+ serializer.addInt(_CodePartKind.code.index);
part.serialize(serializer);
} else if (part is IdentifierImpl) {
- serializer.addNum(_CodePartKind.identifier.index);
+ serializer.addInt(_CodePartKind.identifier.index);
part.serialize(serializer);
} else {
throw new StateError('Unrecognized code part $part');
diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/isolated_executor/isolated_executor.dart b/pkg/_fe_analyzer_shared/lib/src/macros/isolated_executor/isolated_executor.dart
index 6902870..dcd267c 100644
--- a/pkg/_fe_analyzer_shared/lib/src/macros/isolated_executor/isolated_executor.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/macros/isolated_executor/isolated_executor.dart
@@ -126,18 +126,18 @@
required this.messageStream,
required this.sendPort}) {
messageStream.listen((message) {
- withSerializationMode(SerializationMode.server, () {
- JsonDeserializer deserializer =
- new JsonDeserializer(message as List<Object?>);
+ withSerializationMode(SerializationMode.jsonServer, () {
+ Deserializer deserializer =
+ deserializerFactory(message as List<Object?>);
// Every object starts with a zone ID which dictates the zone in which
// we should deserialize the message.
deserializer.moveNext();
- int zoneId = deserializer.expectNum();
+ int zoneId = deserializer.expectInt();
Zone zone = serializationZones[zoneId]!;
zone.run(() async {
deserializer.moveNext();
MessageType messageType =
- MessageType.values[deserializer.expectNum()];
+ MessageType.values[deserializer.expectInt()];
switch (messageType) {
case MessageType.response:
SerializableResponse response =
@@ -169,7 +169,7 @@
? MessageType.namedStaticType
: MessageType.staticType,
serializationZoneId: zoneId);
- JsonSerializer serializer = new JsonSerializer();
+ Serializer serializer = serializerFactory();
response.serialize(serializer);
sendPort.send(serializer.result);
break;
@@ -184,7 +184,7 @@
requestId: request.id,
responseType: MessageType.boolean,
serializationZoneId: zoneId);
- JsonSerializer serializer = new JsonSerializer();
+ Serializer serializer = serializerFactory();
response.serialize(serializer);
sendPort.send(serializer.result);
break;
@@ -199,7 +199,7 @@
requestId: request.id,
responseType: MessageType.boolean,
serializationZoneId: zoneId);
- JsonSerializer serializer = new JsonSerializer();
+ Serializer serializer = serializerFactory();
response.serialize(serializer);
sendPort.send(serializer.result);
break;
@@ -215,7 +215,7 @@
// TODO: Consider refactoring to avoid the need for this.
as TypeDeclarationImpl),
serializationZoneId: zoneId);
- JsonSerializer serializer = new JsonSerializer();
+ Serializer serializer = serializerFactory();
response.serialize(serializer);
sendPort.send(serializer.result);
break;
@@ -233,7 +233,7 @@
// TODO: Consider refactoring to avoid the need for this.
.cast<ConstructorDeclarationImpl>()),
serializationZoneId: zoneId);
- JsonSerializer serializer = new JsonSerializer();
+ Serializer serializer = serializerFactory();
response.serialize(serializer);
sendPort.send(serializer.result);
break;
@@ -251,7 +251,7 @@
// TODO: Consider refactoring to avoid the need for this.
.cast<FieldDeclarationImpl>()),
serializationZoneId: zoneId);
- JsonSerializer serializer = new JsonSerializer();
+ Serializer serializer = serializerFactory();
response.serialize(serializer);
sendPort.send(serializer.result);
break;
@@ -269,7 +269,7 @@
// TODO: Consider refactoring to avoid the need for this.
.cast<ClassDeclarationImpl>()),
serializationZoneId: zoneId);
- JsonSerializer serializer = new JsonSerializer();
+ Serializer serializer = serializerFactory();
response.serialize(serializer);
sendPort.send(serializer.result);
break;
@@ -287,7 +287,7 @@
// TODO: Consider refactoring to avoid the need for this.
.cast<MethodDeclarationImpl>()),
serializationZoneId: zoneId);
- JsonSerializer serializer = new JsonSerializer();
+ Serializer serializer = serializerFactory();
response.serialize(serializer);
sendPort.send(serializer.result);
break;
@@ -305,7 +305,7 @@
// TODO: Consider refactoring to avoid the need for this.
.cast<ClassDeclarationImpl>()),
serializationZoneId: zoneId);
- JsonSerializer serializer = new JsonSerializer();
+ Serializer serializer = serializerFactory();
response.serialize(serializer);
sendPort.send(serializer.result);
break;
@@ -323,7 +323,7 @@
// TODO: Consider refactoring to avoid the need for this.
as ClassDeclarationImpl?,
serializationZoneId: zoneId);
- JsonSerializer serializer = new JsonSerializer();
+ Serializer serializer = serializerFactory();
response.serialize(serializer);
sendPort.send(serializer.result);
break;
@@ -436,13 +436,13 @@
/// Creates a [Request] with a given serialization zone ID, and handles the
/// response, casting it to the expected type or throwing the error provided.
Future<T> _sendRequest<T>(Request Function(int) requestFactory) =>
- withSerializationMode(SerializationMode.server, () async {
+ withSerializationMode(SerializationMode.jsonServer, () async {
int zoneId = _nextSerializationZoneId++;
serializationZones[zoneId] = Zone.current;
Request request = requestFactory(zoneId);
- JsonSerializer serializer = new JsonSerializer();
+ Serializer serializer = serializerFactory();
// It is our responsibility to add the zone ID header.
- serializer.addNum(zoneId);
+ serializer.addInt(zoneId);
request.serialize(serializer);
sendPort.send(serializer.result);
Completer<Response> completer = new Completer<Response>();
diff --git a/pkg/_fe_analyzer_shared/test/macros/executor_shared/serialization_test.dart b/pkg/_fe_analyzer_shared/test/macros/executor_shared/serialization_test.dart
index 879ae11..67cc977 100644
--- a/pkg/_fe_analyzer_shared/test/macros/executor_shared/serialization_test.dart
+++ b/pkg/_fe_analyzer_shared/test/macros/executor_shared/serialization_test.dart
@@ -12,76 +12,109 @@
import '../util.dart';
void main() {
- group('json serializer', () {
- test('can serialize and deserialize basic data', () {
- var serializer = JsonSerializer();
- serializer
- ..addNum(1)
- ..addNullableNum(null)
- ..addString('hello')
- ..addNullableString(null)
- ..startList()
- ..addBool(true)
- ..startList()
- ..addNull()
- ..endList()
- ..addNullableBool(null)
- ..endList()
- ..addNum(1.0)
- ..startList()
- ..endList();
- expect(
- serializer.result,
- equals([
- 1,
- null,
- 'hello',
- null,
- [
- true,
- [null],
- null
- ],
- 1.0,
- [],
- ]));
- var deserializer = JsonDeserializer(serializer.result);
- expect(deserializer.moveNext(), true);
- expect(deserializer.expectNum(), 1);
- expect(deserializer.moveNext(), true);
- expect(deserializer.expectNullableNum(), null);
- expect(deserializer.moveNext(), true);
- expect(deserializer.expectString(), 'hello');
- expect(deserializer.moveNext(), true);
- expect(deserializer.expectNullableString(), null);
- expect(deserializer.moveNext(), true);
+ for (var mode in [
+ SerializationMode.jsonClient,
+ SerializationMode.jsonServer,
+ SerializationMode.byteDataClient,
+ SerializationMode.byteDataServer,
+ ]) {
+ test('$mode can serialize and deserialize basic data', () {
+ withSerializationMode(mode, () {
+ var serializer = serializerFactory();
+ serializer
+ ..addInt(0)
+ ..addInt(1)
+ ..addInt(0xff)
+ ..addInt(0xffff)
+ ..addInt(0xffffffff)
+ ..addInt(0xffffffffffffffff)
+ ..addInt(-1)
+ ..addInt(-0x80)
+ ..addInt(-0x8000)
+ ..addInt(-0x80000000)
+ ..addInt(-0x8000000000000000)
+ ..addNullableInt(null)
+ ..addString('hello')
+ ..addString('€') // Requires a two byte string
+ ..addString('𐐷') // Requires two, 16 bit code units
+ ..addNullableString(null)
+ ..startList()
+ ..addBool(true)
+ ..startList()
+ ..addNull()
+ ..endList()
+ ..addNullableBool(null)
+ ..endList()
+ ..addDouble(1.0)
+ ..startList()
+ ..endList();
+ var deserializer = deserializerFactory(serializer.result);
+ expect(deserializer.moveNext(), true);
+ expect(deserializer.expectInt(), 0);
+ expect(deserializer.moveNext(), true);
+ expect(deserializer.expectInt(), 1);
+ expect(deserializer.moveNext(), true);
+ expect(deserializer.expectInt(), 0xff);
+ expect(deserializer.moveNext(), true);
+ expect(deserializer.expectInt(), 0xffff);
+ expect(deserializer.moveNext(), true);
+ expect(deserializer.expectInt(), 0xffffffff);
+ expect(deserializer.moveNext(), true);
+ expect(deserializer.expectInt(), 0xffffffffffffffff);
+ expect(deserializer.moveNext(), true);
+ expect(deserializer.expectInt(), -1);
+ expect(deserializer.moveNext(), true);
+ expect(deserializer.expectInt(), -0x80);
+ expect(deserializer.moveNext(), true);
+ expect(deserializer.expectInt(), -0x8000);
+ expect(deserializer.moveNext(), true);
+ expect(deserializer.expectInt(), -0x80000000);
+ expect(deserializer.moveNext(), true);
+ expect(deserializer.expectInt(), -0x8000000000000000);
+ expect(deserializer.moveNext(), true);
+ expect(deserializer.expectNullableInt(), null);
+ expect(deserializer.moveNext(), true);
+ expect(deserializer.expectString(), 'hello');
+ expect(deserializer.moveNext(), true);
+ expect(deserializer.expectString(), '€');
+ expect(deserializer.moveNext(), true);
+ expect(deserializer.expectString(), '𐐷');
+ expect(deserializer.moveNext(), true);
+ expect(deserializer.expectNullableString(), null);
+ expect(deserializer.moveNext(), true);
- deserializer.expectList();
- expect(deserializer.moveNext(), true);
- expect(deserializer.expectBool(), true);
- expect(deserializer.moveNext(), true);
+ deserializer.expectList();
+ expect(deserializer.moveNext(), true);
+ expect(deserializer.expectBool(), true);
+ expect(deserializer.moveNext(), true);
- deserializer.expectList();
- expect(deserializer.moveNext(), true);
- expect(deserializer.checkNull(), true);
- expect(deserializer.moveNext(), false);
+ deserializer.expectList();
+ expect(deserializer.moveNext(), true);
+ expect(deserializer.checkNull(), true);
+ expect(deserializer.moveNext(), false);
- expect(deserializer.moveNext(), true);
- expect(deserializer.expectNullableBool(), null);
- expect(deserializer.moveNext(), false);
+ expect(deserializer.moveNext(), true);
+ expect(deserializer.expectNullableBool(), null);
+ expect(deserializer.moveNext(), false);
- // Have to move the parent again to advance it past the list entry.
- expect(deserializer.moveNext(), true);
- expect(deserializer.expectNum(), 1.0);
- expect(deserializer.moveNext(), true);
+ // Have to move the parent again to advance it past the list entry.
+ expect(deserializer.moveNext(), true);
+ expect(deserializer.expectDouble(), 1.0);
+ expect(deserializer.moveNext(), true);
- deserializer.expectList();
- expect(deserializer.moveNext(), false);
+ deserializer.expectList();
+ expect(deserializer.moveNext(), false);
- expect(deserializer.moveNext(), false);
+ expect(deserializer.moveNext(), false);
+ });
});
+ }
- test('remote instances', () async {
+ for (var mode in [
+ SerializationMode.byteDataServer,
+ SerializationMode.jsonServer
+ ]) {
+ test('remote instances in $mode', () async {
var string = NamedTypeAnnotationImpl(
id: RemoteInstance.uniqueId,
isNullable: false,
@@ -93,203 +126,219 @@
isNullable: false,
identifier: IdentifierImpl(id: RemoteInstance.uniqueId, name: 'Foo'),
typeArguments: [string]);
- Object? serializedFoo;
- var serializer = JsonSerializer();
- withSerializationMode(SerializationMode.server, () {
+ withSerializationMode(mode, () {
+ var serializer = serializerFactory();
foo.serialize(serializer);
- serializedFoo = serializer.result;
- var response = roundTrip(serializedFoo);
- var deserializer = JsonDeserializer(response as List<Object?>);
+ var response = roundTrip(serializer.result);
+ var deserializer = deserializerFactory(response);
var instance = RemoteInstance.deserialize(deserializer);
expect(instance, foo);
});
});
+ }
- group('declarations', () {
- final barType = NamedTypeAnnotationImpl(
- id: RemoteInstance.uniqueId,
- isNullable: false,
- identifier: IdentifierImpl(id: RemoteInstance.uniqueId, name: 'Bar'),
- typeArguments: []);
- final fooType = NamedTypeAnnotationImpl(
- id: RemoteInstance.uniqueId,
- isNullable: true,
- identifier: IdentifierImpl(id: RemoteInstance.uniqueId, name: 'Foo'),
- typeArguments: [barType]);
+ group('declarations', () {
+ final barType = NamedTypeAnnotationImpl(
+ id: RemoteInstance.uniqueId,
+ isNullable: false,
+ identifier: IdentifierImpl(id: RemoteInstance.uniqueId, name: 'Bar'),
+ typeArguments: []);
+ final fooType = NamedTypeAnnotationImpl(
+ id: RemoteInstance.uniqueId,
+ isNullable: true,
+ identifier: IdentifierImpl(id: RemoteInstance.uniqueId, name: 'Foo'),
+ typeArguments: [barType]);
- test('NamedTypeAnnotation', () {
- expectSerializationEquality(fooType);
- });
+ for (var mode in [
+ SerializationMode.byteDataServer,
+ SerializationMode.jsonServer
+ ]) {
+ group('with mode $mode', () {
+ test('NamedTypeAnnotation', () {
+ expectSerializationEquality(fooType, mode);
+ });
- final fooNamedParam = ParameterDeclarationImpl(
- id: RemoteInstance.uniqueId,
- isNamed: true,
- isRequired: true,
- identifier: IdentifierImpl(id: RemoteInstance.uniqueId, name: 'foo'),
- type: fooType);
+ final fooNamedParam = ParameterDeclarationImpl(
+ id: RemoteInstance.uniqueId,
+ isNamed: true,
+ isRequired: true,
+ identifier:
+ IdentifierImpl(id: RemoteInstance.uniqueId, name: 'foo'),
+ type: fooType);
- final barPositionalParam = ParameterDeclarationImpl(
- id: RemoteInstance.uniqueId,
- isNamed: false,
- isRequired: false,
- identifier: IdentifierImpl(id: RemoteInstance.uniqueId, name: 'bar'),
- type: barType);
+ final barPositionalParam = ParameterDeclarationImpl(
+ id: RemoteInstance.uniqueId,
+ isNamed: false,
+ isRequired: false,
+ identifier:
+ IdentifierImpl(id: RemoteInstance.uniqueId, name: 'bar'),
+ type: barType);
- final zapTypeParam = TypeParameterDeclarationImpl(
- id: RemoteInstance.uniqueId,
- identifier: IdentifierImpl(id: RemoteInstance.uniqueId, name: 'Zap'),
- bound: barType);
-
- // Transitively tests `TypeParameterDeclaration` and
- // `ParameterDeclaration`.
- test('FunctionTypeAnnotation', () {
- var functionType = FunctionTypeAnnotationImpl(
- id: RemoteInstance.uniqueId,
- isNullable: true,
- namedParameters: [fooNamedParam],
- positionalParameters: [barPositionalParam],
- returnType: fooType,
- typeParameters: [zapTypeParam],
- );
- expectSerializationEquality(functionType);
- });
-
- test('FunctionDeclaration', () {
- var function = FunctionDeclarationImpl(
+ final zapTypeParam = TypeParameterDeclarationImpl(
id: RemoteInstance.uniqueId,
identifier:
- IdentifierImpl(id: RemoteInstance.uniqueId, name: 'name'),
- isAbstract: true,
- isExternal: false,
- isGetter: true,
- isOperator: false,
- isSetter: false,
- namedParameters: [],
- positionalParameters: [],
- returnType: fooType,
- typeParameters: []);
- expectSerializationEquality(function);
- });
+ IdentifierImpl(id: RemoteInstance.uniqueId, name: 'Zap'),
+ bound: barType);
- test('MethodDeclaration', () {
- var method = MethodDeclarationImpl(
+ // Transitively tests `TypeParameterDeclaration` and
+ // `ParameterDeclaration`.
+ test('FunctionTypeAnnotation', () {
+ var functionType = FunctionTypeAnnotationImpl(
id: RemoteInstance.uniqueId,
- identifier:
- IdentifierImpl(id: RemoteInstance.uniqueId, name: 'zorp'),
- isAbstract: false,
- isExternal: false,
- isGetter: false,
- isOperator: false,
- isSetter: true,
+ isNullable: true,
namedParameters: [fooNamedParam],
positionalParameters: [barPositionalParam],
returnType: fooType,
typeParameters: [zapTypeParam],
- definingClass: fooType.identifier);
- expectSerializationEquality(method);
- });
+ );
+ expectSerializationEquality(functionType, mode);
+ });
- test('ConstructorDeclaration', () {
- var constructor = ConstructorDeclarationImpl(
- id: RemoteInstance.uniqueId,
- identifier: IdentifierImpl(id: RemoteInstance.uniqueId, name: 'new'),
- isAbstract: false,
- isExternal: false,
- isGetter: false,
- isOperator: true,
- isSetter: false,
- namedParameters: [fooNamedParam],
- positionalParameters: [barPositionalParam],
- returnType: fooType,
- typeParameters: [zapTypeParam],
- definingClass: fooType.identifier,
- isFactory: true,
- );
- expectSerializationEquality(constructor);
- });
+ test('FunctionDeclaration', () {
+ var function = FunctionDeclarationImpl(
+ id: RemoteInstance.uniqueId,
+ identifier:
+ IdentifierImpl(id: RemoteInstance.uniqueId, name: 'name'),
+ isAbstract: true,
+ isExternal: false,
+ isGetter: true,
+ isOperator: false,
+ isSetter: false,
+ namedParameters: [],
+ positionalParameters: [],
+ returnType: fooType,
+ typeParameters: []);
+ expectSerializationEquality(function, mode);
+ });
- test('VariableDeclaration', () {
- var bar = VariableDeclarationImpl(
- id: RemoteInstance.uniqueId,
- identifier: IdentifierImpl(id: RemoteInstance.uniqueId, name: 'bar'),
- isExternal: true,
- isFinal: false,
- isLate: true,
- type: barType,
- );
- expectSerializationEquality(bar);
- });
+ test('MethodDeclaration', () {
+ var method = MethodDeclarationImpl(
+ id: RemoteInstance.uniqueId,
+ identifier:
+ IdentifierImpl(id: RemoteInstance.uniqueId, name: 'zorp'),
+ isAbstract: false,
+ isExternal: false,
+ isGetter: false,
+ isOperator: false,
+ isSetter: true,
+ namedParameters: [fooNamedParam],
+ positionalParameters: [barPositionalParam],
+ returnType: fooType,
+ typeParameters: [zapTypeParam],
+ definingClass: fooType.identifier);
+ expectSerializationEquality(method, mode);
+ });
- test('FieldDeclaration', () {
- var bar = FieldDeclarationImpl(
- id: RemoteInstance.uniqueId,
- identifier: IdentifierImpl(id: RemoteInstance.uniqueId, name: 'bar'),
- isExternal: false,
- isFinal: true,
- isLate: false,
- type: barType,
- definingClass: fooType.identifier,
- );
- expectSerializationEquality(bar);
- });
+ test('ConstructorDeclaration', () {
+ var constructor = ConstructorDeclarationImpl(
+ id: RemoteInstance.uniqueId,
+ identifier:
+ IdentifierImpl(id: RemoteInstance.uniqueId, name: 'new'),
+ isAbstract: false,
+ isExternal: false,
+ isGetter: false,
+ isOperator: true,
+ isSetter: false,
+ namedParameters: [fooNamedParam],
+ positionalParameters: [barPositionalParam],
+ returnType: fooType,
+ typeParameters: [zapTypeParam],
+ definingClass: fooType.identifier,
+ isFactory: true,
+ );
+ expectSerializationEquality(constructor, mode);
+ });
- var objectType = NamedTypeAnnotationImpl(
- id: RemoteInstance.uniqueId,
- identifier: IdentifierImpl(id: RemoteInstance.uniqueId, name: 'Object'),
- isNullable: false,
- typeArguments: [],
- );
- var serializableType = NamedTypeAnnotationImpl(
- id: RemoteInstance.uniqueId,
- identifier:
- IdentifierImpl(id: RemoteInstance.uniqueId, name: 'Serializable'),
- isNullable: false,
- typeArguments: [],
- );
+ test('VariableDeclaration', () {
+ var bar = VariableDeclarationImpl(
+ id: RemoteInstance.uniqueId,
+ identifier:
+ IdentifierImpl(id: RemoteInstance.uniqueId, name: 'bar'),
+ isExternal: true,
+ isFinal: false,
+ isLate: true,
+ type: barType,
+ );
+ expectSerializationEquality(bar, mode);
+ });
- test('ClassDeclaration', () {
- var fooClass = ClassDeclarationImpl(
- id: RemoteInstance.uniqueId,
- identifier: IdentifierImpl(id: RemoteInstance.uniqueId, name: 'Foo'),
- interfaces: [barType],
- isAbstract: true,
- isExternal: false,
- mixins: [serializableType],
- superclass: objectType,
- typeParameters: [zapTypeParam],
- );
- expectSerializationEquality(fooClass);
- });
+ test('FieldDeclaration', () {
+ var bar = FieldDeclarationImpl(
+ id: RemoteInstance.uniqueId,
+ identifier:
+ IdentifierImpl(id: RemoteInstance.uniqueId, name: 'bar'),
+ isExternal: false,
+ isFinal: true,
+ isLate: false,
+ type: barType,
+ definingClass: fooType.identifier,
+ );
+ expectSerializationEquality(bar, mode);
+ });
- test('TypeAliasDeclaration', () {
- var typeAlias = TypeAliasDeclarationImpl(
+ var objectType = NamedTypeAnnotationImpl(
id: RemoteInstance.uniqueId,
identifier:
- IdentifierImpl(id: RemoteInstance.uniqueId, name: 'FooOfBar'),
- typeParameters: [zapTypeParam],
- aliasedType: NamedTypeAnnotationImpl(
- id: RemoteInstance.uniqueId,
- isNullable: false,
- identifier:
- IdentifierImpl(id: RemoteInstance.uniqueId, name: 'Foo'),
- typeArguments: [barType]),
+ IdentifierImpl(id: RemoteInstance.uniqueId, name: 'Object'),
+ isNullable: false,
+ typeArguments: [],
);
- expectSerializationEquality(typeAlias);
+ var serializableType = NamedTypeAnnotationImpl(
+ id: RemoteInstance.uniqueId,
+ identifier:
+ IdentifierImpl(id: RemoteInstance.uniqueId, name: 'Serializable'),
+ isNullable: false,
+ typeArguments: [],
+ );
+
+ test('ClassDeclaration', () {
+ var fooClass = ClassDeclarationImpl(
+ id: RemoteInstance.uniqueId,
+ identifier:
+ IdentifierImpl(id: RemoteInstance.uniqueId, name: 'Foo'),
+ interfaces: [barType],
+ isAbstract: true,
+ isExternal: false,
+ mixins: [serializableType],
+ superclass: objectType,
+ typeParameters: [zapTypeParam],
+ );
+ expectSerializationEquality(fooClass, mode);
+ });
+
+ test('TypeAliasDeclaration', () {
+ var typeAlias = TypeAliasDeclarationImpl(
+ id: RemoteInstance.uniqueId,
+ identifier:
+ IdentifierImpl(id: RemoteInstance.uniqueId, name: 'FooOfBar'),
+ typeParameters: [zapTypeParam],
+ aliasedType: NamedTypeAnnotationImpl(
+ id: RemoteInstance.uniqueId,
+ isNullable: false,
+ identifier:
+ IdentifierImpl(id: RemoteInstance.uniqueId, name: 'Foo'),
+ typeArguments: [barType]),
+ );
+ expectSerializationEquality(typeAlias, mode);
+ });
});
- });
+ }
});
}
/// Serializes [serializable] in server mode, then deserializes it in client
/// mode, and checks that all the fields are the same.
-void expectSerializationEquality(Serializable serializable) {
- var serializer = JsonSerializer();
- withSerializationMode(SerializationMode.server, () {
+void expectSerializationEquality(
+ Serializable serializable, SerializationMode serverMode) {
+ late Object? serialized;
+ withSerializationMode(serverMode, () {
+ var serializer = serializerFactory();
serializable.serialize(serializer);
+ serialized = serializer.result;
});
- withSerializationMode(SerializationMode.client, () {
- var deserializer = JsonDeserializer(serializer.result);
+ withSerializationMode(_clientModeForServerMode(serverMode), () {
+ var deserializer = deserializerFactory(serialized);
var deserialized = (deserializer..moveNext()).expectRemoteInstance();
if (deserialized is Declaration) {
expect(serializable, deepEqualsDeclaration(deserialized));
@@ -303,12 +352,23 @@
/// Deserializes [serialized] in client mode and sends it back.
Object? roundTrip<Declaration>(Object? serialized) {
- return withSerializationMode(SerializationMode.client, () {
- var deserializer = JsonDeserializer(serialized as List<Object?>);
+ return withSerializationMode(_clientModeForServerMode(serializationMode), () {
+ var deserializer = deserializerFactory(serialized);
var instance =
RemoteInstance.deserialize<NamedTypeAnnotationImpl>(deserializer);
- var serializer = JsonSerializer();
+ var serializer = serializerFactory();
instance.serialize(serializer);
return serializer.result;
});
}
+
+SerializationMode _clientModeForServerMode(SerializationMode serverMode) {
+ switch (serverMode) {
+ case SerializationMode.byteDataServer:
+ return SerializationMode.byteDataClient;
+ case SerializationMode.jsonServer:
+ return SerializationMode.jsonClient;
+ default:
+ throw StateError('Expected to be running in a server mode');
+ }
+}
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart b/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart
index 53b553c..4fbeca3 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart
@@ -9,6 +9,7 @@
import 'package:analysis_server/src/services/completion/dart/closure_contributor.dart';
import 'package:analysis_server/src/services/completion/dart/combinator_contributor.dart';
import 'package:analysis_server/src/services/completion/dart/documentation_cache.dart';
+import 'package:analysis_server/src/services/completion/dart/enum_constant_constructor_contributor.dart';
import 'package:analysis_server/src/services/completion/dart/extension_member_contributor.dart';
import 'package:analysis_server/src/services/completion/dart/feature_computer.dart';
import 'package:analysis_server/src/services/completion/dart/field_formal_contributor.dart';
@@ -142,6 +143,7 @@
ArgListContributor(request, builder),
ClosureContributor(request, builder),
CombinatorContributor(request, builder),
+ EnumConstantConstructorContributor(request, builder),
ExtensionMemberContributor(request, builder),
FieldFormalContributor(request, builder),
KeywordContributor(request, builder),
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/enum_constant_constructor_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/enum_constant_constructor_contributor.dart
new file mode 100644
index 0000000..2680e24
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/completion/dart/enum_constant_constructor_contributor.dart
@@ -0,0 +1,63 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. 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:analysis_server/src/provisional/completion/dart/completion_dart.dart';
+import 'package:analysis_server/src/services/completion/dart/completion_manager.dart';
+import 'package:analysis_server/src/services/completion/dart/suggestion_builder.dart';
+import 'package:analyzer/dart/analysis/features.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/element.dart';
+
+/// A contributor that produces suggestions for constructors to be invoked
+/// in enum constants.
+class EnumConstantConstructorContributor extends DartCompletionContributor {
+ EnumConstantConstructorContributor(
+ DartCompletionRequest request,
+ SuggestionBuilder builder,
+ ) : super(request, builder);
+
+ @override
+ Future<void> computeSuggestions() async {
+ if (!request.featureSet.isEnabled(Feature.enhanced_enums)) {
+ return;
+ }
+
+ // TODO(scheglov) It seems unfortunate that we have to re-discover
+ // the location in contributors. This is the work of `OpType`, so why
+ // doesn't it provide all these enclosing `EnumConstantDeclaration`,
+ // `ConstructorSelector`, `EnumDeclaration`?
+ var node = request.target.containingNode;
+ if (node is! ConstructorSelector) {
+ return;
+ }
+
+ if (request.opType.completionLocation != 'ConstructorSelector_name') {
+ return;
+ }
+
+ var arguments = node.parent;
+ if (arguments is! EnumConstantArguments) {
+ return;
+ }
+
+ var enumConstant = arguments.parent;
+ if (enumConstant is! EnumConstantDeclaration) {
+ return;
+ }
+
+ var enumDeclaration = enumConstant.parent;
+ if (enumDeclaration is! EnumDeclaration) {
+ return;
+ }
+
+ var enumElement = enumDeclaration.declaredElement as ClassElement;
+ for (var constructor in enumElement.constructors) {
+ builder.suggestConstructor(
+ constructor,
+ hasClassName: true,
+ tearOff: true,
+ );
+ }
+ }
+}
diff --git a/pkg/analysis_server/test/services/completion/dart/arglist_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/arglist_contributor_test.dart
index ac6847a..5ed76b7 100644
--- a/pkg/analysis_server/test/services/completion/dart/arglist_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/arglist_contributor_test.dart
@@ -738,6 +738,16 @@
''');
await computeAndCheck();
+ // Enum constant.
+ addTestSource2('''
+$languageVersionLine
+enum E {
+ v$arguments;
+ const E$parameters;
+}
+''');
+ await computeAndCheck();
+
// Function expression invocation.
addTestSource2('''
$languageVersionLine
diff --git a/pkg/analysis_server/test/services/completion/dart/location/enum_test.dart b/pkg/analysis_server/test/services/completion/dart/location/enum_test.dart
index 89bc1b5..295cbdd 100644
--- a/pkg/analysis_server/test/services/completion/dart/location/enum_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/location/enum_test.dart
@@ -213,4 +213,130 @@
check(response).suggestions.isEmpty;
}
+
+ Future<void> test_constantName_dot_name_x_argumentList_named() async {
+ var response = await getTestCodeSuggestions('''
+enum E {
+ v.foo0^();
+ const E.foo01();
+ const E.foo02();
+ const E.bar01();
+}
+''');
+
+ if (isProtocolVersion2) {
+ check(response)
+ ..hasReplacement(left: 4)
+ ..suggestions.matchesInAnyOrder([
+ (suggestion) => suggestion
+ ..completion.isEqualTo('foo01')
+ ..isConstructorInvocation,
+ (suggestion) => suggestion
+ ..completion.isEqualTo('foo02')
+ ..isConstructorInvocation,
+ ]);
+ }
+ }
+
+ Future<void> test_constantName_dot_name_x_semicolon_named() async {
+ var response = await getTestCodeSuggestions('''
+enum E {
+ v.foo0^;
+ const E.foo01();
+ const E.foo02();
+ const E.bar01();
+}
+''');
+
+ if (isProtocolVersion2) {
+ check(response)
+ ..hasReplacement(left: 4)
+ ..suggestions.matchesInAnyOrder([
+ (suggestion) => suggestion
+ ..completion.isEqualTo('foo01')
+ ..isConstructorInvocation,
+ (suggestion) => suggestion
+ ..completion.isEqualTo('foo02')
+ ..isConstructorInvocation,
+ ]);
+ }
+ }
+
+ Future<void> test_constantName_dot_x_argumentList_named() async {
+ var response = await getTestCodeSuggestions('''
+enum E {
+ v.^();
+ const E.foo01();
+ const E.foo02();
+}
+''');
+
+ check(response).suggestions.matchesInAnyOrder([
+ (suggestion) => suggestion
+ ..completion.isEqualTo('foo01')
+ ..isConstructorInvocation,
+ (suggestion) => suggestion
+ ..completion.isEqualTo('foo02')
+ ..isConstructorInvocation,
+ ]);
+ }
+
+ Future<void> test_constantName_dot_x_semicolon_named() async {
+ var response = await getTestCodeSuggestions('''
+enum E {
+ v.^;
+ const E.foo01();
+ const E.foo02();
+}
+''');
+
+ check(response).suggestions.matchesInAnyOrder([
+ (suggestion) => suggestion
+ ..completion.isEqualTo('foo01')
+ ..isConstructorInvocation,
+ (suggestion) => suggestion
+ ..completion.isEqualTo('foo02')
+ ..isConstructorInvocation,
+ ]);
+ }
+
+ Future<void> test_constantName_dot_x_semicolon_unnamed_declared() async {
+ var response = await getTestCodeSuggestions('''
+enum E {
+ v.^;
+ const E();
+}
+''');
+
+ check(response).suggestions.matches([
+ (suggestion) => suggestion
+ ..completion.isEqualTo('new')
+ ..isConstructorInvocation,
+ ]);
+ }
+
+ Future<void> test_constantName_dot_x_unnamed_implicit() async {
+ var response = await getTestCodeSuggestions('''
+enum E {
+ v.^
+}
+''');
+
+ check(response).suggestions.matches([
+ (suggestion) => suggestion
+ ..completion.isEqualTo('new')
+ ..isConstructorInvocation,
+ ]);
+ }
+
+ Future<void> test_constantName_dot_x_unnamed_language216() async {
+ var response = await getTestCodeSuggestions('''
+// @dart = 2.16
+enum E {
+ v.^
+}
+''');
+
+ check(response).suggestions.isEmpty;
+ }
}
diff --git a/pkg/analyzer/lib/src/fasta/ast_builder.dart b/pkg/analyzer/lib/src/fasta/ast_builder.dart
index e04f113..8046f63 100644
--- a/pkg/analyzer/lib/src/fasta/ast_builder.dart
+++ b/pkg/analyzer/lib/src/fasta/ast_builder.dart
@@ -2840,17 +2840,18 @@
var argumentList = tmpArguments?.argumentList;
TypeArgumentListImpl? typeArguments;
- ConstructorSelectorImpl? constructorName;
+ ConstructorSelectorImpl? constructorSelector;
if (tmpConstructor != null) {
typeArguments = tmpConstructor.type2.typeArguments;
var constructorNamePeriod = tmpConstructor.period;
var constructorNameId = tmpConstructor.name;
if (constructorNamePeriod != null && constructorNameId != null) {
- constructorName = ConstructorSelectorImpl(
+ constructorSelector = ConstructorSelectorImpl(
period: constructorNamePeriod,
name: constructorNameId,
);
}
+ // enum E { v<int> }
if (typeArguments != null && argumentList == null) {
errorReporter.errorReporter?.reportErrorForNode(
ParserErrorCode.ENUM_CONSTANT_WITH_TYPE_ARGUMENTS_WITHOUT_ARGUMENTS,
@@ -2858,6 +2859,10 @@
);
argumentList = _syntheticArgumentList(typeArguments.endToken);
}
+ // enum E { v.^ }
+ if (constructorSelector != null) {
+ argumentList ??= _syntheticArgumentList(constructorSelector.endToken);
+ }
}
// Replace the constant to include arguments.
@@ -2868,7 +2873,7 @@
name: constant.name,
arguments: EnumConstantArgumentsImpl(
typeArguments: typeArguments,
- constructorSelector: constructorName,
+ constructorSelector: constructorSelector,
argumentList: argumentList,
),
);
diff --git a/pkg/analyzer/test/src/fasta/ast_builder_test.dart b/pkg/analyzer/test/src/fasta/ast_builder_test.dart
index cdc7a64..5edc30a 100644
--- a/pkg/analyzer/test/src/fasta/ast_builder_test.dart
+++ b/pkg/analyzer/test/src/fasta/ast_builder_test.dart
@@ -58,6 +58,78 @@
expect(member.initializers, hasLength(1));
}
+ void test_enum_constant_name_dot() {
+ var parseResult = parseStringWithErrors(r'''
+enum E {
+ v.
+}
+''');
+ parseResult.assertErrors([
+ error(ParserErrorCode.MISSING_IDENTIFIER, 14, 1),
+ ]);
+
+ var v = parseResult.findNode.enumConstantDeclaration('v.');
+ check(v).name.name.isEqualTo('v');
+ check(v).arguments.isNotNull
+ ..typeArguments.isNull
+ ..constructorSelector.isNotNull.name.isSynthetic
+ ..argumentList.isSynthetic;
+ }
+
+ void test_enum_constant_name_dot_identifier_semicolon() {
+ var parseResult = parseStringWithErrors(r'''
+enum E {
+ v.named;
+}
+''');
+ parseResult.assertNoErrors();
+
+ var v = parseResult.findNode.enumConstantDeclaration('v.');
+ check(v).name.name.isEqualTo('v');
+ check(v).arguments.isNotNull
+ ..typeArguments.isNull
+ ..constructorSelector.isNotNull.name.name.isEqualTo('named')
+ ..argumentList.isSynthetic;
+ }
+
+ void test_enum_constant_name_dot_semicolon() {
+ var parseResult = parseStringWithErrors(r'''
+enum E {
+ v.;
+}
+''');
+ parseResult.assertErrors([
+ error(ParserErrorCode.MISSING_IDENTIFIER, 13, 1),
+ ]);
+
+ var v = parseResult.findNode.enumConstantDeclaration('v.');
+ check(v).name.name.isEqualTo('v');
+ check(v).arguments.isNotNull
+ ..typeArguments.isNull
+ ..constructorSelector.isNotNull.name.isSynthetic
+ ..argumentList.isSynthetic;
+ }
+
+ void test_enum_constant_name_typeArguments_dot() {
+ var parseResult = parseStringWithErrors(r'''
+enum E {
+ v<int>.
+}
+''');
+ parseResult.assertErrors([
+ error(ParserErrorCode.ENUM_CONSTANT_WITH_TYPE_ARGUMENTS_WITHOUT_ARGUMENTS,
+ 12, 5),
+ error(ParserErrorCode.MISSING_IDENTIFIER, 19, 1),
+ ]);
+
+ var v = parseResult.findNode.enumConstantDeclaration('v<int>.');
+ check(v).name.name.isEqualTo('v');
+ check(v).arguments.isNotNull
+ ..typeArguments.isNotNull
+ ..constructorSelector.isNotNull.name.isSynthetic
+ ..argumentList.isSynthetic;
+ }
+
void test_enum_constant_withTypeArgumentsWithoutArguments() {
var parseResult = parseStringWithErrors(r'''
enum E<T> {
diff --git a/pkg/analyzer/test/util/ast_check.dart b/pkg/analyzer/test/util/ast_check.dart
index 65e0da9..8119c60 100644
--- a/pkg/analyzer/test/util/ast_check.dart
+++ b/pkg/analyzer/test/util/ast_check.dart
@@ -41,6 +41,15 @@
}
}
+extension ConstructorSelectorExtension on CheckTarget<ConstructorSelector> {
+ CheckTarget<SimpleIdentifier> get name {
+ return nest(
+ value.name,
+ (selected) => 'has name ${valueStr(selected)}',
+ );
+ }
+}
+
extension EnumConstantArgumentsExtension on CheckTarget<EnumConstantArguments> {
CheckTarget<ArgumentList> get argumentList {
return nest(
@@ -49,6 +58,13 @@
);
}
+ CheckTarget<ConstructorSelector?> get constructorSelector {
+ return nest(
+ value.constructorSelector,
+ (selected) => 'has constructorSelector ${valueStr(selected)}',
+ );
+ }
+
CheckTarget<TypeArgumentList?> get typeArguments {
return nest(
value.typeArguments,
@@ -116,6 +132,12 @@
);
}
+ void get isSynthetic {
+ if (!value.token.isSynthetic) {
+ fail('Is not synthetic');
+ }
+ }
+
CheckTarget<String> get name {
return nest(
value.name,
diff --git a/pkg/analyzer_plugin/lib/src/utilities/completion/completion_target.dart b/pkg/analyzer_plugin/lib/src/utilities/completion/completion_target.dart
index ce716df..0ce5403 100644
--- a/pkg/analyzer_plugin/lib/src/utilities/completion/completion_target.dart
+++ b/pkg/analyzer_plugin/lib/src/utilities/completion/completion_target.dart
@@ -291,6 +291,12 @@
Element? executable;
if (invocation is Annotation) {
executable = invocation.element;
+ } else if (invocation is EnumConstantArguments) {
+ var enumConstant = invocation.parent;
+ if (enumConstant is! EnumConstantDeclaration) {
+ return null;
+ }
+ executable = enumConstant.constructorElement;
} else if (invocation is InstanceCreationExpression) {
executable = invocation.constructorName.staticElement;
} else if (invocation is MethodInvocation) {
diff --git a/pkg/analyzer_plugin/lib/src/utilities/completion/optype.dart b/pkg/analyzer_plugin/lib/src/utilities/completion/optype.dart
index 9d6bce2..74aee3b 100644
--- a/pkg/analyzer_plugin/lib/src/utilities/completion/optype.dart
+++ b/pkg/analyzer_plugin/lib/src/utilities/completion/optype.dart
@@ -450,6 +450,13 @@
}
@override
+ void visitConstructorSelector(ConstructorSelector node) {
+ if (identical(entity, node.name)) {
+ optype.completionLocation = 'ConstructorSelector_name';
+ }
+ }
+
+ @override
void visitContinueStatement(ContinueStatement node) {
if (node.label == null || identical(entity, node.label)) {
optype.includeStatementLabelSuggestions = true;
@@ -1369,6 +1376,8 @@
var parent = node.parent;
if (parent is Annotation) {
return 'annotation';
+ } else if (parent is EnumConstantArguments) {
+ return 'enumConstantArguments';
} else if (parent is ExtensionOverride) {
return 'extensionOverride';
} else if (parent is FunctionExpressionInvocation) {
diff --git a/pkg/front_end/test/spell_checking_list_code.txt b/pkg/front_end/test/spell_checking_list_code.txt
index 10299a1..a8d2705 100644
--- a/pkg/front_end/test/spell_checking_list_code.txt
+++ b/pkg/front_end/test/spell_checking_list_code.txt
@@ -215,6 +215,7 @@
compared
compares
compilations
+complement
completers
completes
complicating
@@ -266,6 +267,7 @@
csslib
cstefantsova
ctx
+customizable
customized
cut
cwd
@@ -378,6 +380,7 @@
effects
efficient
efficiently
+eight
eighth
elem
eliminating
@@ -736,6 +739,7 @@
masking
masks
master
+materialize
mature
mb
mc
@@ -1308,6 +1312,7 @@
traced
tracker
traditional
+transferable
transformers
transforming
translation
@@ -1321,6 +1326,7 @@
ts
tty
tuple
+twos
typeref
u
ufeff
@@ -1466,6 +1472,9 @@
xdfff
xef
xff
+xffff
+xffffffff
+xffffffffffffffff
xi
xj
xk
diff --git a/tools/VERSION b/tools/VERSION
index a9db075..a1cb1b8 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 17
PATCH 0
-PRERELEASE 102
+PRERELEASE 103
PRERELEASE_PATCH 0
\ No newline at end of file