| Index: mojo/public/rust/src/bindings/mojom.rs
|
| diff --git a/mojo/public/rust/src/bindings/mojom.rs b/mojo/public/rust/src/bindings/mojom.rs
|
| deleted file mode 100644
|
| index 8401bb7ddbe3b94fa39acf702b9da000a08369e3..0000000000000000000000000000000000000000
|
| --- a/mojo/public/rust/src/bindings/mojom.rs
|
| +++ /dev/null
|
| @@ -1,897 +0,0 @@
|
| -// Copyright 2016 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -use bindings::decoding::{Decoder, ValidationError};
|
| -use bindings::encoding;
|
| -use bindings::encoding::{Bits, Encoder, Context, DATA_HEADER_SIZE, DataHeader, DataHeaderValue};
|
| -use bindings::message::MessageHeader;
|
| -
|
| -use std::cmp::Eq;
|
| -use std::collections::HashMap;
|
| -use std::hash::Hash;
|
| -use std::mem;
|
| -use std::panic;
|
| -use std::ptr;
|
| -use std::vec::Vec;
|
| -
|
| -use system::{MojoResult, CastHandle, Handle, UntypedHandle};
|
| -use system::data_pipe;
|
| -use system::message_pipe;
|
| -use system::shared_buffer;
|
| -use system::wait_set;
|
| -
|
| -/// The size of a Mojom map plus header in bytes.
|
| -const MAP_SIZE: usize = 24;
|
| -
|
| -/// The sorted set of versions for a map.
|
| -const MAP_VERSIONS: [(u32, u32); 1] = [(0, MAP_SIZE as u32)];
|
| -
|
| -/// The size of a Mojom union in bytes (header included).
|
| -pub const UNION_SIZE: usize = 16;
|
| -
|
| -/// The size of a Mojom pointer in bits.
|
| -pub const POINTER_BIT_SIZE: Bits = Bits(64);
|
| -
|
| -/// The value of a Mojom null pointer.
|
| -pub const MOJOM_NULL_POINTER: u64 = 0;
|
| -
|
| -/// An enumeration of all the possible low-level Mojom types.
|
| -pub enum MojomType {
|
| - Simple,
|
| - Pointer,
|
| - Union,
|
| - Handle,
|
| - Interface,
|
| -}
|
| -
|
| -/// Whatever implements this trait can be serialized in the Mojom format.
|
| -pub trait MojomEncodable: Sized {
|
| - /// Get the Mojom type.
|
| - fn mojom_type() -> MojomType;
|
| -
|
| - /// Get this type's Mojom alignment.
|
| - fn mojom_alignment() -> usize;
|
| -
|
| - /// The amount of space in bits the type takes up when inlined
|
| - /// into another type at serialization time.
|
| - fn embed_size(context: &Context) -> Bits;
|
| -
|
| - /// Recursively computes the size of the complete Mojom archive
|
| - /// starting from this type.
|
| - fn compute_size(&self, context: Context) -> usize;
|
| -
|
| - /// Encodes this type into the encoder given a context.
|
| - fn encode(self, encoder: &mut Encoder, context: Context);
|
| -
|
| - /// Using a decoder, decodes itself out of a byte buffer.
|
| - fn decode(decoder: &mut Decoder, context: Context) -> Result<Self, ValidationError>;
|
| -}
|
| -
|
| -/// Whatever implements this trait is a Mojom pointer type which means
|
| -/// that on encode, a pointer is inlined and the implementer is
|
| -/// serialized elsewhere in the output buffer.
|
| -pub trait MojomPointer: MojomEncodable {
|
| - /// Get the DataHeader meta-data for this pointer type.
|
| - fn header_data(&self) -> DataHeaderValue;
|
| -
|
| - /// Get the size of only this type when serialized.
|
| - fn serialized_size(&self, context: &Context) -> usize;
|
| -
|
| - /// Encodes the actual values of the type into the encoder.
|
| - fn encode_value(self, encoder: &mut Encoder, context: Context);
|
| -
|
| - /// Decodes the actual values of the type into the decoder.
|
| - fn decode_value(decoder: &mut Decoder, context: Context) -> Result<Self, ValidationError>;
|
| -
|
| - /// Writes a pointer inlined into the current context before calling
|
| - /// encode_value.
|
| - fn encode_new(self, encoder: &mut Encoder, context: Context) {
|
| - let data_size = self.serialized_size(&context);
|
| - let data_header = DataHeader::new(data_size, self.header_data());
|
| - let new_context = encoder.add(&data_header).unwrap();
|
| - self.encode_value(encoder, new_context);
|
| - }
|
| -
|
| - /// Reads a pointer inlined into the current context before calling
|
| - /// decode_value.
|
| - fn decode_new(decoder: &mut Decoder, _context: Context, pointer: u64) -> Result<Self, ValidationError> {
|
| - match decoder.claim(pointer as usize) {
|
| - Ok(new_context) => Self::decode_value(decoder, new_context),
|
| - Err(err) => Err(err),
|
| - }
|
| - }
|
| -}
|
| -
|
| -/// Whatever implements this trait is a Mojom union type which means that
|
| -/// on encode it is inlined, but if the union is nested inside of another
|
| -/// union type, it is treated as a pointer type.
|
| -pub trait MojomUnion: MojomEncodable {
|
| - /// Get the union's current tag.
|
| - fn get_tag(&self) -> u32;
|
| -
|
| - /// Encode the actual value of the union.
|
| - fn encode_value(self, encoder: &mut Encoder, context: Context);
|
| -
|
| - /// Decode the actual value of the union.
|
| - fn decode_value(decoder: &mut Decoder, context: Context) -> Result<Self, ValidationError>;
|
| -
|
| - /// The embed_size for when the union acts as a pointer type.
|
| - fn nested_embed_size() -> Bits {
|
| - POINTER_BIT_SIZE
|
| - }
|
| -
|
| - /// The encoding routine for when the union acts as a pointer type.
|
| - fn nested_encode(self, encoder: &mut Encoder, context: Context) {
|
| - let loc = encoder.size() as u64;
|
| - {
|
| - let state = encoder.get_mut(&context);
|
| - state.encode_pointer(loc);
|
| - }
|
| - let tag = DataHeaderValue::UnionTag(self.get_tag());
|
| - let data_header = DataHeader::new(UNION_SIZE, tag);
|
| - let new_context = encoder.add(&data_header).unwrap();
|
| - self.encode_value(encoder, new_context.set_is_union(true));
|
| - }
|
| -
|
| - /// The decoding routine for when the union acts as a pointer type.
|
| - fn nested_decode(decoder: &mut Decoder, context: Context) -> Result<Self, ValidationError> {
|
| - let global_offset = {
|
| - let state = decoder.get_mut(&context);
|
| - match state.decode_pointer() {
|
| - Some(ptr) => ptr as usize,
|
| - None => return Err(ValidationError::IllegalPointer),
|
| - }
|
| - };
|
| - if global_offset == (MOJOM_NULL_POINTER as usize) {
|
| - return Err(ValidationError::UnexpectedNullPointer);
|
| - }
|
| - match decoder.claim(global_offset as usize) {
|
| - Ok(new_context) => Self::decode_value(decoder, new_context),
|
| - Err(err) => Err(err),
|
| - }
|
| - }
|
| -
|
| - /// The embed_size for when the union is inlined into the current context.
|
| - fn inline_embed_size() -> Bits {
|
| - Bits(8 * (UNION_SIZE as usize))
|
| - }
|
| -
|
| - /// The encoding routine for when the union is inlined into the current context.
|
| - fn inline_encode(self, encoder: &mut Encoder, context: Context) {
|
| - {
|
| - let mut state = encoder.get_mut(&context);
|
| - state.align_to_bytes(8);
|
| - state.encode(UNION_SIZE as u32);
|
| - state.encode(self.get_tag());
|
| - }
|
| - self.encode_value(encoder, context.clone());
|
| - {
|
| - let mut state = encoder.get_mut(&context);
|
| - state.align_to_bytes(8);
|
| - state.align_to_byte();
|
| - }
|
| - }
|
| -
|
| - /// The decoding routine for when the union is inlined into the current context.
|
| - fn inline_decode(decoder: &mut Decoder, context: Context) -> Result<Self, ValidationError> {
|
| - {
|
| - let mut state = decoder.get_mut(&context);
|
| - state.align_to_byte();
|
| - state.align_to_bytes(8);
|
| - }
|
| - let value = Self::decode_value(decoder, context.clone());
|
| - {
|
| - let mut state = decoder.get_mut(&context);
|
| - state.align_to_byte();
|
| - state.align_to_bytes(8);
|
| - }
|
| - value
|
| - }
|
| -}
|
| -
|
| -/// A marker trait that marks Mojo handles as encodable.
|
| -pub trait MojomHandle: CastHandle + MojomEncodable {}
|
| -
|
| -/// Whatever implements this trait is considered to be a Mojom
|
| -/// interface, that is, a message pipe which conforms to some
|
| -/// messaging interface.
|
| -///
|
| -/// We force an underlying message pipe to be used via the pipe()
|
| -/// and unwrap() routines.
|
| -pub trait MojomInterface: MojomEncodable {
|
| - /// Get the service name for this interface.
|
| - fn service_name() -> &'static str;
|
| -
|
| - /// Get the version for this interface.
|
| - fn version(&self) -> u32;
|
| -
|
| - /// Access the underlying message pipe for this interface.
|
| - fn pipe(&self) -> &message_pipe::MessageEndpoint;
|
| -
|
| - /// Unwrap the interface into its underlying message pipe.
|
| - fn unwrap(self) -> message_pipe::MessageEndpoint;
|
| -}
|
| -
|
| -/// An error that may occur when sending data over a Mojom interface.
|
| -#[derive(Debug)]
|
| -pub enum MojomSendError {
|
| - /// Failed to write to the underlying message pipe.
|
| - FailedWrite(MojoResult),
|
| -
|
| - /// The version is too old to write the attempted message.
|
| - OldVersion(u32, u32),
|
| -}
|
| -
|
| -/// Whatever implements this trait is considered to be a Mojom
|
| -/// interface that may send messages of some generic type.
|
| -///
|
| -/// When implementing this trait, the correct way is to specify
|
| -/// a tighter trait bound than MojomMessage that limits the types
|
| -/// available for sending to those that are valid messages available
|
| -/// to the interface.
|
| -///
|
| -/// TODO(mknyszek): Add sending control messages
|
| -pub trait MojomInterfaceSend<R: MojomMessage>: MojomInterface {
|
| - /// Creates a message.
|
| - fn create_request(&self, req_id: u64, payload: R) -> (Vec<u8>, Vec<UntypedHandle>) {
|
| - let mut header = R::create_header();
|
| - header.request_id = req_id;
|
| - let header_size = header.compute_size(Default::default());
|
| - let size = header_size + payload.compute_size(Default::default());
|
| - let mut buffer: Vec<u8> = Vec::with_capacity(size);
|
| - buffer.resize(size, 0);
|
| - let handles = {
|
| - let (header_buf, rest_buf) = buffer.split_at_mut(header_size);
|
| - let mut handles = header.serialize(header_buf);
|
| - handles.extend(payload.serialize(rest_buf).into_iter());
|
| - handles
|
| - };
|
| - (buffer, handles)
|
| - }
|
| -
|
| - /// Creates and sends a message, and returns its request ID.
|
| - fn send_request(&self, req_id: u64, payload: R) -> Result<(), MojomSendError> {
|
| - if self.version() < R::min_version() {
|
| - return Err(MojomSendError::OldVersion(self.version(), R::min_version()));
|
| - }
|
| - let (buffer, handles) = self.create_request(req_id, payload);
|
| - match self.pipe().write(&buffer, handles, mpflags!(Write::None)) {
|
| - MojoResult::Okay => Ok(()),
|
| - err => Err(MojomSendError::FailedWrite(err)),
|
| - }
|
| - }
|
| -}
|
| -
|
| -/// An error that may occur when attempting to recieve a message over a
|
| -/// Mojom interface.
|
| -#[derive(Debug)]
|
| -pub enum MojomRecvError {
|
| - /// Failed to read from the underlying message pipe.
|
| - FailedRead(MojoResult),
|
| -
|
| - /// Failed to validate the buffer during decode.
|
| - FailedValidation(ValidationError),
|
| -}
|
| -
|
| -/// Whatever implements this trait is considered to be a Mojom
|
| -/// interface that may recieve messages for some interface.
|
| -///
|
| -/// When implementing this trait, specify the container "union" type
|
| -/// which can contain any of the potential messages that may be recieved.
|
| -/// This way, we can return that type and let the user multiplex over
|
| -/// what message was received.
|
| -///
|
| -/// TODO(mknyszek): Add responding to control messages
|
| -pub trait MojomInterfaceRecv: MojomInterface {
|
| - type Container: MojomMessageOption;
|
| -
|
| - /// Tries to read a message from a pipe and decodes it.
|
| - fn recv_response(&self) -> Result<(u64, Self::Container), MojomRecvError> {
|
| - match self.pipe().read(mpflags!(Read::None)) {
|
| - Ok((buffer, handles)) => {
|
| - match Self::Container::decode_message(buffer, handles) {
|
| - Ok((req_id, val)) => Ok((req_id, val)),
|
| - Err(err) => Err(MojomRecvError::FailedValidation(err)),
|
| - }
|
| - },
|
| - Err(err) => Err(MojomRecvError::FailedRead(err)),
|
| - }
|
| - }
|
| -}
|
| -
|
| -/// Whatever implements this trait is considered to be a Mojom struct.
|
| -///
|
| -/// Mojom structs are always the root of any Mojom message. Thus, we
|
| -/// provide convenience functions for serialization here.
|
| -pub trait MojomStruct: MojomPointer {
|
| - /// Given a pre-allocated buffer, the struct serializes itself.
|
| - fn serialize(self, buffer: &mut [u8]) -> Vec<UntypedHandle> {
|
| - let mut encoder = Encoder::new(buffer);
|
| - self.encode_new(&mut encoder, Default::default());
|
| - encoder.unwrap()
|
| - }
|
| -
|
| - /// The struct computes its own size, allocates a buffer, and then
|
| - /// serializes itself into that buffer.
|
| - fn auto_serialize(self) -> (Vec<u8>, Vec<UntypedHandle>) {
|
| - let size = self.compute_size(Default::default());
|
| - let mut buf = Vec::with_capacity(size);
|
| - buf.resize(size, 0);
|
| - let handles = self.serialize(&mut buf);
|
| - (buf, handles)
|
| - }
|
| -
|
| - /// Decode the type from a byte array and a set of handles.
|
| - fn deserialize(buffer: &[u8], handles: Vec<UntypedHandle>) -> Result<Self, ValidationError> {
|
| - let mut decoder = Decoder::new(buffer, handles);
|
| - Self::decode_new(&mut decoder, Default::default(), 0)
|
| - }
|
| -}
|
| -
|
| -/// Marks a MojomStruct as being capable of being sent across some
|
| -/// Mojom interface.
|
| -pub trait MojomMessage: MojomStruct {
|
| - fn min_version() -> u32;
|
| - fn create_header() -> MessageHeader;
|
| -}
|
| -
|
| -/// The trait for a "container" type intended to be used in MojomInterfaceRecv.
|
| -///
|
| -/// This trait contains the decode logic which decodes based on the message header
|
| -/// and returns itself: a union type which may contain any of the possible messages
|
| -/// that may be sent across this interface.
|
| -pub trait MojomMessageOption: Sized {
|
| - /// Decodes the actual payload of the message.
|
| - ///
|
| - /// Implemented by a code generator.
|
| - fn decode_payload(header: MessageHeader, buffer: &[u8], handles: Vec<UntypedHandle>) -> Result<Self, ValidationError>;
|
| -
|
| - /// Decodes the message header and then the payload, returning a new
|
| - /// copy of itself and the request ID found in the header.
|
| - fn decode_message(buffer: Vec<u8>, handles: Vec<UntypedHandle>) -> Result<(u64, Self), ValidationError> {
|
| - let header = try!(MessageHeader::deserialize(&buffer[..], Vec::new()));
|
| - let payload_buffer = &buffer[header.serialized_size(&Default::default())..];
|
| - let req_id = header.request_id;
|
| - let ret = try!(Self::decode_payload(header, payload_buffer, handles));
|
| - Ok((req_id, ret))
|
| - }
|
| -}
|
| -
|
| -// ********************************************** //
|
| -// ****** IMPLEMENTATIONS FOR COMMON TYPES ****** //
|
| -// ********************************************** //
|
| -
|
| -macro_rules! impl_encodable_for_prim {
|
| - ($($prim_type:ty),*) => {
|
| - $(
|
| - impl MojomEncodable for $prim_type {
|
| - fn mojom_type() -> MojomType {
|
| - MojomType::Simple
|
| - }
|
| - fn mojom_alignment() -> usize {
|
| - mem::size_of::<$prim_type>()
|
| - }
|
| - fn embed_size(_context: &Context) -> Bits {
|
| - Bits(8 * mem::size_of::<$prim_type>())
|
| - }
|
| - fn compute_size(&self, _context: Context) -> usize {
|
| - 0 // Indicates that this type is inlined and it adds nothing external to the size
|
| - }
|
| - fn encode(self, encoder: &mut Encoder, context: Context) {
|
| - let mut state = encoder.get_mut(&context);
|
| - state.encode(self);
|
| - }
|
| - fn decode(decoder: &mut Decoder, context: Context) -> Result<Self, ValidationError> {
|
| - let mut state = decoder.get_mut(&context);
|
| - Ok(state.decode::<Self>())
|
| - }
|
| - }
|
| - )*
|
| - }
|
| -}
|
| -
|
| -impl_encodable_for_prim!(i8, i16, i32, i64, u8, u16, u32, u64, f32, f64);
|
| -
|
| -impl MojomEncodable for bool {
|
| - fn mojom_alignment() -> usize {
|
| - panic!("Should never check_decode mojom_alignment of bools (they're bit-aligned)!");
|
| - }
|
| - fn mojom_type() -> MojomType {
|
| - MojomType::Simple
|
| - }
|
| - fn embed_size(_context: &Context) -> Bits {
|
| - Bits(1)
|
| - }
|
| - fn compute_size(&self, _context: Context) -> usize {
|
| - 0 // Indicates that this type is inlined and it adds nothing external to the size
|
| - }
|
| - fn encode(self, encoder: &mut Encoder, context: Context) {
|
| - let mut state = encoder.get_mut(&context);
|
| - state.encode_bool(self);
|
| - }
|
| - fn decode(decoder: &mut Decoder, context: Context) -> Result<Self, ValidationError> {
|
| - let mut state = decoder.get_mut(&context);
|
| - Ok(state.decode_bool())
|
| - }
|
| -}
|
| -
|
| -// Options should be considered to represent nullability the Mojom IDL.
|
| -// Any type wrapped in an Option type is nullable.
|
| -
|
| -impl<T: MojomEncodable> MojomEncodable for Option<T> {
|
| - fn mojom_alignment() -> usize {
|
| - T::mojom_alignment()
|
| - }
|
| - fn mojom_type() -> MojomType {
|
| - T::mojom_type()
|
| - }
|
| - fn embed_size(context: &Context) -> Bits {
|
| - T::embed_size(context)
|
| - }
|
| - fn compute_size(&self, context: Context) -> usize {
|
| - match *self {
|
| - Some(ref value) => value.compute_size(context),
|
| - None => 0,
|
| - }
|
| - }
|
| - fn encode(self, encoder: &mut Encoder, context: Context) {
|
| - match self {
|
| - Some(value) => value.encode(encoder, context),
|
| - None => {
|
| - let mut state = encoder.get_mut(&context);
|
| - match T::mojom_type() {
|
| - MojomType::Pointer => state.encode_null_pointer(),
|
| - MojomType::Union => state.encode_null_union(),
|
| - MojomType::Handle => state.encode_null_handle(),
|
| - MojomType::Interface => {
|
| - state.encode_null_handle();
|
| - state.encode(0 as u32);
|
| - },
|
| - MojomType::Simple => panic!("Unexpected simple type in Option!"),
|
| - }
|
| - },
|
| - }
|
| - }
|
| - fn decode(decoder: &mut Decoder, context: Context) -> Result<Self, ValidationError> {
|
| - let skipped = {
|
| - let mut state = decoder.get_mut(&context);
|
| - match T::mojom_type() {
|
| - MojomType::Pointer => state.skip_if_null_pointer(),
|
| - MojomType::Union => state.skip_if_null_union(),
|
| - MojomType::Handle => state.skip_if_null_handle(),
|
| - MojomType::Interface => state.skip_if_null_interface(),
|
| - MojomType::Simple => panic!("Unexpected simple type in Option!"),
|
| - }
|
| - };
|
| - if skipped {
|
| - Ok(None)
|
| - } else {
|
| - match T::decode(decoder, context) {
|
| - Ok(value) => Ok(Some(value)),
|
| - Err(err) => Err(err),
|
| - }
|
| - }
|
| - }
|
| -}
|
| -
|
| -macro_rules! impl_pointer_for_array {
|
| - () => {
|
| - fn header_data(&self) -> DataHeaderValue {
|
| - DataHeaderValue::Elements(self.len() as u32)
|
| - }
|
| - fn serialized_size(&self, context: &Context) -> usize {
|
| - DATA_HEADER_SIZE + if self.len() > 0 {
|
| - (T::embed_size(context) * self.len()).as_bytes()
|
| - } else {
|
| - 0
|
| - }
|
| - }
|
| - }
|
| -}
|
| -
|
| -macro_rules! impl_encodable_for_array {
|
| - () => {
|
| - impl_encodable_for_pointer!();
|
| - fn compute_size(&self, context: Context) -> usize {
|
| - let mut size = encoding::align_default(self.serialized_size(&context));
|
| - for elem in self.iter() {
|
| - size += elem.compute_size(context.clone());
|
| - }
|
| - size
|
| - }
|
| - }
|
| -}
|
| -
|
| -impl<T: MojomEncodable> MojomPointer for Vec<T> {
|
| - impl_pointer_for_array!();
|
| - fn encode_value(self, encoder: &mut Encoder, context: Context) {
|
| - for elem in self.into_iter() {
|
| - elem.encode(encoder, context.clone());
|
| - }
|
| - }
|
| - fn decode_value(decoder: &mut Decoder, context: Context) -> Result<Vec<T>, ValidationError> {
|
| - let elems = {
|
| - let mut state = decoder.get_mut(&context);
|
| - match state.decode_array_header::<T>() {
|
| - Ok(header) => header.data(),
|
| - Err(err) => return Err(err),
|
| - }
|
| - };
|
| - let mut value = Vec::with_capacity(elems as usize);
|
| - for _ in 0..elems {
|
| - match T::decode(decoder, context.clone()) {
|
| - Ok(elem) => value.push(elem),
|
| - Err(err) => return Err(err),
|
| - }
|
| - }
|
| - Ok(value)
|
| - }
|
| -}
|
| -
|
| -impl<T: MojomEncodable> MojomEncodable for Vec<T> {
|
| - impl_encodable_for_array!();
|
| -}
|
| -
|
| -macro_rules! impl_encodable_for_fixed_array {
|
| - ($($len:expr),*) => {
|
| - $(
|
| - impl<T: MojomEncodable> MojomPointer for [T; $len] {
|
| - impl_pointer_for_array!();
|
| - fn encode_value(mut self, encoder: &mut Encoder, context: Context) {
|
| - let mut panic_error = None;
|
| - let mut moves = 0;
|
| - unsafe {
|
| - // In order to move elements out of an array we need to replace the
|
| - // value with uninitialized memory.
|
| - for elem in self.iter_mut() {
|
| - let owned_elem = mem::replace(elem, mem::uninitialized());
|
| - // We need to handle if an unwinding panic happens to prevent use of
|
| - // uninitialized memory...
|
| - let next_context = context.clone();
|
| - // We assert everything going into this closure is unwind safe. If anything
|
| - // is added, PLEASE make sure it is also unwind safe...
|
| - let result = panic::catch_unwind(panic::AssertUnwindSafe(|| {
|
| - owned_elem.encode(encoder, next_context);
|
| - }));
|
| - if let Err(err) = result {
|
| - panic_error = Some(err);
|
| - break;
|
| - }
|
| - moves += 1;
|
| - }
|
| - if let Some(err) = panic_error {
|
| - for i in moves..self.len() {
|
| - ptr::drop_in_place(&mut self[i] as *mut T);
|
| - }
|
| - // Forget the array to prevent a drop
|
| - mem::forget(self);
|
| - // Continue unwinding
|
| - panic::resume_unwind(err);
|
| - }
|
| - // We cannot risk drop() getting run on the array values, so we just
|
| - // forget self.
|
| - mem::forget(self);
|
| - }
|
| - }
|
| - fn decode_value(decoder: &mut Decoder, context: Context) -> Result<[T; $len], ValidationError> {
|
| - let elems = {
|
| - let mut state = decoder.get_mut(&context);
|
| - match state.decode_array_header::<T>() {
|
| - Ok(header) => header.data(),
|
| - Err(err) => return Err(err),
|
| - }
|
| - };
|
| - if elems != $len {
|
| - return Err(ValidationError::UnexpectedArrayHeader);
|
| - }
|
| - let mut array: [T; $len];
|
| - let mut panic_error = None;
|
| - let mut inits = 0;
|
| - let mut error = None;
|
| - unsafe {
|
| - // Since we don't force Clone to be implemented on Mojom types
|
| - // (mainly due to handles) we need to create this array as uninitialized
|
| - // and initialize it manually.
|
| - array = mem::uninitialized();
|
| - for elem in &mut array[..] {
|
| - // When a panic unwinds it may try to read and drop uninitialized
|
| - // memory, so we need to catch this. However, we pass mutable state!
|
| - // This could be bad as we could observe a broken invariant inside
|
| - // of decoder and access it as usual, but we do NOT access decoder
|
| - // here, nor do we ever unwind through one of decoder's methods.
|
| - // Therefore, it should be safe to assert that decoder is unwind safe.
|
| - let next_context = context.clone();
|
| - // We assert everything going into this closure is unwind safe. If anything
|
| - // is added, PLEASE make sure it is also unwind safe...
|
| - let result = panic::catch_unwind(panic::AssertUnwindSafe(|| {
|
| - T::decode(decoder, next_context)
|
| - }));
|
| - match result {
|
| - Ok(non_panic_value) => match non_panic_value {
|
| - Ok(value) => ptr::write(elem, value),
|
| - Err(err) => {
|
| - error = Some(err);
|
| - break;
|
| - },
|
| - },
|
| - Err(err) => {
|
| - panic_error = Some(err);
|
| - break;
|
| - },
|
| - }
|
| - inits += 1;
|
| - }
|
| - if panic_error.is_some() || error.is_some() {
|
| - // Drop everything that was initialized
|
| - for i in 0..inits {
|
| - ptr::drop_in_place(&mut array[i] as *mut T);
|
| - }
|
| - // Forget the array to prevent a drop
|
| - mem::forget(array);
|
| - if let Some(err) = panic_error {
|
| - panic::resume_unwind(err);
|
| - }
|
| - return Err(error.take().expect("Corrupted stack?"));
|
| - }
|
| - }
|
| - Ok(array)
|
| - }
|
| - }
|
| - impl<T: MojomEncodable> MojomEncodable for [T; $len] {
|
| - impl_encodable_for_array!();
|
| - }
|
| - )*
|
| - }
|
| -}
|
| -
|
| -// Unfortunately, we cannot be generic over the length of a fixed array
|
| -// even though its part of the type (this will hopefully be added in the
|
| -// future) so for now we implement encodable for only the first 33 fixed
|
| -// size array types.
|
| -impl_encodable_for_fixed_array!( 0, 1, 2, 3, 4, 5, 6, 7,
|
| - 8, 9, 10, 11, 12, 13, 14, 15,
|
| - 16, 17, 18, 19, 20, 21, 22, 23,
|
| - 24, 25, 26, 27, 28, 29, 30, 31,
|
| - 32);
|
| -
|
| -impl<T: MojomEncodable> MojomPointer for Box<[T]> {
|
| - impl_pointer_for_array!();
|
| - fn encode_value(self, encoder: &mut Encoder, context: Context) {
|
| - for elem in self.into_vec().into_iter() {
|
| - elem.encode(encoder, context.clone());
|
| - }
|
| - }
|
| - fn decode_value(decoder: &mut Decoder, context: Context) -> Result<Box<[T]>, ValidationError> {
|
| - match Vec::<T>::decode_value(decoder, context) {
|
| - Ok(vec) => Ok(vec.into_boxed_slice()),
|
| - Err(err) => Err(err),
|
| - }
|
| - }
|
| -}
|
| -
|
| -impl<T: MojomEncodable> MojomEncodable for Box<[T]> {
|
| - impl_encodable_for_array!();
|
| -}
|
| -
|
| -// We can represent a Mojom string as just a Rust String type
|
| -// since both are UTF-8.
|
| -impl MojomPointer for String {
|
| - fn header_data(&self) -> DataHeaderValue {
|
| - DataHeaderValue::Elements(self.len() as u32)
|
| - }
|
| - fn serialized_size(&self, _context: &Context) -> usize {
|
| - DATA_HEADER_SIZE + self.len()
|
| - }
|
| - fn encode_value(self, encoder: &mut Encoder, context: Context) {
|
| - for byte in self.as_bytes() {
|
| - byte.encode(encoder, context.clone());
|
| - }
|
| - }
|
| - fn decode_value(decoder: &mut Decoder, context: Context) -> Result<String, ValidationError> {
|
| - let mut state = decoder.get_mut(&context);
|
| - let elems = match state.decode_array_header::<u8>() {
|
| - Ok(header) => header.data(),
|
| - Err(err) => return Err(err),
|
| - };
|
| - let mut value = Vec::with_capacity(elems as usize);
|
| - for _ in 0..elems {
|
| - value.push(state.decode::<u8>());
|
| - }
|
| - match String::from_utf8(value) {
|
| - Ok(string) => Ok(string),
|
| - Err(err) => panic!("Error decoding String: {}", err),
|
| - }
|
| - }
|
| -}
|
| -
|
| -impl MojomEncodable for String {
|
| - impl_encodable_for_pointer!();
|
| - fn compute_size(&self, context: Context) -> usize {
|
| - encoding::align_default(self.serialized_size(&context))
|
| - }
|
| -}
|
| -
|
| -/// Helper function to clean up duplicate code in HashMap.
|
| -fn array_claim_and_decode_header<T: MojomEncodable>(decoder: &mut Decoder, offset: usize) -> Result<(Context, usize), ValidationError> {
|
| - let context = match decoder.claim(offset) {
|
| - Ok(new_context) => new_context,
|
| - Err(err) => return Err(err),
|
| - };
|
| - let elems = {
|
| - let state = decoder.get_mut(&context);
|
| - match state.decode_array_header::<T>() {
|
| - Ok(header) => header.data(),
|
| - Err(err) => return Err(err),
|
| - }
|
| - };
|
| - Ok((context, elems as usize))
|
| -}
|
| -
|
| -impl<K: MojomEncodable + Eq + Hash, V: MojomEncodable> MojomPointer for HashMap<K, V> {
|
| - fn header_data(&self) -> DataHeaderValue {
|
| - DataHeaderValue::Version(0)
|
| - }
|
| - fn serialized_size(&self, _context: &Context) -> usize {
|
| - MAP_SIZE
|
| - }
|
| - fn encode_value(self, encoder: &mut Encoder, context: Context) {
|
| - let elems = self.len();
|
| - let meta_value = DataHeaderValue::Elements(elems as u32);
|
| - // We need to move values into this vector because we can't copy the keys.
|
| - // (Handles are not copyable so MojomEncodable cannot be copyable!)
|
| - let mut vals_vec = Vec::with_capacity(elems);
|
| - // Key setup
|
| - // Write a pointer to the keys array.
|
| - let keys_loc = encoder.size() as u64;
|
| - {
|
| - let state = encoder.get_mut(&context);
|
| - state.encode_pointer(keys_loc);
|
| - }
|
| - // Create the keys data header
|
| - let keys_bytes = DATA_HEADER_SIZE + (K::embed_size(&context) * elems).as_bytes();
|
| - let keys_data_header = DataHeader::new(keys_bytes, meta_value);
|
| - // Claim space for the keys array in the encoder
|
| - let keys_context = encoder.add(&keys_data_header).unwrap();
|
| - // Encode keys, setup vals
|
| - for (key, value) in self.into_iter() {
|
| - key.encode(encoder, keys_context.clone());
|
| - vals_vec.push(value);
|
| - }
|
| - // Encode vals
|
| - vals_vec.encode(encoder, context.clone())
|
| - }
|
| - fn decode_value(decoder: &mut Decoder, context: Context) -> Result<HashMap<K, V>, ValidationError> {
|
| - let (keys_offset, vals_offset) = {
|
| - let state = decoder.get_mut(&context);
|
| - match state.decode_struct_header(&MAP_VERSIONS) {
|
| - Ok(_) => (),
|
| - Err(err) => return Err(err),
|
| - };
|
| - // Decode the keys pointer and check for overflow
|
| - let keys_offset = match state.decode_pointer() {
|
| - Some(ptr) => ptr,
|
| - None => return Err(ValidationError::IllegalPointer),
|
| - };
|
| - // Decode the keys pointer and check for overflow
|
| - let vals_offset = match state.decode_pointer() {
|
| - Some(ptr) => ptr,
|
| - None => return Err(ValidationError::IllegalPointer),
|
| - };
|
| - if keys_offset == MOJOM_NULL_POINTER || vals_offset == MOJOM_NULL_POINTER {
|
| - return Err(ValidationError::UnexpectedNullPointer);
|
| - }
|
| - (keys_offset as usize, vals_offset as usize)
|
| - };
|
| - let (keys_context, keys_elems) = match array_claim_and_decode_header::<K>(decoder, keys_offset) {
|
| - Ok((context, elems)) => (context, elems),
|
| - Err(err) => return Err(err),
|
| - };
|
| - let mut keys_vec: Vec<K> = Vec::with_capacity(keys_elems as usize);
|
| - for _ in 0..keys_elems {
|
| - let key = match K::decode(decoder, keys_context.clone()) {
|
| - Ok(value) => value,
|
| - Err(err) => return Err(err),
|
| - };
|
| - keys_vec.push(key);
|
| - }
|
| - let (vals_context, vals_elems) = match array_claim_and_decode_header::<V>(decoder, vals_offset) {
|
| - Ok((context, elems)) => (context, elems),
|
| - Err(err) => return Err(err),
|
| - };
|
| - if keys_elems != vals_elems {
|
| - return Err(ValidationError::DifferentSizedArraysInMap);
|
| - }
|
| - let mut map = HashMap::with_capacity(keys_elems as usize);
|
| - for key in keys_vec.into_iter() {
|
| - let val = match V::decode(decoder, vals_context.clone()) {
|
| - Ok(value) => value,
|
| - Err(err) => return Err(err),
|
| - };
|
| - map.insert(key, val);
|
| - }
|
| - Ok(map)
|
| - }
|
| -}
|
| -
|
| -impl<K: MojomEncodable + Eq + Hash, V: MojomEncodable> MojomEncodable for HashMap<K, V> {
|
| - impl_encodable_for_pointer!();
|
| - fn compute_size(&self, context: Context) -> usize {
|
| - let mut size = encoding::align_default(self.serialized_size(&context));
|
| - // The size of the one array
|
| - size += DATA_HEADER_SIZE;
|
| - size += (K::embed_size(&context) * self.len()).as_bytes();
|
| - size = encoding::align_default(size);
|
| - // Any extra space used by the keys
|
| - for (key, _) in self {
|
| - size += key.compute_size(context.clone());
|
| - }
|
| - // Need to re-align after this for the next array
|
| - size = encoding::align_default(size);
|
| - // The size of the one array
|
| - size += DATA_HEADER_SIZE;
|
| - size += (V::embed_size(&context) * self.len()).as_bytes();
|
| - size = encoding::align_default(size);
|
| - // Any extra space used by the values
|
| - for (_, value) in self {
|
| - size += value.compute_size(context.clone());
|
| - }
|
| - // Align one more time at the end to keep the next object aligned.
|
| - encoding::align_default(size)
|
| - }
|
| -}
|
| -
|
| -impl<T: MojomEncodable + CastHandle + Handle> MojomHandle for T {}
|
| -
|
| -macro_rules! impl_encodable_for_handle {
|
| - ($handle_type:path) => {
|
| - fn mojom_alignment() -> usize {
|
| - 4
|
| - }
|
| - fn mojom_type() -> MojomType {
|
| - MojomType::Handle
|
| - }
|
| - fn embed_size(_context: &Context) -> Bits {
|
| - Bits(8 * mem::size_of::<u32>())
|
| - }
|
| - fn compute_size(&self, _context: Context) -> usize {
|
| - 0
|
| - }
|
| - fn encode(self, encoder: &mut Encoder, context: Context) {
|
| - let pos = encoder.add_handle(self.as_untyped());
|
| - let mut state = encoder.get_mut(&context);
|
| - state.encode(pos as i32);
|
| - }
|
| - fn decode(decoder: &mut Decoder, context: Context) -> Result<$handle_type, ValidationError> {
|
| - let handle_index = {
|
| - let mut state = decoder.get_mut(&context);
|
| - state.decode::<i32>()
|
| - };
|
| - decoder.claim_handle::<$handle_type>(handle_index)
|
| - }
|
| - }
|
| -}
|
| -
|
| -impl MojomEncodable for UntypedHandle {
|
| - impl_encodable_for_handle!(UntypedHandle);
|
| -}
|
| -
|
| -impl MojomEncodable for message_pipe::MessageEndpoint {
|
| - impl_encodable_for_handle!(message_pipe::MessageEndpoint);
|
| -}
|
| -
|
| -impl MojomEncodable for shared_buffer::SharedBuffer {
|
| - impl_encodable_for_handle!(shared_buffer::SharedBuffer);
|
| -}
|
| -
|
| -impl<T> MojomEncodable for data_pipe::Consumer<T> {
|
| - impl_encodable_for_handle!(data_pipe::Consumer<T>);
|
| -}
|
| -
|
| -impl<T> MojomEncodable for data_pipe::Producer<T> {
|
| - impl_encodable_for_handle!(data_pipe::Producer<T>);
|
| -}
|
| -
|
| -impl MojomEncodable for wait_set::WaitSet {
|
| - impl_encodable_for_handle!(wait_set::WaitSet);
|
| -}
|
|
|