blob: cc7633afb9161cdf01dad877daac65ac48ff13bc [file] [log] [blame]
// 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 std::mem;
use std::vec;
use std::ptr;
use system::ffi;
use system::handle;
use system::handle::{CastHandle, Handle};
// This full import is intentional; nearly every type in mojo_types needs to be used.
use system::mojo_types::*;
#[repr(u32)]
/// Create flags for message pipes
pub enum Create {
None = 0,
}
#[repr(u32)]
/// Write flags for message pipes
pub enum Write {
None = 0,
}
#[repr(u32)]
/// Read flags for message pipes
pub enum Read {
None = 0,
/// If the message is unable to be
/// read for whatever reason, dequeue
/// it anyway
MayDiscard = 1 << 0,
}
/// Creates a message pipe in Mojo and gives back two
/// MessageEndpoints which represent the endpoints of the
/// message pipe
pub fn create(flags: CreateFlags) -> Result<(MessageEndpoint, MessageEndpoint), MojoResult> {
let mut handle0: MojoHandle = 0;
let mut handle1: MojoHandle = 0;
let opts = ffi::MojoCreateMessagePipeOptions {
struct_size: mem::size_of::<ffi::MojoCreateMessagePipeOptions>() as u32,
flags: flags,
_align: [],
};
let raw_opts = &opts as *const ffi::MojoCreateMessagePipeOptions;
let r = MojoResult::from_code(unsafe {
ffi::MojoCreateMessagePipe(raw_opts,
&mut handle0 as *mut MojoHandle,
&mut handle1 as *mut MojoHandle)
});
if r != MojoResult::Okay {
Err(r)
} else {
Ok((MessageEndpoint { handle: unsafe { handle::acquire(handle0) } },
MessageEndpoint { handle: unsafe { handle::acquire(handle1) } }))
}
}
/// Represents the one endpoint of a message pipe.
/// This data structure wraps a handle and acts
/// effectively as a typed handle.
pub struct MessageEndpoint {
handle: handle::UntypedHandle,
}
impl MessageEndpoint {
/// Read the next message from the endpoint. Messages in Mojo
/// are some set of bytes plus a bunch of handles, so we
/// return both a vector of bytes and a vector of untyped handles.
///
/// Because the handles are untyped, it is up to the user of this
/// library to know what type the handle actually is and to use
/// from_untyped in order to convert the handle to the correct type.
/// This is abstracted away, however, when using the Mojo bindings
/// generator where you may specify your interface in Mojom.
///
/// If an empty message (that is, it has neither data nor handles)
/// is received, it will show up as an Err() containing MojoResult::Okay.
pub fn read(&self,
flags: ReadFlags)
-> Result<(vec::Vec<u8>, vec::Vec<handle::UntypedHandle>), MojoResult> {
let mut num_bytes: u32 = 0;
let mut num_handles: u32 = 0;
let result_prelim = MojoResult::from_code(unsafe {
ffi::MojoReadMessage(self.handle.get_native_handle(),
ptr::null_mut(),
&mut num_bytes as *mut u32,
ptr::null_mut(),
&mut num_handles as *mut u32,
flags)
});
if result_prelim != MojoResult::ResourceExhausted {
return Err(result_prelim);
}
let mut buf: vec::Vec<u8> = vec::Vec::with_capacity(num_bytes as usize);
let mut raw_handles: vec::Vec<MojoHandle> = vec::Vec::with_capacity(num_handles as usize);
let buf_ptr;
if num_bytes == 0 {
buf_ptr = ptr::null_mut();
} else {
buf_ptr = buf.as_mut_ptr() as *mut ffi::c_void;
}
let raw_handles_ptr;
if num_handles == 0 {
raw_handles_ptr = ptr::null_mut();
} else {
raw_handles_ptr = raw_handles.as_mut_ptr();
}
let r = MojoResult::from_code(unsafe {
ffi::MojoReadMessage(self.handle.get_native_handle(),
buf_ptr,
&mut num_bytes as *mut u32,
raw_handles_ptr,
&mut num_handles as *mut u32,
flags)
});
unsafe {
buf.set_len(num_bytes as usize);
raw_handles.set_len(num_handles as usize);
}
let mut handles: vec::Vec<handle::UntypedHandle> =
vec::Vec::with_capacity(num_handles as usize);
for raw_handle in raw_handles.iter() {
handles.push(unsafe { handle::acquire(*raw_handle) });
}
if r != MojoResult::Okay {
Err(r)
} else {
Ok((buf, handles))
}
}
/// Write a message to the endpoint. Messages in Mojo
/// are some set of bytes plus a bunch of handles, so we
/// return both a vector of bytes and a vector of untyped handles.
///
/// Because the handles are untyped, it is up to the user of this
/// library to know what type the handle actually is and to use
/// from_untyped in order to convert the handle to the correct type.
/// This is abstracted away, however, when using the Mojo bindings
/// generator where you may specify your interface in Mojom.
///
/// Additionally, the handles passed in are consumed. This is because
/// Mojo handles operate on move semantics much like Rust data types.
/// When a handle is sent through a message pipe it is invalidated and
/// may not even be represented by the same integer on the other side,
/// so care must be taken to design your application with this in mind.
pub fn write(&self,
bytes: &[u8],
mut handles: vec::Vec<handle::UntypedHandle>,
flags: WriteFlags)
-> MojoResult {
let bytes_ptr;
if bytes.len() == 0 {
bytes_ptr = ptr::null();
} else {
bytes_ptr = bytes.as_ptr() as *const ffi::c_void;
}
let mut raw_handles: vec::Vec<MojoHandle> = vec::Vec::with_capacity(handles.len());
for handle in handles.iter_mut() {
unsafe {
raw_handles.push(handle.get_native_handle());
handle.invalidate();
}
}
let raw_handles_ptr;
if raw_handles.len() == 0 {
raw_handles_ptr = ptr::null();
} else {
raw_handles_ptr = raw_handles.as_ptr();
}
return MojoResult::from_code(unsafe {
ffi::MojoWriteMessage(self.handle.get_native_handle(),
bytes_ptr,
bytes.len() as u32,
raw_handles_ptr,
raw_handles.len() as u32,
flags)
});
}
}
impl CastHandle for MessageEndpoint {
/// Generates a MessageEndpoint from an untyped handle wrapper
/// See mojo::system::handle for information on untyped vs. typed
unsafe fn from_untyped(handle: handle::UntypedHandle) -> Self {
MessageEndpoint { handle: handle }
}
/// Consumes this object and produces a plain handle wrapper
/// See mojo::system::handle for information on untyped vs. typed
fn as_untyped(self) -> handle::UntypedHandle {
self.handle
}
}
impl Handle for MessageEndpoint {
/// Returns the native handle wrapped by this structure.
///
/// See mojo::system::handle for information on handle wrappers
fn get_native_handle(&self) -> MojoHandle {
self.handle.get_native_handle()
}
}