#![deny(warnings)]
#[macro_use]
extern crate bitflags;
pub extern crate fuchsia_zircon_sys as sys;
#[deprecated(note="use fuchsia_zircon::sys::ZX_CPRNG_DRAW_MAX_LEN instead")]
#[doc(hidden)]
pub use sys::ZX_CPRNG_DRAW_MAX_LEN;
macro_rules! impl_handle_based {
($type_name:path) => {
impl AsHandleRef for $type_name {
fn as_handle_ref(&self) -> HandleRef {
self.0.as_handle_ref()
}
}
impl From<Handle> for $type_name {
fn from(handle: Handle) -> Self {
$type_name(handle)
}
}
impl From<$type_name> for Handle {
fn from(x: $type_name) -> Handle {
x.0
}
}
impl HandleBased for $type_name {}
}
}
macro_rules! assoc_consts {
($typename:ident, [$($name:ident = $num:expr;)*]) => {
#[allow(non_upper_case_globals)]
impl $typename {
$(
pub const $name: $typename = $typename($num);
)*
}
}
}
mod channel;
mod cprng;
mod event;
mod eventpair;
mod fifo;
mod handle;
mod job;
mod port;
mod process;
mod rights;
mod socket;
mod signals;
mod status;
mod time;
mod thread;
mod vmar;
mod vmo;
pub use channel::*;
pub use cprng::*;
pub use event::*;
pub use eventpair::*;
pub use fifo::*;
pub use handle::*;
pub use job::*;
pub use port::*;
pub use process::*;
pub use rights::*;
pub use socket::*;
pub use signals::*;
pub use status::*;
pub use thread::*;
pub use time::*;
pub use vmar::*;
pub use vmo::*;
pub mod prelude {
pub use {
AsHandleRef,
Cookied,
DurationNum,
HandleBased,
Peered,
};
}
pub fn ok(raw: sys::zx_status_t) -> Result<(), Status> {
Status::ok(raw)
}
#[repr(C)]
#[derive(Debug)]
pub struct WaitItem<'a> {
pub handle: HandleRef<'a>,
pub waitfor: Signals,
pub pending: Signals,
}
#[repr(u32)]
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum ClockId {
Monotonic = 0,
UTC = 1,
Thread = 2,
}
pub fn object_wait_many(items: &mut [WaitItem], deadline: Time) -> Result<bool, Status>
{
let len = try!(usize_into_u32(items.len()).map_err(|_| Status::OUT_OF_RANGE));
let items_ptr = items.as_mut_ptr() as *mut sys::zx_wait_item_t;
let status = unsafe { sys::zx_object_wait_many( items_ptr, len, deadline.nanos()) };
if status == sys::ZX_ERR_CANCELED {
return Ok(true)
}
ok(status).map(|()| false)
}
#[cfg(test)]
mod tests {
use super::*;
#[allow(unused_imports)]
use super::prelude::*;
#[test]
fn monotonic_time_increases() {
let time1 = Time::get(ClockId::Monotonic);
1_000.nanos().sleep();
let time2 = Time::get(ClockId::Monotonic);
assert!(time2 > time1);
}
#[test]
fn utc_time_increases() {
let time1 = Time::get(ClockId::UTC);
1_000.nanos().sleep();
let time2 = Time::get(ClockId::UTC);
assert!(time2 > time1);
}
#[test]
fn thread_time_increases() {
let time1 = Time::get(ClockId::Thread);
1_000.nanos().sleep();
let time2 = Time::get(ClockId::Thread);
assert!(time2 > time1);
}
#[test]
fn ticks_increases() {
let ticks1 = ticks_get();
1_000.nanos().sleep();
let ticks2 = ticks_get();
assert!(ticks2 > ticks1);
}
#[test]
fn tick_length() {
let sleep_time = 1.milli();
let ticks1 = ticks_get();
sleep_time.sleep();
let ticks2 = ticks_get();
let sleep_ticks = sleep_time.millis() * ticks_per_second() / 1000;
assert!(ticks2 >= (ticks1 + sleep_ticks));
}
#[test]
fn into_raw() {
let vmo = Vmo::create(1).unwrap();
let h = vmo.into_raw();
let vmo2 = Vmo::from(unsafe { Handle::from_raw(h) });
assert!(vmo2.write(b"1", 0).is_ok());
}
#[test]
fn sleep() {
let sleep_ns = 1.millis();
let time1 = Time::get(ClockId::Monotonic);
sleep_ns.sleep();
let time2 = Time::get(ClockId::Monotonic);
assert!(time2 > time1 + sleep_ns);
}
#[test]
fn duplicate() {
let hello_length: usize = 5;
let vmo = Vmo::create(hello_length as u64).unwrap();
assert!(vmo.write(b"hello", 0).is_ok());
let readonly_vmo = vmo.duplicate_handle(Rights::READ).unwrap();
let mut read_vec = vec![0; hello_length];
assert_eq!(readonly_vmo.read(&mut read_vec, 0).unwrap(), hello_length);
assert_eq!(read_vec, b"hello");
assert_eq!(readonly_vmo.write(b"", 0), Err(Status::ACCESS_DENIED));
assert!(vmo.write(b"bye", 0).is_ok());
assert_eq!(readonly_vmo.read(&mut read_vec, 0).unwrap(), hello_length);
assert_eq!(read_vec, b"byelo");
}
#[test]
fn replace() {
let hello_length: usize = 5;
let vmo = Vmo::create(hello_length as u64).unwrap();
assert!(vmo.write(b"hello", 0).is_ok());
let readonly_vmo = vmo.replace_handle(Rights::READ).unwrap();
let mut read_vec = vec![0; hello_length];
assert_eq!(readonly_vmo.read(&mut read_vec, 0).unwrap(), hello_length);
assert_eq!(read_vec, b"hello");
assert_eq!(readonly_vmo.write(b"", 0), Err(Status::ACCESS_DENIED));
}
#[test]
fn wait_and_signal() {
let event = Event::create().unwrap();
let ten_ms = 10.millis();
assert_eq!(event.wait_handle(
Signals::USER_0, ten_ms.after_now()), Err(Status::TIMED_OUT));
assert!(event.signal_handle(Signals::NONE, Signals::USER_0).is_ok());
assert_eq!(event.wait_handle(Signals::USER_0, ten_ms.after_now()).unwrap(),
Signals::USER_0);
assert_eq!(event.wait_handle(Signals::USER_0, ten_ms.after_now()).unwrap(),
Signals::USER_0);
assert!(event.signal_handle(Signals::USER_0, Signals::NONE).is_ok());
assert_eq!(event.wait_handle(
Signals::USER_0, ten_ms.after_now()), Err(Status::TIMED_OUT));
}
#[test]
fn wait_many_and_signal() {
let ten_ms = 10.millis();
let e1 = Event::create().unwrap();
let e2 = Event::create().unwrap();
let mut items = vec![
WaitItem { handle: e1.as_handle_ref(), waitfor: Signals::USER_0, pending: Signals::NONE },
WaitItem { handle: e2.as_handle_ref(), waitfor: Signals::USER_1, pending: Signals::NONE },
];
assert_eq!(object_wait_many(&mut items, ten_ms.after_now()), Err(Status::TIMED_OUT));
assert_eq!(items[0].pending, Signals::NONE);
assert_eq!(items[1].pending, Signals::NONE);
assert!(e1.signal_handle(Signals::NONE, Signals::USER_0).is_ok());
assert!(object_wait_many(&mut items, ten_ms.after_now()).is_ok());
assert_eq!(items[0].pending, Signals::USER_0);
assert_eq!(items[1].pending, Signals::NONE);
assert!(e2.signal_handle(Signals::NONE, Signals::USER_1).is_ok());
assert!(object_wait_many(&mut items, ten_ms.after_now()).is_ok());
assert_eq!(items[0].pending, Signals::USER_0);
assert_eq!(items[1].pending, Signals::USER_1);
assert!(e1.signal_handle(Signals::USER_0, Signals::NONE).is_ok());
assert!(e2.signal_handle(Signals::USER_1, Signals::NONE).is_ok());
assert_eq!(object_wait_many(&mut items, ten_ms.after_now()), Err(Status::TIMED_OUT));
assert_eq!(items[0].pending, Signals::NONE);
assert_eq!(items[1].pending, Signals::NONE);
}
#[test]
fn cookies() {
let event = Event::create().unwrap();
let scope = Event::create().unwrap();
assert_eq!(event.get_cookie(&scope.as_handle_ref()), Err(Status::ACCESS_DENIED));
assert_eq!(event.set_cookie(&scope.as_handle_ref(), 42), Ok(()));
assert_eq!(event.get_cookie(&scope.as_handle_ref()), Ok(42));
assert_eq!(event.get_cookie(&event.as_handle_ref()), Err(Status::ACCESS_DENIED));
assert_eq!(event.set_cookie(&scope.as_handle_ref(), 123), Ok(()));
assert_eq!(event.set_cookie(&event.as_handle_ref(), 123), Err(Status::ACCESS_DENIED));
}
}
pub fn usize_into_u32(n: usize) -> Result<u32, ()> {
if n > ::std::u32::MAX as usize || n < ::std::u32::MIN as usize {
return Err(())
}
Ok(n as u32)
}
pub fn size_to_u32_sat(n: usize) -> u32 {
if n > ::std::u32::MAX as usize {
return ::std::u32::MAX;
}
if n < ::std::u32::MIN as usize {
return ::std::u32::MIN;
}
n as u32
}