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

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

Issue 317273006: Add serialization/deserialization of structs for mojo java bindings. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 5 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 | Annotate | Revision Log
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.Struct.DataHeader;
8 import org.chromium.mojo.system.Core;
9 import org.chromium.mojo.system.Handle;
10
11 import java.nio.ByteBuffer;
12 import java.nio.ByteOrder;
13 import java.nio.charset.Charset;
14 import java.util.ArrayList;
15 import java.util.List;
16
17 /**
18 * Helper class to encode a mojo struct. It keeps track of the output buffer, re sizing it as needed.
19 * It also keeps track of the associated handles, and the offset of the current data section.
20 */
21 public class Encoder {
22
23 /**
24 * Container class for all state that must be shared between the main encode r and any used sub
25 * encoder.
26 */
27 private static class EncoderState {
28
29 /**
30 * The core used to encode interfaces.
31 */
32 public final Core core;
33
34 /**
35 * The ByteBuffer to which the message will be encoded.
36 */
37 public ByteBuffer byteBuffer;
38
39 /**
40 * The list of encountered handles.
41 */
42 public final List<Handle> handles = new ArrayList<Handle>();
43
44 /**
45 * The current absolute position for the next data section.
46 */
47 public int dataEnd;
48
49 /**
50 * @param core the |Core| implementation used to generate handles. Only used if the |Struct|
51 * being encoded contains interfaces, can be |null| otherwise .
52 * @param bufferSize A hint on the size of the message. Used to build th e initial byte
53 * buffer.
54 */
55 private EncoderState(Core core, int bufferSize) {
56 assert bufferSize % BindingsHelper.ALIGNMENT == 0;
57 this.core = core;
58 byteBuffer = ByteBuffer.allocateDirect(
59 bufferSize > 0 ? bufferSize : INITIAL_BUFFER_SIZE);
60 byteBuffer.order(ByteOrder.nativeOrder());
61 dataEnd = 0;
62 }
63
64 /**
65 * Claim the given amount of memory at the end of the buffer, resizing i t if needed.
66 */
67 public void claimMemory(int size) {
68 dataEnd += size;
69 growIfNeeded();
70 }
71
72 /**
73 * Grow the associated ByteBuffer if needed.
74 */
75 private void growIfNeeded() {
76 if (byteBuffer.capacity() >= dataEnd) {
77 return;
78 }
79 int targetSize = byteBuffer.capacity() * 2;
80 while (targetSize < dataEnd) {
81 targetSize *= 2;
82 }
83 ByteBuffer newBuffer = ByteBuffer.allocateDirect(targetSize);
84 newBuffer.order(ByteOrder.nativeOrder());
85 byteBuffer.position(0);
86 byteBuffer.limit(byteBuffer.capacity());
87 newBuffer.put(byteBuffer);
88 byteBuffer = newBuffer;
89 }
90 }
91
92 /**
93 * Default initial size of the data buffer. This must be a multiple of 8 byt es.
94 */
95 private static final int INITIAL_BUFFER_SIZE = 1024;
96
97 /**
98 * Base offset in the byte buffer for writing.
99 */
100 private int mBaseOffset;
101
102 /**
103 * The encoder state shared by the main encoder and all its sub-encoder.
104 */
105 private final EncoderState mEncoderState;
106
107 /**
108 * Returns the result message.
109 */
110 public Message getMessage() {
111 mEncoderState.byteBuffer.position(0);
112 mEncoderState.byteBuffer.limit(mEncoderState.dataEnd);
113 return new Message(mEncoderState.byteBuffer, mEncoderState.handles);
114 }
115
116 /**
117 * Constructor.
118 *
119 * @param core the |Core| implementation used to generate handles. Only used if the |Struct|
120 * being encoded contains interfaces, can be |null| otherwise.
121 * @param sizeHint A hint on the size of the message. Used to build the init ial byte buffer.
122 */
123 public Encoder(Core core, int sizeHint) {
124 this(new EncoderState(core, sizeHint));
125 }
126
127 /**
128 * Private constructor for sub-encoders.
129 */
130 private Encoder(EncoderState bufferInformation) {
131 mEncoderState = bufferInformation;
132 mBaseOffset = bufferInformation.dataEnd;
133 }
134
135 /**
136 * Returns a new encoder that will append to the current buffer.
137 */
138 public Encoder getEncoderAtDataOffset(DataHeader dataHeader) {
139 Encoder result = new Encoder(mEncoderState);
140 result.encode(dataHeader);
141 return result;
142
143 }
144
145 /**
146 * Encode a {@link DataHeader} and claim the amount of memory required for t he data section
147 * (resizing the buffer if required).
148 */
149 public void encode(DataHeader s) {
150 mEncoderState.claimMemory(s.size);
151 encode(s.size, DataHeader.SIZE_OFFSET);
152 encode(s.numFields, DataHeader.NUM_FIELDS_OFFSET);
153 }
154
155 /**
156 * Encode a byte at the given offset.
157 */
158 public void encode(byte v, int offset) {
159 mEncoderState.byteBuffer.put(mBaseOffset + offset, v);
160 }
161
162 /**
163 * Encode a boolean at the given offset.
164 */
165 public void encode(boolean v, int offset, int bit) {
166 if (v) {
167 byte encodedValue = mEncoderState.byteBuffer.get(mBaseOffset + offse t);
168 encodedValue |= 1 << bit;
169 mEncoderState.byteBuffer.put(mBaseOffset + offset, encodedValue);
170 }
171 }
172
173 /**
174 * Encode a short at the given offset.
175 */
176 public void encode(short v, int offset) {
177 mEncoderState.byteBuffer.putShort(mBaseOffset + offset, v);
178 }
179
180 /**
181 * Encode an int at the given offset.
182 */
183 public void encode(int v, int offset) {
184 mEncoderState.byteBuffer.putInt(mBaseOffset + offset, v);
185 }
186
187 /**
188 * Encode a float at the given offset.
189 */
190 public void encode(float v, int offset) {
191 mEncoderState.byteBuffer.putFloat(mBaseOffset + offset, v);
192 }
193
194 /**
195 * Encode a long at the given offset.
196 */
197 public void encode(long v, int offset) {
198 mEncoderState.byteBuffer.putLong(mBaseOffset + offset, v);
199 }
200
201 /**
202 * Encode a double at the given offset.
203 */
204 public void encode(double v, int offset) {
205 mEncoderState.byteBuffer.putDouble(mBaseOffset + offset, v);
206 }
207
208 /**
209 * Encode a {@link Struct} at the given offset.
210 */
211 public void encode(Struct v, int offset) {
212 if (v == null) {
213 encodeNullPointer(offset);
214 return;
215 }
216 encodePointerToNextUnclaimedData(offset);
217 v.encode(this);
218 }
219
220 /**
221 * Encodes a String.
222 */
223 public void encode(String v, int offset) {
224 if (v == null) {
225 encodeNullPointer(offset);
226 return;
227 }
228 encode(v.getBytes(Charset.forName("utf8")), offset);
229 }
230
231 /**
232 * Encodes a {@link Handle}.
233 */
234 public void encode(Handle v, int offset) {
235 if (v == null || !v.isValid()) {
236 encode(-1, offset);
237 } else {
238 encode(mEncoderState.handles.size(), offset);
239 mEncoderState.handles.add(v);
240 }
241 }
242
243 /**
244 * Encode an {@link Interface}.
245 */
246 public <T extends Interface> void encode(T v, int offset, Object builder) {
247 if (mEncoderState.core == null) {
248 throw new UnsupportedOperationException(
249 "The encoder has been created without a Core. It can't encod e an interface.");
250 }
251 // TODO(qsr): To be implemented when interfaces proxy and stubs are impl emented.
252 throw new UnsupportedOperationException("Unimplemented operation");
253 }
254
255 /**
256 * Encode an {@link InterfaceRequest}.
257 */
258 public <T extends Interface> void encode(InterfaceRequest<T> v, int offset) {
259 if (mEncoderState.core == null) {
260 throw new UnsupportedOperationException(
261 "The encoder has been created without a Core. It can't encod e an interface.");
262 }
263 // TODO(qsr): To be implemented when interfaces proxy and stubs are impl emented.
264 throw new UnsupportedOperationException("Unimplemented operation");
265 }
266
267 /**
268 * Returns an {@link Encoder} suitable for encoding an array of pointer of t he given length.
269 */
270 public Encoder encodePointerArray(int length, int offset) {
271 return encoderForArray(BindingsHelper.POINTER_SIZE, length, offset);
272 }
273
274 /**
275 * Encodes an array of booleans.
276 */
277 public void encode(boolean[] v, int offset) {
278 if (v == null) {
279 encodeNullPointer(offset);
280 return;
281 }
282 byte[] bytes = new byte[(v.length + 7) / BindingsHelper.ALIGNMENT];
283 for (int i = 0; i < bytes.length; ++i) {
284 for (int j = 0; j < BindingsHelper.ALIGNMENT; ++j) {
285 int booleanIndex = BindingsHelper.ALIGNMENT * i + j;
286 if (booleanIndex < v.length && v[booleanIndex]) {
287 bytes[i] |= (1 << j);
288 }
289 }
290 }
291 encodeByteArray(bytes, v.length, offset);
292 }
293
294 /**
295 * Encodes an array of bytes.
296 */
297 public void encode(byte[] v, int offset) {
298 if (v == null) {
299 encodeNullPointer(offset);
300 return;
301 }
302 encodeByteArray(v, v.length, offset);
303 }
304
305 /**
306 * Encodes an array of shorts.
307 */
308 public void encode(short[] v, int offset) {
309 if (v == null) {
310 encodeNullPointer(offset);
311 return;
312 }
313 encoderForArray(2, v.length, offset).append(v);
314 }
315
316 /**
317 * Encodes an array of ints.
318 */
319 public void encode(int[] v, int offset) {
320 if (v == null) {
321 encodeNullPointer(offset);
322 return;
323 }
324 encoderForArray(4, v.length, offset).append(v);
325 }
326
327 /**
328 * Encodes an array of floats.
329 */
330 public void encode(float[] v, int offset) {
331 if (v == null) {
332 encodeNullPointer(offset);
333 return;
334 }
335 encoderForArray(4, v.length, offset).append(v);
336 }
337
338 /**
339 * Encodes an array of longs.
340 */
341 public void encode(long[] v, int offset) {
342 if (v == null) {
343 encodeNullPointer(offset);
344 return;
345 }
346 encoderForArray(8, v.length, offset).append(v);
347 }
348
349 /**
350 * Encodes an array of doubles.
351 */
352 public void encode(double[] v, int offset) {
353 if (v == null) {
354 encodeNullPointer(offset);
355 return;
356 }
357 encoderForArray(8, v.length, offset).append(v);
358 }
359
360 /**
361 * Encodes an array of {@link Handle}.
362 */
363 public void encode(Handle[] v, int offset) {
364 if (v == null) {
365 encodeNullPointer(offset);
366 return;
367 }
368 Encoder e = encoderForArray(BindingsHelper.SERIALIZED_HANDLE_SIZE, v.len gth, offset);
369 for (int i = 0; i < v.length; ++i) {
370 e.encode(v[i], DataHeader.HEADER_SIZE + BindingsHelper.SERIALIZED_HA NDLE_SIZE * i);
371 }
372 }
373
374 /**
375 * Encodes an array of {@link Interface}.
376 */
377 public <T extends Interface> void encode(T[] v, int offset, Object builder) {
378 if (v == null) {
379 encodeNullPointer(offset);
380 return;
381 }
382 Encoder e = encoderForArray(BindingsHelper.SERIALIZED_HANDLE_SIZE, v.len gth, offset);
383 for (int i = 0; i < v.length; ++i) {
384 e.encode(v[i], DataHeader.HEADER_SIZE + BindingsHelper.SERIALIZED_HA NDLE_SIZE * i,
385 builder);
386 }
387 }
388
389 /**
390 * Encodes an array of {@link Interface}.
391 */
392 public <T extends Interface> void encode(InterfaceRequest<T>[] v, int offset ) {
393 if (v == null) {
394 encodeNullPointer(offset);
395 return;
396 }
397 Encoder e = encoderForArray(BindingsHelper.SERIALIZED_HANDLE_SIZE, v.len gth, offset);
398 for (int i = 0; i < v.length; ++i) {
399 e.encode(v[i], DataHeader.HEADER_SIZE + BindingsHelper.SERIALIZED_HA NDLE_SIZE * i);
400 }
401 }
402
403 /**
404 * Encode a <code>null</code> pointer.
405 */
406 public void encodeNullPointer(int offset) {
407 mEncoderState.byteBuffer.putLong(mBaseOffset + offset, 0);
408 }
409
410 private void encodePointerToNextUnclaimedData(int offset) {
411 encode((long) mEncoderState.dataEnd - (mBaseOffset + offset), offset);
412 }
413
414 private Encoder encoderForArray(int elementSizeInByte, int length, int offse t) {
415 return encoderForArrayByTotalSize(length * elementSizeInByte, length, of fset);
416 }
417
418 private Encoder encoderForArrayByTotalSize(int byteSize, int length, int off set) {
419 encodePointerToNextUnclaimedData(offset);
420 return getEncoderAtDataOffset(
421 new DataHeader(DataHeader.HEADER_SIZE + BindingsHelper.align(byt eSize), length));
422 }
423
424 private void encodeByteArray(byte[] bytes, int length, int offset) {
425 encoderForArrayByTotalSize(bytes.length, length, offset).append(bytes);
426 }
427
428 private void append(byte[] v) {
429 mEncoderState.byteBuffer.position(mBaseOffset + DataHeader.HEADER_SIZE);
430 mEncoderState.byteBuffer.put(v);
431 }
432
433 private void append(short[] v) {
434 mEncoderState.byteBuffer.position(mBaseOffset + DataHeader.HEADER_SIZE);
435 mEncoderState.byteBuffer.asShortBuffer().put(v);
436 }
437
438 private void append(int[] v) {
439 mEncoderState.byteBuffer.position(mBaseOffset + DataHeader.HEADER_SIZE);
440 mEncoderState.byteBuffer.asIntBuffer().put(v);
441 }
442
443 private void append(float[] v) {
444 mEncoderState.byteBuffer.position(mBaseOffset + DataHeader.HEADER_SIZE);
445 mEncoderState.byteBuffer.asFloatBuffer().put(v);
446 }
447
448 private void append(double[] v) {
449 mEncoderState.byteBuffer.position(mBaseOffset + DataHeader.HEADER_SIZE);
450 mEncoderState.byteBuffer.asDoubleBuffer().put(v);
451 }
452
453 private void append(long[] v) {
454 mEncoderState.byteBuffer.position(mBaseOffset + DataHeader.HEADER_SIZE);
455 mEncoderState.byteBuffer.asLongBuffer().put(v);
456 }
457
458 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698