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

Side by Side Diff: mojo/public/rust/src/bindings/mojom.rs

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
« no previous file with comments | « mojo/public/rust/src/bindings/mod.rs ('k') | mojo/public/rust/src/bindings/run_loop.rs » ('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 2016 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 use bindings::decoding::{Decoder, ValidationError};
6 use bindings::encoding;
7 use bindings::encoding::{Bits, Encoder, Context, DATA_HEADER_SIZE, DataHeader, D ataHeaderValue};
8 use bindings::message::MessageHeader;
9
10 use std::cmp::Eq;
11 use std::collections::HashMap;
12 use std::hash::Hash;
13 use std::mem;
14 use std::panic;
15 use std::ptr;
16 use std::vec::Vec;
17
18 use system::{MojoResult, CastHandle, Handle, UntypedHandle};
19 use system::data_pipe;
20 use system::message_pipe;
21 use system::shared_buffer;
22 use system::wait_set;
23
24 /// The size of a Mojom map plus header in bytes.
25 const MAP_SIZE: usize = 24;
26
27 /// The sorted set of versions for a map.
28 const MAP_VERSIONS: [(u32, u32); 1] = [(0, MAP_SIZE as u32)];
29
30 /// The size of a Mojom union in bytes (header included).
31 pub const UNION_SIZE: usize = 16;
32
33 /// The size of a Mojom pointer in bits.
34 pub const POINTER_BIT_SIZE: Bits = Bits(64);
35
36 /// The value of a Mojom null pointer.
37 pub const MOJOM_NULL_POINTER: u64 = 0;
38
39 /// An enumeration of all the possible low-level Mojom types.
40 pub enum MojomType {
41 Simple,
42 Pointer,
43 Union,
44 Handle,
45 Interface,
46 }
47
48 /// Whatever implements this trait can be serialized in the Mojom format.
49 pub trait MojomEncodable: Sized {
50 /// Get the Mojom type.
51 fn mojom_type() -> MojomType;
52
53 /// Get this type's Mojom alignment.
54 fn mojom_alignment() -> usize;
55
56 /// The amount of space in bits the type takes up when inlined
57 /// into another type at serialization time.
58 fn embed_size(context: &Context) -> Bits;
59
60 /// Recursively computes the size of the complete Mojom archive
61 /// starting from this type.
62 fn compute_size(&self, context: Context) -> usize;
63
64 /// Encodes this type into the encoder given a context.
65 fn encode(self, encoder: &mut Encoder, context: Context);
66
67 /// Using a decoder, decodes itself out of a byte buffer.
68 fn decode(decoder: &mut Decoder, context: Context) -> Result<Self, Validatio nError>;
69 }
70
71 /// Whatever implements this trait is a Mojom pointer type which means
72 /// that on encode, a pointer is inlined and the implementer is
73 /// serialized elsewhere in the output buffer.
74 pub trait MojomPointer: MojomEncodable {
75 /// Get the DataHeader meta-data for this pointer type.
76 fn header_data(&self) -> DataHeaderValue;
77
78 /// Get the size of only this type when serialized.
79 fn serialized_size(&self, context: &Context) -> usize;
80
81 /// Encodes the actual values of the type into the encoder.
82 fn encode_value(self, encoder: &mut Encoder, context: Context);
83
84 /// Decodes the actual values of the type into the decoder.
85 fn decode_value(decoder: &mut Decoder, context: Context) -> Result<Self, Val idationError>;
86
87 /// Writes a pointer inlined into the current context before calling
88 /// encode_value.
89 fn encode_new(self, encoder: &mut Encoder, context: Context) {
90 let data_size = self.serialized_size(&context);
91 let data_header = DataHeader::new(data_size, self.header_data());
92 let new_context = encoder.add(&data_header).unwrap();
93 self.encode_value(encoder, new_context);
94 }
95
96 /// Reads a pointer inlined into the current context before calling
97 /// decode_value.
98 fn decode_new(decoder: &mut Decoder, _context: Context, pointer: u64) -> Res ult<Self, ValidationError> {
99 match decoder.claim(pointer as usize) {
100 Ok(new_context) => Self::decode_value(decoder, new_context),
101 Err(err) => Err(err),
102 }
103 }
104 }
105
106 /// Whatever implements this trait is a Mojom union type which means that
107 /// on encode it is inlined, but if the union is nested inside of another
108 /// union type, it is treated as a pointer type.
109 pub trait MojomUnion: MojomEncodable {
110 /// Get the union's current tag.
111 fn get_tag(&self) -> u32;
112
113 /// Encode the actual value of the union.
114 fn encode_value(self, encoder: &mut Encoder, context: Context);
115
116 /// Decode the actual value of the union.
117 fn decode_value(decoder: &mut Decoder, context: Context) -> Result<Self, Val idationError>;
118
119 /// The embed_size for when the union acts as a pointer type.
120 fn nested_embed_size() -> Bits {
121 POINTER_BIT_SIZE
122 }
123
124 /// The encoding routine for when the union acts as a pointer type.
125 fn nested_encode(self, encoder: &mut Encoder, context: Context) {
126 let loc = encoder.size() as u64;
127 {
128 let state = encoder.get_mut(&context);
129 state.encode_pointer(loc);
130 }
131 let tag = DataHeaderValue::UnionTag(self.get_tag());
132 let data_header = DataHeader::new(UNION_SIZE, tag);
133 let new_context = encoder.add(&data_header).unwrap();
134 self.encode_value(encoder, new_context.set_is_union(true));
135 }
136
137 /// The decoding routine for when the union acts as a pointer type.
138 fn nested_decode(decoder: &mut Decoder, context: Context) -> Result<Self, Va lidationError> {
139 let global_offset = {
140 let state = decoder.get_mut(&context);
141 match state.decode_pointer() {
142 Some(ptr) => ptr as usize,
143 None => return Err(ValidationError::IllegalPointer),
144 }
145 };
146 if global_offset == (MOJOM_NULL_POINTER as usize) {
147 return Err(ValidationError::UnexpectedNullPointer);
148 }
149 match decoder.claim(global_offset as usize) {
150 Ok(new_context) => Self::decode_value(decoder, new_context),
151 Err(err) => Err(err),
152 }
153 }
154
155 /// The embed_size for when the union is inlined into the current context.
156 fn inline_embed_size() -> Bits {
157 Bits(8 * (UNION_SIZE as usize))
158 }
159
160 /// The encoding routine for when the union is inlined into the current cont ext.
161 fn inline_encode(self, encoder: &mut Encoder, context: Context) {
162 {
163 let mut state = encoder.get_mut(&context);
164 state.align_to_bytes(8);
165 state.encode(UNION_SIZE as u32);
166 state.encode(self.get_tag());
167 }
168 self.encode_value(encoder, context.clone());
169 {
170 let mut state = encoder.get_mut(&context);
171 state.align_to_bytes(8);
172 state.align_to_byte();
173 }
174 }
175
176 /// The decoding routine for when the union is inlined into the current cont ext.
177 fn inline_decode(decoder: &mut Decoder, context: Context) -> Result<Self, Va lidationError> {
178 {
179 let mut state = decoder.get_mut(&context);
180 state.align_to_byte();
181 state.align_to_bytes(8);
182 }
183 let value = Self::decode_value(decoder, context.clone());
184 {
185 let mut state = decoder.get_mut(&context);
186 state.align_to_byte();
187 state.align_to_bytes(8);
188 }
189 value
190 }
191 }
192
193 /// A marker trait that marks Mojo handles as encodable.
194 pub trait MojomHandle: CastHandle + MojomEncodable {}
195
196 /// Whatever implements this trait is considered to be a Mojom
197 /// interface, that is, a message pipe which conforms to some
198 /// messaging interface.
199 ///
200 /// We force an underlying message pipe to be used via the pipe()
201 /// and unwrap() routines.
202 pub trait MojomInterface: MojomEncodable {
203 /// Get the service name for this interface.
204 fn service_name() -> &'static str;
205
206 /// Get the version for this interface.
207 fn version(&self) -> u32;
208
209 /// Access the underlying message pipe for this interface.
210 fn pipe(&self) -> &message_pipe::MessageEndpoint;
211
212 /// Unwrap the interface into its underlying message pipe.
213 fn unwrap(self) -> message_pipe::MessageEndpoint;
214 }
215
216 /// An error that may occur when sending data over a Mojom interface.
217 #[derive(Debug)]
218 pub enum MojomSendError {
219 /// Failed to write to the underlying message pipe.
220 FailedWrite(MojoResult),
221
222 /// The version is too old to write the attempted message.
223 OldVersion(u32, u32),
224 }
225
226 /// Whatever implements this trait is considered to be a Mojom
227 /// interface that may send messages of some generic type.
228 ///
229 /// When implementing this trait, the correct way is to specify
230 /// a tighter trait bound than MojomMessage that limits the types
231 /// available for sending to those that are valid messages available
232 /// to the interface.
233 ///
234 /// TODO(mknyszek): Add sending control messages
235 pub trait MojomInterfaceSend<R: MojomMessage>: MojomInterface {
236 /// Creates a message.
237 fn create_request(&self, req_id: u64, payload: R) -> (Vec<u8>, Vec<UntypedHa ndle>) {
238 let mut header = R::create_header();
239 header.request_id = req_id;
240 let header_size = header.compute_size(Default::default());
241 let size = header_size + payload.compute_size(Default::default());
242 let mut buffer: Vec<u8> = Vec::with_capacity(size);
243 buffer.resize(size, 0);
244 let handles = {
245 let (header_buf, rest_buf) = buffer.split_at_mut(header_size);
246 let mut handles = header.serialize(header_buf);
247 handles.extend(payload.serialize(rest_buf).into_iter());
248 handles
249 };
250 (buffer, handles)
251 }
252
253 /// Creates and sends a message, and returns its request ID.
254 fn send_request(&self, req_id: u64, payload: R) -> Result<(), MojomSendError > {
255 if self.version() < R::min_version() {
256 return Err(MojomSendError::OldVersion(self.version(), R::min_version ()));
257 }
258 let (buffer, handles) = self.create_request(req_id, payload);
259 match self.pipe().write(&buffer, handles, mpflags!(Write::None)) {
260 MojoResult::Okay => Ok(()),
261 err => Err(MojomSendError::FailedWrite(err)),
262 }
263 }
264 }
265
266 /// An error that may occur when attempting to recieve a message over a
267 /// Mojom interface.
268 #[derive(Debug)]
269 pub enum MojomRecvError {
270 /// Failed to read from the underlying message pipe.
271 FailedRead(MojoResult),
272
273 /// Failed to validate the buffer during decode.
274 FailedValidation(ValidationError),
275 }
276
277 /// Whatever implements this trait is considered to be a Mojom
278 /// interface that may recieve messages for some interface.
279 ///
280 /// When implementing this trait, specify the container "union" type
281 /// which can contain any of the potential messages that may be recieved.
282 /// This way, we can return that type and let the user multiplex over
283 /// what message was received.
284 ///
285 /// TODO(mknyszek): Add responding to control messages
286 pub trait MojomInterfaceRecv: MojomInterface {
287 type Container: MojomMessageOption;
288
289 /// Tries to read a message from a pipe and decodes it.
290 fn recv_response(&self) -> Result<(u64, Self::Container), MojomRecvError> {
291 match self.pipe().read(mpflags!(Read::None)) {
292 Ok((buffer, handles)) => {
293 match Self::Container::decode_message(buffer, handles) {
294 Ok((req_id, val)) => Ok((req_id, val)),
295 Err(err) => Err(MojomRecvError::FailedValidation(err)),
296 }
297 },
298 Err(err) => Err(MojomRecvError::FailedRead(err)),
299 }
300 }
301 }
302
303 /// Whatever implements this trait is considered to be a Mojom struct.
304 ///
305 /// Mojom structs are always the root of any Mojom message. Thus, we
306 /// provide convenience functions for serialization here.
307 pub trait MojomStruct: MojomPointer {
308 /// Given a pre-allocated buffer, the struct serializes itself.
309 fn serialize(self, buffer: &mut [u8]) -> Vec<UntypedHandle> {
310 let mut encoder = Encoder::new(buffer);
311 self.encode_new(&mut encoder, Default::default());
312 encoder.unwrap()
313 }
314
315 /// The struct computes its own size, allocates a buffer, and then
316 /// serializes itself into that buffer.
317 fn auto_serialize(self) -> (Vec<u8>, Vec<UntypedHandle>) {
318 let size = self.compute_size(Default::default());
319 let mut buf = Vec::with_capacity(size);
320 buf.resize(size, 0);
321 let handles = self.serialize(&mut buf);
322 (buf, handles)
323 }
324
325 /// Decode the type from a byte array and a set of handles.
326 fn deserialize(buffer: &[u8], handles: Vec<UntypedHandle>) -> Result<Self, V alidationError> {
327 let mut decoder = Decoder::new(buffer, handles);
328 Self::decode_new(&mut decoder, Default::default(), 0)
329 }
330 }
331
332 /// Marks a MojomStruct as being capable of being sent across some
333 /// Mojom interface.
334 pub trait MojomMessage: MojomStruct {
335 fn min_version() -> u32;
336 fn create_header() -> MessageHeader;
337 }
338
339 /// The trait for a "container" type intended to be used in MojomInterfaceRecv.
340 ///
341 /// This trait contains the decode logic which decodes based on the message head er
342 /// and returns itself: a union type which may contain any of the possible messa ges
343 /// that may be sent across this interface.
344 pub trait MojomMessageOption: Sized {
345 /// Decodes the actual payload of the message.
346 ///
347 /// Implemented by a code generator.
348 fn decode_payload(header: MessageHeader, buffer: &[u8], handles: Vec<Untyped Handle>) -> Result<Self, ValidationError>;
349
350 /// Decodes the message header and then the payload, returning a new
351 /// copy of itself and the request ID found in the header.
352 fn decode_message(buffer: Vec<u8>, handles: Vec<UntypedHandle>) -> Result<(u 64, Self), ValidationError> {
353 let header = try!(MessageHeader::deserialize(&buffer[..], Vec::new()));
354 let payload_buffer = &buffer[header.serialized_size(&Default::default()) ..];
355 let req_id = header.request_id;
356 let ret = try!(Self::decode_payload(header, payload_buffer, handles));
357 Ok((req_id, ret))
358 }
359 }
360
361 // ********************************************** //
362 // ****** IMPLEMENTATIONS FOR COMMON TYPES ****** //
363 // ********************************************** //
364
365 macro_rules! impl_encodable_for_prim {
366 ($($prim_type:ty),*) => {
367 $(
368 impl MojomEncodable for $prim_type {
369 fn mojom_type() -> MojomType {
370 MojomType::Simple
371 }
372 fn mojom_alignment() -> usize {
373 mem::size_of::<$prim_type>()
374 }
375 fn embed_size(_context: &Context) -> Bits {
376 Bits(8 * mem::size_of::<$prim_type>())
377 }
378 fn compute_size(&self, _context: Context) -> usize {
379 0 // Indicates that this type is inlined and it adds nothing ext ernal to the size
380 }
381 fn encode(self, encoder: &mut Encoder, context: Context) {
382 let mut state = encoder.get_mut(&context);
383 state.encode(self);
384 }
385 fn decode(decoder: &mut Decoder, context: Context) -> Result<Self, V alidationError> {
386 let mut state = decoder.get_mut(&context);
387 Ok(state.decode::<Self>())
388 }
389 }
390 )*
391 }
392 }
393
394 impl_encodable_for_prim!(i8, i16, i32, i64, u8, u16, u32, u64, f32, f64);
395
396 impl MojomEncodable for bool {
397 fn mojom_alignment() -> usize {
398 panic!("Should never check_decode mojom_alignment of bools (they're bit- aligned)!");
399 }
400 fn mojom_type() -> MojomType {
401 MojomType::Simple
402 }
403 fn embed_size(_context: &Context) -> Bits {
404 Bits(1)
405 }
406 fn compute_size(&self, _context: Context) -> usize {
407 0 // Indicates that this type is inlined and it adds nothing external to the size
408 }
409 fn encode(self, encoder: &mut Encoder, context: Context) {
410 let mut state = encoder.get_mut(&context);
411 state.encode_bool(self);
412 }
413 fn decode(decoder: &mut Decoder, context: Context) -> Result<Self, Validatio nError> {
414 let mut state = decoder.get_mut(&context);
415 Ok(state.decode_bool())
416 }
417 }
418
419 // Options should be considered to represent nullability the Mojom IDL.
420 // Any type wrapped in an Option type is nullable.
421
422 impl<T: MojomEncodable> MojomEncodable for Option<T> {
423 fn mojom_alignment() -> usize {
424 T::mojom_alignment()
425 }
426 fn mojom_type() -> MojomType {
427 T::mojom_type()
428 }
429 fn embed_size(context: &Context) -> Bits {
430 T::embed_size(context)
431 }
432 fn compute_size(&self, context: Context) -> usize {
433 match *self {
434 Some(ref value) => value.compute_size(context),
435 None => 0,
436 }
437 }
438 fn encode(self, encoder: &mut Encoder, context: Context) {
439 match self {
440 Some(value) => value.encode(encoder, context),
441 None => {
442 let mut state = encoder.get_mut(&context);
443 match T::mojom_type() {
444 MojomType::Pointer => state.encode_null_pointer(),
445 MojomType::Union => state.encode_null_union(),
446 MojomType::Handle => state.encode_null_handle(),
447 MojomType::Interface => {
448 state.encode_null_handle();
449 state.encode(0 as u32);
450 },
451 MojomType::Simple => panic!("Unexpected simple type in Optio n!"),
452 }
453 },
454 }
455 }
456 fn decode(decoder: &mut Decoder, context: Context) -> Result<Self, Validatio nError> {
457 let skipped = {
458 let mut state = decoder.get_mut(&context);
459 match T::mojom_type() {
460 MojomType::Pointer => state.skip_if_null_pointer(),
461 MojomType::Union => state.skip_if_null_union(),
462 MojomType::Handle => state.skip_if_null_handle(),
463 MojomType::Interface => state.skip_if_null_interface(),
464 MojomType::Simple => panic!("Unexpected simple type in Option!") ,
465 }
466 };
467 if skipped {
468 Ok(None)
469 } else {
470 match T::decode(decoder, context) {
471 Ok(value) => Ok(Some(value)),
472 Err(err) => Err(err),
473 }
474 }
475 }
476 }
477
478 macro_rules! impl_pointer_for_array {
479 () => {
480 fn header_data(&self) -> DataHeaderValue {
481 DataHeaderValue::Elements(self.len() as u32)
482 }
483 fn serialized_size(&self, context: &Context) -> usize {
484 DATA_HEADER_SIZE + if self.len() > 0 {
485 (T::embed_size(context) * self.len()).as_bytes()
486 } else {
487 0
488 }
489 }
490 }
491 }
492
493 macro_rules! impl_encodable_for_array {
494 () => {
495 impl_encodable_for_pointer!();
496 fn compute_size(&self, context: Context) -> usize {
497 let mut size = encoding::align_default(self.serialized_size(&context ));
498 for elem in self.iter() {
499 size += elem.compute_size(context.clone());
500 }
501 size
502 }
503 }
504 }
505
506 impl<T: MojomEncodable> MojomPointer for Vec<T> {
507 impl_pointer_for_array!();
508 fn encode_value(self, encoder: &mut Encoder, context: Context) {
509 for elem in self.into_iter() {
510 elem.encode(encoder, context.clone());
511 }
512 }
513 fn decode_value(decoder: &mut Decoder, context: Context) -> Result<Vec<T>, V alidationError> {
514 let elems = {
515 let mut state = decoder.get_mut(&context);
516 match state.decode_array_header::<T>() {
517 Ok(header) => header.data(),
518 Err(err) => return Err(err),
519 }
520 };
521 let mut value = Vec::with_capacity(elems as usize);
522 for _ in 0..elems {
523 match T::decode(decoder, context.clone()) {
524 Ok(elem) => value.push(elem),
525 Err(err) => return Err(err),
526 }
527 }
528 Ok(value)
529 }
530 }
531
532 impl<T: MojomEncodable> MojomEncodable for Vec<T> {
533 impl_encodable_for_array!();
534 }
535
536 macro_rules! impl_encodable_for_fixed_array {
537 ($($len:expr),*) => {
538 $(
539 impl<T: MojomEncodable> MojomPointer for [T; $len] {
540 impl_pointer_for_array!();
541 fn encode_value(mut self, encoder: &mut Encoder, context: Context) {
542 let mut panic_error = None;
543 let mut moves = 0;
544 unsafe {
545 // In order to move elements out of an array we need to repl ace the
546 // value with uninitialized memory.
547 for elem in self.iter_mut() {
548 let owned_elem = mem::replace(elem, mem::uninitialized() );
549 // We need to handle if an unwinding panic happens to pr event use of
550 // uninitialized memory...
551 let next_context = context.clone();
552 // We assert everything going into this closure is unwin d safe. If anything
553 // is added, PLEASE make sure it is also unwind safe...
554 let result = panic::catch_unwind(panic::AssertUnwindSafe (|| {
555 owned_elem.encode(encoder, next_context);
556 }));
557 if let Err(err) = result {
558 panic_error = Some(err);
559 break;
560 }
561 moves += 1;
562 }
563 if let Some(err) = panic_error {
564 for i in moves..self.len() {
565 ptr::drop_in_place(&mut self[i] as *mut T);
566 }
567 // Forget the array to prevent a drop
568 mem::forget(self);
569 // Continue unwinding
570 panic::resume_unwind(err);
571 }
572 // We cannot risk drop() getting run on the array values, so we just
573 // forget self.
574 mem::forget(self);
575 }
576 }
577 fn decode_value(decoder: &mut Decoder, context: Context) -> Result<[ T; $len], ValidationError> {
578 let elems = {
579 let mut state = decoder.get_mut(&context);
580 match state.decode_array_header::<T>() {
581 Ok(header) => header.data(),
582 Err(err) => return Err(err),
583 }
584 };
585 if elems != $len {
586 return Err(ValidationError::UnexpectedArrayHeader);
587 }
588 let mut array: [T; $len];
589 let mut panic_error = None;
590 let mut inits = 0;
591 let mut error = None;
592 unsafe {
593 // Since we don't force Clone to be implemented on Mojom typ es
594 // (mainly due to handles) we need to create this array as u ninitialized
595 // and initialize it manually.
596 array = mem::uninitialized();
597 for elem in &mut array[..] {
598 // When a panic unwinds it may try to read and drop unin itialized
599 // memory, so we need to catch this. However, we pass mu table state!
600 // This could be bad as we could observe a broken invari ant inside
601 // of decoder and access it as usual, but we do NOT acce ss decoder
602 // here, nor do we ever unwind through one of decoder's methods.
603 // Therefore, it should be safe to assert that decoder i s unwind safe.
604 let next_context = context.clone();
605 // We assert everything going into this closure is unwin d safe. If anything
606 // is added, PLEASE make sure it is also unwind safe...
607 let result = panic::catch_unwind(panic::AssertUnwindSafe (|| {
608 T::decode(decoder, next_context)
609 }));
610 match result {
611 Ok(non_panic_value) => match non_panic_value {
612 Ok(value) => ptr::write(elem, value),
613 Err(err) => {
614 error = Some(err);
615 break;
616 },
617 },
618 Err(err) => {
619 panic_error = Some(err);
620 break;
621 },
622 }
623 inits += 1;
624 }
625 if panic_error.is_some() || error.is_some() {
626 // Drop everything that was initialized
627 for i in 0..inits {
628 ptr::drop_in_place(&mut array[i] as *mut T);
629 }
630 // Forget the array to prevent a drop
631 mem::forget(array);
632 if let Some(err) = panic_error {
633 panic::resume_unwind(err);
634 }
635 return Err(error.take().expect("Corrupted stack?"));
636 }
637 }
638 Ok(array)
639 }
640 }
641 impl<T: MojomEncodable> MojomEncodable for [T; $len] {
642 impl_encodable_for_array!();
643 }
644 )*
645 }
646 }
647
648 // Unfortunately, we cannot be generic over the length of a fixed array
649 // even though its part of the type (this will hopefully be added in the
650 // future) so for now we implement encodable for only the first 33 fixed
651 // size array types.
652 impl_encodable_for_fixed_array!( 0, 1, 2, 3, 4, 5, 6, 7,
653 8, 9, 10, 11, 12, 13, 14, 15,
654 16, 17, 18, 19, 20, 21, 22, 23,
655 24, 25, 26, 27, 28, 29, 30, 31,
656 32);
657
658 impl<T: MojomEncodable> MojomPointer for Box<[T]> {
659 impl_pointer_for_array!();
660 fn encode_value(self, encoder: &mut Encoder, context: Context) {
661 for elem in self.into_vec().into_iter() {
662 elem.encode(encoder, context.clone());
663 }
664 }
665 fn decode_value(decoder: &mut Decoder, context: Context) -> Result<Box<[T]>, ValidationError> {
666 match Vec::<T>::decode_value(decoder, context) {
667 Ok(vec) => Ok(vec.into_boxed_slice()),
668 Err(err) => Err(err),
669 }
670 }
671 }
672
673 impl<T: MojomEncodable> MojomEncodable for Box<[T]> {
674 impl_encodable_for_array!();
675 }
676
677 // We can represent a Mojom string as just a Rust String type
678 // since both are UTF-8.
679 impl MojomPointer for String {
680 fn header_data(&self) -> DataHeaderValue {
681 DataHeaderValue::Elements(self.len() as u32)
682 }
683 fn serialized_size(&self, _context: &Context) -> usize {
684 DATA_HEADER_SIZE + self.len()
685 }
686 fn encode_value(self, encoder: &mut Encoder, context: Context) {
687 for byte in self.as_bytes() {
688 byte.encode(encoder, context.clone());
689 }
690 }
691 fn decode_value(decoder: &mut Decoder, context: Context) -> Result<String, V alidationError> {
692 let mut state = decoder.get_mut(&context);
693 let elems = match state.decode_array_header::<u8>() {
694 Ok(header) => header.data(),
695 Err(err) => return Err(err),
696 };
697 let mut value = Vec::with_capacity(elems as usize);
698 for _ in 0..elems {
699 value.push(state.decode::<u8>());
700 }
701 match String::from_utf8(value) {
702 Ok(string) => Ok(string),
703 Err(err) => panic!("Error decoding String: {}", err),
704 }
705 }
706 }
707
708 impl MojomEncodable for String {
709 impl_encodable_for_pointer!();
710 fn compute_size(&self, context: Context) -> usize {
711 encoding::align_default(self.serialized_size(&context))
712 }
713 }
714
715 /// Helper function to clean up duplicate code in HashMap.
716 fn array_claim_and_decode_header<T: MojomEncodable>(decoder: &mut Decoder, offse t: usize) -> Result<(Context, usize), ValidationError> {
717 let context = match decoder.claim(offset) {
718 Ok(new_context) => new_context,
719 Err(err) => return Err(err),
720 };
721 let elems = {
722 let state = decoder.get_mut(&context);
723 match state.decode_array_header::<T>() {
724 Ok(header) => header.data(),
725 Err(err) => return Err(err),
726 }
727 };
728 Ok((context, elems as usize))
729 }
730
731 impl<K: MojomEncodable + Eq + Hash, V: MojomEncodable> MojomPointer for HashMap< K, V> {
732 fn header_data(&self) -> DataHeaderValue {
733 DataHeaderValue::Version(0)
734 }
735 fn serialized_size(&self, _context: &Context) -> usize {
736 MAP_SIZE
737 }
738 fn encode_value(self, encoder: &mut Encoder, context: Context) {
739 let elems = self.len();
740 let meta_value = DataHeaderValue::Elements(elems as u32);
741 // We need to move values into this vector because we can't copy the key s.
742 // (Handles are not copyable so MojomEncodable cannot be copyable!)
743 let mut vals_vec = Vec::with_capacity(elems);
744 // Key setup
745 // Write a pointer to the keys array.
746 let keys_loc = encoder.size() as u64;
747 {
748 let state = encoder.get_mut(&context);
749 state.encode_pointer(keys_loc);
750 }
751 // Create the keys data header
752 let keys_bytes = DATA_HEADER_SIZE + (K::embed_size(&context) * elems).as _bytes();
753 let keys_data_header = DataHeader::new(keys_bytes, meta_value);
754 // Claim space for the keys array in the encoder
755 let keys_context = encoder.add(&keys_data_header).unwrap();
756 // Encode keys, setup vals
757 for (key, value) in self.into_iter() {
758 key.encode(encoder, keys_context.clone());
759 vals_vec.push(value);
760 }
761 // Encode vals
762 vals_vec.encode(encoder, context.clone())
763 }
764 fn decode_value(decoder: &mut Decoder, context: Context) -> Result<HashMap<K , V>, ValidationError> {
765 let (keys_offset, vals_offset) = {
766 let state = decoder.get_mut(&context);
767 match state.decode_struct_header(&MAP_VERSIONS) {
768 Ok(_) => (),
769 Err(err) => return Err(err),
770 };
771 // Decode the keys pointer and check for overflow
772 let keys_offset = match state.decode_pointer() {
773 Some(ptr) => ptr,
774 None => return Err(ValidationError::IllegalPointer),
775 };
776 // Decode the keys pointer and check for overflow
777 let vals_offset = match state.decode_pointer() {
778 Some(ptr) => ptr,
779 None => return Err(ValidationError::IllegalPointer),
780 };
781 if keys_offset == MOJOM_NULL_POINTER || vals_offset == MOJOM_NULL_PO INTER {
782 return Err(ValidationError::UnexpectedNullPointer);
783 }
784 (keys_offset as usize, vals_offset as usize)
785 };
786 let (keys_context, keys_elems) = match array_claim_and_decode_header::<K >(decoder, keys_offset) {
787 Ok((context, elems)) => (context, elems),
788 Err(err) => return Err(err),
789 };
790 let mut keys_vec: Vec<K> = Vec::with_capacity(keys_elems as usize);
791 for _ in 0..keys_elems {
792 let key = match K::decode(decoder, keys_context.clone()) {
793 Ok(value) => value,
794 Err(err) => return Err(err),
795 };
796 keys_vec.push(key);
797 }
798 let (vals_context, vals_elems) = match array_claim_and_decode_header::<V >(decoder, vals_offset) {
799 Ok((context, elems)) => (context, elems),
800 Err(err) => return Err(err),
801 };
802 if keys_elems != vals_elems {
803 return Err(ValidationError::DifferentSizedArraysInMap);
804 }
805 let mut map = HashMap::with_capacity(keys_elems as usize);
806 for key in keys_vec.into_iter() {
807 let val = match V::decode(decoder, vals_context.clone()) {
808 Ok(value) => value,
809 Err(err) => return Err(err),
810 };
811 map.insert(key, val);
812 }
813 Ok(map)
814 }
815 }
816
817 impl<K: MojomEncodable + Eq + Hash, V: MojomEncodable> MojomEncodable for HashMa p<K, V> {
818 impl_encodable_for_pointer!();
819 fn compute_size(&self, context: Context) -> usize {
820 let mut size = encoding::align_default(self.serialized_size(&context));
821 // The size of the one array
822 size += DATA_HEADER_SIZE;
823 size += (K::embed_size(&context) * self.len()).as_bytes();
824 size = encoding::align_default(size);
825 // Any extra space used by the keys
826 for (key, _) in self {
827 size += key.compute_size(context.clone());
828 }
829 // Need to re-align after this for the next array
830 size = encoding::align_default(size);
831 // The size of the one array
832 size += DATA_HEADER_SIZE;
833 size += (V::embed_size(&context) * self.len()).as_bytes();
834 size = encoding::align_default(size);
835 // Any extra space used by the values
836 for (_, value) in self {
837 size += value.compute_size(context.clone());
838 }
839 // Align one more time at the end to keep the next object aligned.
840 encoding::align_default(size)
841 }
842 }
843
844 impl<T: MojomEncodable + CastHandle + Handle> MojomHandle for T {}
845
846 macro_rules! impl_encodable_for_handle {
847 ($handle_type:path) => {
848 fn mojom_alignment() -> usize {
849 4
850 }
851 fn mojom_type() -> MojomType {
852 MojomType::Handle
853 }
854 fn embed_size(_context: &Context) -> Bits {
855 Bits(8 * mem::size_of::<u32>())
856 }
857 fn compute_size(&self, _context: Context) -> usize {
858 0
859 }
860 fn encode(self, encoder: &mut Encoder, context: Context) {
861 let pos = encoder.add_handle(self.as_untyped());
862 let mut state = encoder.get_mut(&context);
863 state.encode(pos as i32);
864 }
865 fn decode(decoder: &mut Decoder, context: Context) -> Result<$handle_typ e, ValidationError> {
866 let handle_index = {
867 let mut state = decoder.get_mut(&context);
868 state.decode::<i32>()
869 };
870 decoder.claim_handle::<$handle_type>(handle_index)
871 }
872 }
873 }
874
875 impl MojomEncodable for UntypedHandle {
876 impl_encodable_for_handle!(UntypedHandle);
877 }
878
879 impl MojomEncodable for message_pipe::MessageEndpoint {
880 impl_encodable_for_handle!(message_pipe::MessageEndpoint);
881 }
882
883 impl MojomEncodable for shared_buffer::SharedBuffer {
884 impl_encodable_for_handle!(shared_buffer::SharedBuffer);
885 }
886
887 impl<T> MojomEncodable for data_pipe::Consumer<T> {
888 impl_encodable_for_handle!(data_pipe::Consumer<T>);
889 }
890
891 impl<T> MojomEncodable for data_pipe::Producer<T> {
892 impl_encodable_for_handle!(data_pipe::Producer<T>);
893 }
894
895 impl MojomEncodable for wait_set::WaitSet {
896 impl_encodable_for_handle!(wait_set::WaitSet);
897 }
OLDNEW
« no previous file with comments | « mojo/public/rust/src/bindings/mod.rs ('k') | mojo/public/rust/src/bindings/run_loop.rs » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698