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

Side by Side Diff: mojo/public/java/bindings/src/org/chromium/mojo/bindings/Encoder.java

Issue 2250183003: Make the fuchsia mojo/public repo the source of truth. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Created 4 years, 4 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
OLDNEW
(Empty)
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 package org.chromium.mojo.bindings;
6
7 import org.chromium.mojo.bindings.Interface.Proxy.Handler;
8 import org.chromium.mojo.system.Core;
9 import org.chromium.mojo.system.Handle;
10 import org.chromium.mojo.system.MessagePipeHandle;
11 import org.chromium.mojo.system.Pair;
12
13 import java.nio.ByteBuffer;
14 import java.nio.ByteOrder;
15 import java.nio.charset.Charset;
16 import java.util.ArrayList;
17 import java.util.List;
18
19 /**
20 * Helper class to encode a mojo struct. It keeps track of the output buffer, re sizing it as needed.
21 * It also keeps track of the associated handles, and the offset of the current data section.
22 */
23 public class Encoder {
24
25 /**
26 * Container class for all state that must be shared between the main encode r and any used sub
27 * encoder.
28 */
29 private static class EncoderState {
30
31 /**
32 * The core used to encode interfaces.
33 */
34 public final Core core;
35
36 /**
37 * The ByteBuffer to which the message will be encoded.
38 */
39 public ByteBuffer byteBuffer;
40
41 /**
42 * The list of encountered handles.
43 */
44 public final List<Handle> handles = new ArrayList<Handle>();
45
46 /**
47 * The current absolute position for the next data section.
48 */
49 public int dataEnd;
50
51 /**
52 * @param core the |Core| implementation used to generate handles. Only used if the data
53 * structure being encoded contains interfaces, can be |null| otherwise.
54 * @param bufferSize A hint on the size of the message. Used to build th e initial byte
55 * buffer.
56 */
57 private EncoderState(Core core, int bufferSize) {
58 assert bufferSize % BindingsHelper.ALIGNMENT == 0;
59 this.core = core;
60 byteBuffer = ByteBuffer.allocateDirect(
61 bufferSize > 0 ? bufferSize : INITIAL_BUFFER_SIZE);
62 byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
63 dataEnd = 0;
64 }
65
66 /**
67 * Claim the given amount of memory at the end of the buffer, resizing i t if needed.
68 */
69 public void claimMemory(int size) {
70 dataEnd += size;
71 growIfNeeded();
72 }
73
74 /**
75 * Grow the associated ByteBuffer if needed.
76 */
77 private void growIfNeeded() {
78 if (byteBuffer.capacity() >= dataEnd) {
79 return;
80 }
81 int targetSize = byteBuffer.capacity() * 2;
82 while (targetSize < dataEnd) {
83 targetSize *= 2;
84 }
85 ByteBuffer newBuffer = ByteBuffer.allocateDirect(targetSize);
86 newBuffer.order(ByteOrder.nativeOrder());
87 byteBuffer.position(0);
88 byteBuffer.limit(byteBuffer.capacity());
89 newBuffer.put(byteBuffer);
90 byteBuffer = newBuffer;
91 }
92 }
93
94 /**
95 * Default initial size of the data buffer. This must be a multiple of 8 byt es.
96 */
97 private static final int INITIAL_BUFFER_SIZE = 1024;
98
99 /**
100 * Base offset in the byte buffer for writing.
101 */
102 private int mBaseOffset;
103
104 /**
105 * The encoder state shared by the main encoder and all its sub-encoder.
106 */
107 private final EncoderState mEncoderState;
108
109 /**
110 * Returns the result message.
111 */
112 public Message getMessage() {
113 mEncoderState.byteBuffer.position(0);
114 mEncoderState.byteBuffer.limit(mEncoderState.dataEnd);
115 return new Message(mEncoderState.byteBuffer, mEncoderState.handles);
116 }
117
118 /**
119 * Constructor.
120 *
121 * @param core the |Core| implementation used to generate handles. Only used if the data
122 * structure being encoded contains interfaces, can be |null| oth erwise.
123 * @param sizeHint A hint on the size of the message. Used to build the init ial byte buffer.
124 */
125 public Encoder(Core core, int sizeHint) {
126 this(new EncoderState(core, sizeHint));
127 }
128
129 /**
130 * Private constructor for sub-encoders.
131 */
132 private Encoder(EncoderState bufferInformation) {
133 mEncoderState = bufferInformation;
134 mBaseOffset = bufferInformation.dataEnd;
135 }
136
137 /**
138 * Returns a new encoder that will append to the current buffer.
139 */
140 public Encoder getEncoderAtDataOffset(DataHeader dataHeader) {
141 Encoder result = new Encoder(mEncoderState);
142 result.encode(dataHeader);
143 return result;
144 }
145
146 /**
147 * Encode a {@link DataHeader} and claim the amount of memory required for t he data section
148 * (resizing the buffer if required).
149 */
150 public void encode(DataHeader s) {
151 mEncoderState.claimMemory(BindingsHelper.align(s.size));
152 encode(s.size, DataHeader.SIZE_OFFSET);
153 encode(s.elementsOrVersion, DataHeader.ELEMENTS_OR_VERSION_OFFSET);
154 }
155
156 /**
157 * Encode a byte at the given offset.
158 */
159 public void encode(byte v, int offset) {
160 mEncoderState.byteBuffer.put(mBaseOffset + offset, v);
161 }
162
163 /**
164 * Encode a boolean at the given offset.
165 */
166 public void encode(boolean v, int offset, int bit) {
167 if (v) {
168 byte encodedValue = mEncoderState.byteBuffer.get(mBaseOffset + offse t);
169 encodedValue |= (byte) (1 << bit);
170 mEncoderState.byteBuffer.put(mBaseOffset + offset, encodedValue);
171 }
172 }
173
174 /**
175 * Encode a short at the given offset.
176 */
177 public void encode(short v, int offset) {
178 mEncoderState.byteBuffer.putShort(mBaseOffset + offset, v);
179 }
180
181 /**
182 * Encode an int at the given offset.
183 */
184 public void encode(int v, int offset) {
185 mEncoderState.byteBuffer.putInt(mBaseOffset + offset, v);
186 }
187
188 /**
189 * Encode a float at the given offset.
190 */
191 public void encode(float v, int offset) {
192 mEncoderState.byteBuffer.putFloat(mBaseOffset + offset, v);
193 }
194
195 /**
196 * Encode a long at the given offset.
197 */
198 public void encode(long v, int offset) {
199 mEncoderState.byteBuffer.putLong(mBaseOffset + offset, v);
200 }
201
202 /**
203 * Encode a double at the given offset.
204 */
205 public void encode(double v, int offset) {
206 mEncoderState.byteBuffer.putDouble(mBaseOffset + offset, v);
207 }
208
209 /**
210 * Encode a {@link Struct} at the given offset.
211 */
212 public void encode(Struct v, int offset, boolean nullable) {
213 if (v == null) {
214 encodeNullPointer(offset, nullable);
215 return;
216 }
217 encodePointerToNextUnclaimedData(offset);
218 v.encode(this);
219 }
220
221 /**
222 * Encode a {@link Union} at the given offset.
223 */
224 public void encode(Union v, int offset, boolean nullable) {
225 if (v == null && !nullable) {
226 throw new SerializationException(
227 "Trying to encode a null pointer for a non-nullable type.");
228 }
229 if (v == null) {
230 encode(0L, offset);
231 encode(0L, offset + DataHeader.HEADER_SIZE);
232 return;
233 }
234 v.encode(this, offset);
235 }
236
237 /**
238 * Encodes a String.
239 */
240 public void encode(String v, int offset, boolean nullable) {
241 if (v == null) {
242 encodeNullPointer(offset, nullable);
243 return;
244 }
245 final int arrayNullability = nullable
246 ? BindingsHelper.ARRAY_NULLABLE : BindingsHelper.NOTHING_NULLABL E;
247 encode(v.getBytes(Charset.forName("utf8")), offset, arrayNullability,
248 BindingsHelper.UNSPECIFIED_ARRAY_LENGTH);
249 }
250
251 /**
252 * Encodes a {@link Handle}.
253 */
254 public void encode(Handle v, int offset, boolean nullable) {
255 if (v == null || !v.isValid()) {
256 encodeInvalidHandle(offset, nullable);
257 } else {
258 encode(mEncoderState.handles.size(), offset);
259 mEncoderState.handles.add(v);
260 }
261 }
262
263 /**
264 * Encode an {@link Interface}.
265 */
266 public <T extends Interface> void encode(T v, int offset, boolean nullable,
267 Interface.Manager<T, ?> manager) {
268 if (v == null) {
269 encodeInvalidHandle(offset, nullable);
270 encode(0, offset + BindingsHelper.SERIALIZED_HANDLE_SIZE);
271 return;
272 }
273 if (mEncoderState.core == null) {
274 throw new UnsupportedOperationException(
275 "The encoder has been created without a Core. It can't encod e an interface.");
276 }
277 // If the instance is a proxy, pass the proxy's handle instead of creati ng a new stub.
278 if (v instanceof Interface.Proxy) {
279 Handler handler = ((Interface.Proxy) v).getProxyHandler();
280 encode(handler.passHandle(), offset, nullable);
281 encode(handler.getVersion(), offset + BindingsHelper.SERIALIZED_HAND LE_SIZE);
282 return;
283 }
284 Pair<MessagePipeHandle, MessagePipeHandle> handles =
285 mEncoderState.core.createMessagePipe(null);
286 manager.bind(v, handles.first);
287 encode(handles.second, offset, nullable);
288 encode(manager.getVersion(), offset + BindingsHelper.SERIALIZED_HANDLE_S IZE);
289 }
290
291 /**
292 * Encode an {@link InterfaceRequest}.
293 */
294 public <I extends Interface> void encode(InterfaceRequest<I> v, int offset, boolean nullable) {
295 if (v == null) {
296 encodeInvalidHandle(offset, nullable);
297 return;
298 }
299 if (mEncoderState.core == null) {
300 throw new UnsupportedOperationException(
301 "The encoder has been created without a Core. It can't encod e an interface.");
302 }
303 encode(v.passHandle(), offset, nullable);
304 }
305
306 /**
307 * Returns an {@link Encoder} suitable for encoding an array of pointer of t he given length.
308 */
309 public Encoder encodePointerArray(int length, int offset, int expectedLength ) {
310 return encoderForArray(BindingsHelper.POINTER_SIZE, length, offset, expe ctedLength);
311 }
312
313 /**
314 * Returns an {@link Encoder} suitable for encoding an array of union of the given length.
315 */
316 public Encoder encodeUnionArray(int length, int offset, int expectedLength) {
317 return encoderForArray(BindingsHelper.UNION_SIZE, length, offset, expect edLength);
318 }
319
320 /**
321 * Encodes an array of booleans.
322 */
323 public void encode(boolean[] v, int offset, int arrayNullability, int expect edLength) {
324 if (v == null) {
325 encodeNullPointer(offset, BindingsHelper.isArrayNullable(arrayNullab ility));
326 return;
327 }
328 if (expectedLength != BindingsHelper.UNSPECIFIED_ARRAY_LENGTH
329 && expectedLength != v.length) {
330 throw new SerializationException("Trying to encode a fixed array of incorrect length.");
331 }
332 byte[] bytes = new byte[(v.length + 7) / BindingsHelper.ALIGNMENT];
333 for (int i = 0; i < bytes.length; ++i) {
334 for (int j = 0; j < BindingsHelper.ALIGNMENT; ++j) {
335 int booleanIndex = BindingsHelper.ALIGNMENT * i + j;
336 if (booleanIndex < v.length && v[booleanIndex]) {
337 bytes[i] |= (byte) (1 << j);
338 }
339 }
340 }
341 encodeByteArray(bytes, v.length, offset);
342 }
343
344 /**
345 * Encodes an array of bytes.
346 */
347 public void encode(byte[] v, int offset, int arrayNullability, int expectedL ength) {
348 if (v == null) {
349 encodeNullPointer(offset, BindingsHelper.isArrayNullable(arrayNullab ility));
350 return;
351 }
352 if (expectedLength != BindingsHelper.UNSPECIFIED_ARRAY_LENGTH
353 && expectedLength != v.length) {
354 throw new SerializationException("Trying to encode a fixed array of incorrect length.");
355 }
356 encodeByteArray(v, v.length, offset);
357 }
358
359 /**
360 * Encodes an array of shorts.
361 */
362 public void encode(short[] v, int offset, int arrayNullability, int expected Length) {
363 if (v == null) {
364 encodeNullPointer(offset, BindingsHelper.isArrayNullable(arrayNullab ility));
365 return;
366 }
367 encoderForArray(2, v.length, offset, expectedLength).append(v);
368 }
369
370 /**
371 * Encodes an array of ints.
372 */
373 public void encode(int[] v, int offset, int arrayNullability, int expectedLe ngth) {
374 if (v == null) {
375 encodeNullPointer(offset, BindingsHelper.isArrayNullable(arrayNullab ility));
376 return;
377 }
378 encoderForArray(4, v.length, offset, expectedLength).append(v);
379 }
380
381 /**
382 * Encodes an array of floats.
383 */
384 public void encode(float[] v, int offset, int arrayNullability, int expected Length) {
385 if (v == null) {
386 encodeNullPointer(offset, BindingsHelper.isArrayNullable(arrayNullab ility));
387 return;
388 }
389 encoderForArray(4, v.length, offset, expectedLength).append(v);
390 }
391
392 /**
393 * Encodes an array of longs.
394 */
395 public void encode(long[] v, int offset, int arrayNullability, int expectedL ength) {
396 if (v == null) {
397 encodeNullPointer(offset, BindingsHelper.isArrayNullable(arrayNullab ility));
398 return;
399 }
400 encoderForArray(8, v.length, offset, expectedLength).append(v);
401 }
402
403 /**
404 * Encodes an array of doubles.
405 */
406 public void encode(double[] v, int offset, int arrayNullability, int expecte dLength) {
407 if (v == null) {
408 encodeNullPointer(offset, BindingsHelper.isArrayNullable(arrayNullab ility));
409 return;
410 }
411 encoderForArray(8, v.length, offset, expectedLength).append(v);
412 }
413
414 /**
415 * Encodes an array of {@link Handle}.
416 */
417 public void encode(Handle[] v, int offset, int arrayNullability, int expecte dLength) {
418 if (v == null) {
419 encodeNullPointer(offset, BindingsHelper.isArrayNullable(arrayNullab ility));
420 return;
421 }
422 Encoder e = encoderForArray(
423 BindingsHelper.SERIALIZED_HANDLE_SIZE, v.length, offset, expecte dLength);
424 for (int i = 0; i < v.length; ++i) {
425 e.encode(v[i], DataHeader.HEADER_SIZE + BindingsHelper.SERIALIZED_HA NDLE_SIZE * i,
426 BindingsHelper.isElementNullable(arrayNullability));
427 }
428 }
429
430 /**
431 * Encodes an array of {@link Interface}.
432 */
433 public <T extends Interface> void encode(T[] v, int offset, int arrayNullabi lity,
434 int expectedLength, Interface.Manager<T, ?> manager) {
435 if (v == null) {
436 encodeNullPointer(offset, BindingsHelper.isArrayNullable(arrayNullab ility));
437 return;
438 }
439 Encoder e = encoderForArray(
440 BindingsHelper.SERIALIZED_INTERFACE_SIZE, v.length, offset, expe ctedLength);
441 for (int i = 0; i < v.length; ++i) {
442 e.encode(v[i], DataHeader.HEADER_SIZE + BindingsHelper.SERIALIZED_IN TERFACE_SIZE * i,
443 BindingsHelper.isElementNullable(arrayNullability), manager) ;
444 }
445 }
446
447 public Encoder encoderForMap(int offset) {
448 encodePointerToNextUnclaimedData(offset);
449 return getEncoderAtDataOffset(BindingsHelper.MAP_STRUCT_HEADER);
450 }
451
452 /**
453 * Encodes a pointer to the next unclaimed memory and returns an encoder sui table to encode an
454 * union at this location.
455 */
456 public Encoder encoderForUnionPointer(int offset) {
457 encodePointerToNextUnclaimedData(offset);
458 Encoder result = new Encoder(mEncoderState);
459 result.mEncoderState.claimMemory(16);
460 return result;
461 }
462
463 /**
464 * Encodes an array of {@link InterfaceRequest}.
465 */
466 public <I extends Interface> void encode(InterfaceRequest<I>[] v, int offset ,
467 int arrayNullability, int expectedLength) {
468 if (v == null) {
469 encodeNullPointer(offset, BindingsHelper.isArrayNullable(arrayNullab ility));
470 return;
471 }
472 Encoder e = encoderForArray(
473 BindingsHelper.SERIALIZED_HANDLE_SIZE, v.length, offset, expecte dLength);
474 for (int i = 0; i < v.length; ++i) {
475 e.encode(v[i], DataHeader.HEADER_SIZE + BindingsHelper.SERIALIZED_HA NDLE_SIZE * i,
476 BindingsHelper.isElementNullable(arrayNullability));
477 }
478 }
479
480 /**
481 * Encodes a <code>null</code> pointer iff the object is nullable, raises an exception
482 * otherwise.
483 */
484 public void encodeNullPointer(int offset, boolean nullable) {
485 if (!nullable) {
486 throw new SerializationException(
487 "Trying to encode a null pointer for a non-nullable type.");
488 }
489 mEncoderState.byteBuffer.putLong(mBaseOffset + offset, 0);
490 }
491
492 /**
493 * Encodes an invalid handle iff the object is nullable, raises an exception otherwise.
494 */
495 public void encodeInvalidHandle(int offset, boolean nullable) {
496 if (!nullable) {
497 throw new SerializationException(
498 "Trying to encode an invalid handle for a non-nullable type. ");
499 }
500 mEncoderState.byteBuffer.putInt(mBaseOffset + offset, -1);
501 }
502
503 /**
504 * Claim the given amount of memory at the end of the buffer, resizing it if needed.
505 */
506 void claimMemory(int size) {
507 mEncoderState.claimMemory(BindingsHelper.align(size));
508 }
509
510 private void encodePointerToNextUnclaimedData(int offset) {
511 encode((long) mEncoderState.dataEnd - (mBaseOffset + offset), offset);
512 }
513
514 private Encoder encoderForArray(
515 int elementSizeInByte, int length, int offset, int expectedLength) {
516 if (expectedLength != BindingsHelper.UNSPECIFIED_ARRAY_LENGTH
517 && expectedLength != length) {
518 throw new SerializationException("Trying to encode a fixed array of incorrect length.");
519 }
520 return encoderForArrayByTotalSize(length * elementSizeInByte, length, of fset);
521 }
522
523 private Encoder encoderForArrayByTotalSize(int byteSize, int length, int off set) {
524 encodePointerToNextUnclaimedData(offset);
525 return getEncoderAtDataOffset(
526 new DataHeader(DataHeader.HEADER_SIZE + byteSize, length));
527 }
528
529 private void encodeByteArray(byte[] bytes, int length, int offset) {
530 encoderForArrayByTotalSize(bytes.length, length, offset).append(bytes);
531 }
532
533 private void append(byte[] v) {
534 mEncoderState.byteBuffer.position(mBaseOffset + DataHeader.HEADER_SIZE);
535 mEncoderState.byteBuffer.put(v);
536 }
537
538 private void append(short[] v) {
539 mEncoderState.byteBuffer.position(mBaseOffset + DataHeader.HEADER_SIZE);
540 mEncoderState.byteBuffer.asShortBuffer().put(v);
541 }
542
543 private void append(int[] v) {
544 mEncoderState.byteBuffer.position(mBaseOffset + DataHeader.HEADER_SIZE);
545 mEncoderState.byteBuffer.asIntBuffer().put(v);
546 }
547
548 private void append(float[] v) {
549 mEncoderState.byteBuffer.position(mBaseOffset + DataHeader.HEADER_SIZE);
550 mEncoderState.byteBuffer.asFloatBuffer().put(v);
551 }
552
553 private void append(double[] v) {
554 mEncoderState.byteBuffer.position(mBaseOffset + DataHeader.HEADER_SIZE);
555 mEncoderState.byteBuffer.asDoubleBuffer().put(v);
556 }
557
558 private void append(long[] v) {
559 mEncoderState.byteBuffer.position(mBaseOffset + DataHeader.HEADER_SIZE);
560 mEncoderState.byteBuffer.asLongBuffer().put(v);
561 }
562
563 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698