OLD | NEW |
| (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 } | |
OLD | NEW |