Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(91)

Side by Side Diff: pkg/fletchc/lib/src/shared_command_infrastructure.dart

Issue 1659163007: Rename fletch -> dartino (Closed) Base URL: https://github.com/dartino/sdk.git@master
Patch Set: address comments Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « pkg/fletchc/lib/src/please_report_crash.dart ('k') | pkg/fletchc/lib/src/verbs/README.md » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2015, the Dartino project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE.md file.
4
5 /// Provides common infrastructure for reading commads from a [Stream].
6 ///
7 /// We have two independent command kinds that follow the same scheme:
8 ///
9 /// 1. ../vm_commands.dart
10 /// 2. hub/client_commands.dart
11 ///
12 /// Both commands are serialized in this format (using little endian):
13 ///
14 /// * Byte offset 0: one byte (code) which corresponds to an enum value.
15 /// * Byte offset 1: four bytes payload length (unsigned int).
16 /// * Byte offset 5: payload length bytes of payload.
17 library fletchc.src.command_transformer_builder;
18
19 import 'dart:async' show
20 EventSink,
21 StreamTransformer;
22
23 import 'dart:convert' show
24 ASCII;
25
26 import 'dart:io' show
27 BytesBuilder;
28
29 import 'dart:typed_data' show
30 ByteData,
31 Endianness,
32 TypedData,
33 Uint32List,
34 Uint8List;
35
36 const Endianness commandEndianness = Endianness.LITTLE_ENDIAN;
37
38 /// 32 bit package length + 8 bit code is 5 bytes.
39 const headerSize = 5;
40
41 /// [C] is the command implementation class.
42 abstract class CommandTransformerBuilder<C> {
43 StreamTransformer<List<int>, C> build() {
44 BytesBuilder builder = new BytesBuilder(copy: false);
45
46 ByteData toByteData(TypedData data, [int offset = 0, int length]) {
47 return data.buffer.asByteData(data.offsetInBytes + offset, length);
48 }
49
50 void handleData(Uint8List data, EventSink<C> sink) {
51 builder.add(toUint8ListView(data));
52 Uint8List list = builder.takeBytes();
53
54 ByteData view = toByteData(list);
55
56 while (view.lengthInBytes >= headerSize) {
57 int length = view.getUint32(0, commandEndianness);
58 if ((view.lengthInBytes - headerSize) < length) {
59 // Not all of the payload has arrived yet.
60 break;
61 }
62 int code = view.getUint8(4);
63
64 ByteData payload = toByteData(view, headerSize, length);
65
66 C command = makeCommand(code, payload);
67
68 if (command != null) {
69 sink.add(command);
70 } else {
71 sink.addError("Command not implemented yet: $code");
72 }
73
74 view = toByteData(payload, length);
75 }
76
77 if (view.lengthInBytes > 0) {
78 builder.add(toUint8ListView(view));
79 }
80 }
81
82 void handleError(error, StackTrace stackTrace, EventSink<C> sink) {
83 sink.addError(error, stackTrace);
84 }
85
86 void handleDone(EventSink<C> sink) {
87 List trailing = builder.takeBytes();
88 if (trailing.length != 0) {
89 sink.addError(
90 new StateError("Stream closed with trailing bytes : $trailing"));
91 }
92 sink.close();
93 }
94
95 return new StreamTransformer<List<int>, C>.fromHandlers(
96 handleData: handleData,
97 handleError: handleError,
98 handleDone: handleDone);
99 }
100
101 C makeCommand(int code, ByteData payload);
102 }
103
104 Uint8List toUint8ListView(TypedData list, [int offset = 0, int length]) {
105 if (length == null) {
106 length = list.lengthInBytes;
107 }
108 return new Uint8List.view(list.buffer, list.offsetInBytes + offset, length);
109 }
110
111 /// [E] is an enum.
112 class CommandBuffer<E> {
113 int position = headerSize;
114
115 Uint8List list = new Uint8List(16);
116
117 ByteData view;
118
119 CommandBuffer() {
120 view = new ByteData.view(list.buffer, list.offsetInBytes);
121 }
122
123 void growBytes(int size) {
124 while (position + size >= list.length) {
125 list = new Uint8List(list.length * 2)
126 ..setRange(0, list.length, list);
127 view = new ByteData.view(list.buffer, list.offsetInBytes);
128 }
129 }
130
131 void addUint8(int value) {
132 growBytes(1);
133 view.setUint8(position++, value);
134 }
135
136 void addUint32(int value) {
137 // TODO(ahe): The C++ appears to often read 32-bit values into a signed
138 // integer. Figure which is signed and which is unsigned.
139 growBytes(4);
140 view.setUint32(position, value, commandEndianness);
141 position += 4;
142 }
143
144 void addUint64(int value) {
145 growBytes(8);
146 view.setUint64(position, value, commandEndianness);
147 position += 8;
148 }
149
150 void addDouble(double value) {
151 growBytes(8);
152 view.setFloat64(position, value, commandEndianness);
153 position += 8;
154 }
155
156 void addUint8List(List<int> value) {
157 growBytes(value.length);
158 list.setRange(position, position + value.length, value);
159 position += value.length;
160 }
161
162 void addAsciiString(String value) {
163 addUint8List(ASCII.encode(value));
164 }
165
166 void addBool(bool value) {
167 addUint8(value ? 1 : 0);
168 }
169
170 void sendOn(Sink<List<int>> sink, E code) {
171 view.setUint32(0, position - headerSize, commandEndianness);
172 view.setUint8(4, (code as dynamic).index);
173 sink.add(new Uint8List.view(list.buffer, list.offsetInBytes, position));
174 }
175
176 static bool readBoolFromBuffer(Uint8List buffer, int offset) {
177 return buffer[offset] != 0;
178 }
179
180 static String readStringFromBuffer(Uint8List buffer, int offset, int length) {
181 const bytesPerCharacter = 4;
182 int numberOfCharacters = length ~/ bytesPerCharacter;
183 assert(length == numberOfCharacters * bytesPerCharacter);
184 if (((buffer.offsetInBytes + offset) % Uint32List.BYTES_PER_ELEMENT) != 0) {
185 // Uint32List.view throws ArgumentError if offset isn't muliple of 4.
186 buffer = new Uint8List.fromList(buffer);
187 }
188 return new String.fromCharCodes(
189 new Uint32List.view(
190 buffer.buffer, buffer.offsetInBytes + offset, numberOfCharacters));
191 }
192
193 static String readAsciiStringFromBuffer(
194 Uint8List buffer, int offset, int length) {
195 return new String.fromCharCodes(
196 new Uint8List.view(
197 buffer.buffer, buffer.offsetInBytes + offset, length));
198 }
199
200 static int readInt32FromBuffer(Uint8List buffer, int offset) {
201 return buffer.buffer.asByteData(buffer.offsetInBytes)
202 .getInt32(offset, commandEndianness);
203 }
204
205 static int readInt64FromBuffer(Uint8List buffer, int offset) {
206 return buffer.buffer.asByteData(buffer.offsetInBytes)
207 .getInt64(offset, commandEndianness);
208 }
209
210 static double readDoubleFromBuffer(Uint8List buffer, int offset) {
211 {
212 // TODO(ahe): On ARM the Dart VM might crash when reading a double from
213 // an unaligned address. Remove this block when this bug is fixed:
214 // https://github.com/dart-lang/sdk/issues/23953
215 buffer = new Uint8List.fromList(
216 buffer.buffer.asUint8List(buffer.offsetInBytes + offset));
217 assert(buffer.offsetInBytes == 0);
218 offset = 0;
219 }
220 return buffer.buffer.asByteData(buffer.offsetInBytes)
221 .getFloat64(offset, commandEndianness);
222 }
223 }
OLDNEW
« no previous file with comments | « pkg/fletchc/lib/src/please_report_crash.dart ('k') | pkg/fletchc/lib/src/verbs/README.md » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698