<commit_before>//! Kata OS CAmkES component helpers

#![no_std]
#![allow(non_camel_case_types)]

use allocator;
use logger::KataLogger;
use slot_allocator::KATA_CSPACE_SLOTS;
use log::trace;
use sel4_sys;

use sel4_sys::seL4_CNode_Delete;
use sel4_sys::seL4_CPtr;
use sel4_sys::seL4_GetCapReceivePath;
use sel4_sys::seL4_SetCap;
use sel4_sys::seL4_SetCapReceivePath;
use sel4_sys::seL4_Word;
use sel4_sys::seL4_WordBits;

pub type seL4_CPath = (seL4_CPtr, seL4_CPtr, seL4_Word);

extern "C" {
    // CAmkES components marked with
    //    attribute integer kataos = 1;
    // automatically get a self-reference to their top-level CNode and
    // the slot #'s of the first & last free slots in the CNode.
    static SELF_CNODE: seL4_CPtr;
    static SELF_CNODE_FIRST_SLOT: seL4_CPtr;
    static SELF_CNODE_LAST_SLOT: seL4_CPtr;
}

// RAII wrapper for handling request cap cleanup.
pub struct RequestCapCleanup {}
impl Drop for RequestCapCleanup {
    fn drop(&mut self) {
        unsafe { seL4_SetCap(0, 0); }
    }
}

pub struct Camkes {
    name: &'static str, // Component name
    recv_path: seL4_CPath, // IPCBuffer receive path
}

impl Camkes {
    pub const fn new(name: &'static str) -> Self {
        Camkes {
            name,
            recv_path: (seL4_CPtr::MAX, seL4_CPtr::MAX, seL4_Word::MAX),
        }
    }

    pub fn init_logger(self: &Camkes, level: log::LevelFilter) {
        static KATA_LOGGER: KataLogger = KataLogger;
        log::set_logger(&KATA_LOGGER).unwrap();
        log::set_max_level(level);
    }

    pub fn init_allocator(self: &Camkes, heap: &'static mut [u8]) {
        unsafe {
            allocator::ALLOCATOR.init(heap.as_mut_ptr() as usize, heap.len());
        }
        trace!("setup heap: start_addr {:p} size {}", heap.as_ptr(), heap.len());
    }

    pub fn init_slot_allocator(self: &Camkes, first_slot: seL4_CPtr, last_slot: seL4_CPtr) {
        unsafe {
            KATA_CSPACE_SLOTS.init(self.name, first_slot, last_slot - first_slot);
            trace!("setup cspace slots: first slot {} free {}",
                   KATA_CSPACE_SLOTS.base_slot(),
                   KATA_CSPACE_SLOTS.free_slots());
        }
    }

    pub fn pre_init(
        self: &Camkes,
        level: log::LevelFilter,
        heap: &'static mut [u8],
    ) {
        self.init_logger(level);
        self.init_allocator(heap);
        unsafe { self.init_slot_allocator(SELF_CNODE_FIRST_SLOT, SELF_CNODE_LAST_SLOT); }
    }

    pub fn top_level_path(slot: seL4_CPtr) -> seL4_CPath {
        unsafe { (SELF_CNODE, slot, seL4_WordBits) }
    }

    // Initializes the IPCBuffer receive path with |path|.
    pub fn init_recv_path(self: &mut Camkes, path: &seL4_CPath) {
        self.recv_path = *path;
        unsafe { seL4_SetCapReceivePath(path.0, path.1, path.2); }
        trace!("{}: Cap receive path {:?}", self.name, path);
    }

    // Returns the path specified with init_recv_path.
    pub fn get_recv_path(self: &Camkes) -> seL4_CPath { self.recv_path }

    // Returns the component name.
    pub fn get_name(self: &Camkes) -> &'static str { self.name }

    // Returns the current receive path from the IPCBuffer.
    pub fn get_current_recv_path(self: &Camkes) -> seL4_CPath {
        unsafe { seL4_GetCapReceivePath() }
    }

    // Clears any capability the receive path path points to.
    pub fn clear_recv_path(self: &Camkes) {
        let path = &self.recv_path;
        // Assert since future receives are likely to fail
        unsafe { seL4_CNode_Delete(path.0, path.1, path.2 as u8) }.expect(self.name);
    }

    // Check the current receive path in the IPCBuffer against what was
    // setup with init_recv_path.
    pub fn check_recv_path(self: &Camkes) -> bool {
        self.get_current_recv_path() == self.get_recv_path()
    }

    // Like check_recv_path but asserts if there is an inconsistency.
    pub fn assert_recv_path(self: &Camkes) {
        assert!(self.check_recv_path(),
                "Current receive path {:?} does not match init'd path {:?}",
                self.get_current_recv_path(), self.recv_path);
    }

    // Attaches a capability to a CAmkES RPC request msg. seL4 will copy
    // the capabiltiy.
    #[must_use]
    pub fn set_request_cap(cptr: seL4_CPtr) -> RequestCapCleanup {
        unsafe { seL4_SetCap(0, cptr); }
        RequestCapCleanup{}
    }

    // Wrappers for sel4_sys::debug_assert macros.
    pub fn debug_assert_slot_empty(tag: &str, path: &seL4_CPath) {
        sel4_sys::debug_assert_slot_empty!(path.1,
            "{}: expected slot {:?} empty but has cap type {:?}",
            tag, path, sel4_sys::cap_identify(path.1));
    }
    pub fn debug_assert_slot_cnode(tag: &str, path: &seL4_CPath) {
        sel4_sys::debug_assert_slot_cnode!(path.1,
            "{}: expected cnode in slot {:?} but found cap type {:?}",
            tag, path, sel4_sys::cap_identify(path.1));
    }
}
<commit_msg>kata-os-camkes: wrap reply ipc buffer capability handling<commit_after>//! Kata OS CAmkES component helpers

#![no_std]
#![allow(non_camel_case_types)]

use allocator;
use logger::KataLogger;
use slot_allocator::KATA_CSPACE_SLOTS;
use log::trace;
use sel4_sys;

use sel4_sys::seL4_CNode_Delete;
use sel4_sys::seL4_CPtr;
use sel4_sys::seL4_GetCapReceivePath;
use sel4_sys::seL4_SetCap;
use sel4_sys::seL4_SetCapReceivePath;
use sel4_sys::seL4_Word;
use sel4_sys::seL4_WordBits;

pub type seL4_CPath = (seL4_CPtr, seL4_CPtr, seL4_Word);

extern "C" {
    // CAmkES components marked with
    //    attribute integer kataos = 1;
    // automatically get a self-reference to their top-level CNode and
    // the slot #'s of the first & last free slots in the CNode.
    static SELF_CNODE: seL4_CPtr;
    static SELF_CNODE_FIRST_SLOT: seL4_CPtr;
    static SELF_CNODE_LAST_SLOT: seL4_CPtr;
}

// Flag or'd into reply capability to indicate the cap should be
// deleted _after_ the reply is done. This depends on KataOS-specific
// CAmkES support enabled through build glue (cbindgen processes this
// crate to generate CamkesBindings.h which exports #define CAP_RELEASE
// that enables the necessaery #ifdef's).
pub const CAP_RELEASE: usize = 0x8000_0000;

// RAII wrapper for handling request cap cleanup.
pub struct RequestCapCleanup {}
impl Drop for RequestCapCleanup {
    fn drop(&mut self) {
        unsafe { seL4_SetCap(0, 0); }
    }
}

pub struct Camkes {
    name: &'static str, // Component name
    recv_path: seL4_CPath, // IPCBuffer receive path
}

impl Camkes {
    pub const fn new(name: &'static str) -> Self {
        Camkes {
            name,
            recv_path: (seL4_CPtr::MAX, seL4_CPtr::MAX, seL4_Word::MAX),
        }
    }

    pub fn init_logger(self: &Camkes, level: log::LevelFilter) {
        static KATA_LOGGER: KataLogger = KataLogger;
        log::set_logger(&KATA_LOGGER).unwrap();
        log::set_max_level(level);
    }

    pub fn init_allocator(self: &Camkes, heap: &'static mut [u8]) {
        unsafe {
            allocator::ALLOCATOR.init(heap.as_mut_ptr() as usize, heap.len());
        }
        trace!("setup heap: start_addr {:p} size {}", heap.as_ptr(), heap.len());
    }

    pub fn init_slot_allocator(self: &Camkes, first_slot: seL4_CPtr, last_slot: seL4_CPtr) {
        unsafe {
            KATA_CSPACE_SLOTS.init(self.name, first_slot, last_slot - first_slot);
            trace!("setup cspace slots: first slot {} free {}",
                   KATA_CSPACE_SLOTS.base_slot(),
                   KATA_CSPACE_SLOTS.free_slots());
        }
    }

    pub fn pre_init(
        self: &Camkes,
        level: log::LevelFilter,
        heap: &'static mut [u8],
    ) {
        self.init_logger(level);
        self.init_allocator(heap);
        unsafe { self.init_slot_allocator(SELF_CNODE_FIRST_SLOT, SELF_CNODE_LAST_SLOT); }
    }

    pub fn top_level_path(slot: seL4_CPtr) -> seL4_CPath {
        unsafe { (SELF_CNODE, slot, seL4_WordBits) }
    }

    // Initializes the IPCBuffer receive path with |path|.
    pub fn init_recv_path(self: &mut Camkes, path: &seL4_CPath) {
        self.recv_path = *path;
        unsafe { seL4_SetCapReceivePath(path.0, path.1, path.2); }
        trace!("{}: Cap receive path {:?}", self.name, path);
    }

    // Returns the path specified with init_recv_path.
    pub fn get_recv_path(self: &Camkes) -> seL4_CPath { self.recv_path }

    // Returns the component name.
    pub fn get_name(self: &Camkes) -> &'static str { self.name }

    // Returns the current receive path from the IPCBuffer.
    pub fn get_current_recv_path(self: &Camkes) -> seL4_CPath {
        unsafe { seL4_GetCapReceivePath() }
    }

    // Clears any capability the receive path path points to.
    pub fn clear_recv_path(self: &Camkes) {
        let path = &self.recv_path;
        // Assert since future receives are likely to fail
        unsafe { seL4_CNode_Delete(path.0, path.1, path.2 as u8) }.expect(self.name);
    }

    // Check the current receive path in the IPCBuffer against what was
    // setup with init_recv_path.
    pub fn check_recv_path(self: &Camkes) -> bool {
        self.get_current_recv_path() == self.get_recv_path()
    }

    // Like check_recv_path but asserts if there is an inconsistency.
    pub fn assert_recv_path(self: &Camkes) {
        assert!(self.check_recv_path(),
                "Current receive path {:?} does not match init'd path {:?}",
                self.get_current_recv_path(), self.recv_path);
    }

    // Attaches a capability to a CAmkES RPC request msg. seL4 will copy
    // the capabiltiy.
    #[must_use]
    pub fn set_request_cap(cptr: seL4_CPtr) -> RequestCapCleanup {
        unsafe { seL4_SetCap(0, cptr); }
        RequestCapCleanup{}
    }

    // Attaches a capability to a CAmkES RPC reply msg. seL4 will copy
    // the capabiltiy.
    pub fn set_reply_cap(cptr: seL4_CPtr) {
        unsafe { seL4_SetCap(0, cptr); }
    }

    // Attaches a capability to a CAmkES RPC reply msg and arranges for
    // the capability to be released after the reply completes.
    pub fn set_reply_cap_release(cptr: seL4_CPtr) {
        unsafe {
            // NB: logically this belongs in the CAmkES code where the
            // cap is deleted but that's not possible so do it here--there
            // should be no race to re-purpose the slot since everything
            // is assumed single-threaded (and CAmkES-generated code does
            // not short-circuit the cap delete).
            KATA_CSPACE_SLOTS.free(cptr, 1);
            seL4_SetCap(0, cptr | CAP_RELEASE);
        }
    }

    // Clears any capability attached to a CAmkES RPC reply msg.
    pub fn clear_reply_cap() { Camkes::set_reply_cap(0); }

    // Wrappers for sel4_sys::debug_assert macros.
    pub fn debug_assert_slot_empty(tag: &str, path: &seL4_CPath) {
        sel4_sys::debug_assert_slot_empty!(path.1,
            "{}: expected slot {:?} empty but has cap type {:?}",
            tag, path, sel4_sys::cap_identify(path.1));
    }
    pub fn debug_assert_slot_cnode(tag: &str, path: &seL4_CPath) {
        sel4_sys::debug_assert_slot_cnode!(path.1,
            "{}: expected cnode in slot {:?} but found cap type {:?}",
            tag, path, sel4_sys::cap_identify(path.1));
    }
}
<|endoftext|>


<commit_before>#![feature(plugin)]
#![plugin(clippy)]

#![allow(dead_code)]
#![allow(unused_variables)]
#![deny(large_enum_variant)]

enum LargeEnum {
    A(i32),
    B([i32; 8000]), //~ ERROR large enum variant found
    //~^ HELP consider boxing the large fields to reduce the total size of the enum
    //~| SUGGESTION Box<[i32; 8000]>
}

enum GenericEnum<T> {
    A(i32),
    B([i32; 8000]), //~ ERROR large enum variant found
    //~^ HELP consider boxing the large fields to reduce the total size of the enum
    //~| SUGGESTION Box<[i32; 8000]>
    C([T; 8000]),
    D(T, [i32; 8000]), //~ ERROR large enum variant found
    //~^ HELP consider boxing the large fields to reduce the total size of the enum
}

trait SomeTrait {
    type Item;
}

enum LargeEnumGeneric<A: SomeTrait> {
    Var(A::Item), // regression test, this used to ICE
}

enum AnotherLargeEnum {
    VariantOk(i32, u32),
    ContainingLargeEnum(LargeEnum), //~ ERROR large enum variant found
    //~^ HELP consider boxing the large fields to reduce the total size of the enum
    //~| SUGGESTION Box<LargeEnum>
    ContainingMoreThanOneField(i32, [i32; 8000], [i32; 9500]), //~ ERROR large enum variant found
    //~^ HELP consider boxing the large fields to reduce the total size of the enum
    VoidVariant,
    StructLikeLittle { x: i32, y: i32 },
    StructLikeLarge { x: [i32; 8000], y: i32 }, //~ ERROR large enum variant found
    //~^ HELP consider boxing the large fields to reduce the total size of the enum
    StructLikeLarge2 {
        x:
        [i32; 8000] //~ SUGGESTION Box<[i32; 8000]>
    },
    //~^ ERROR large enum variant found
    //~^ HELP consider boxing the large fields to reduce the total size of the enum
}

fn main() {

}
<commit_msg>place the error checks on the correct lines<commit_after>#![feature(plugin)]
#![plugin(clippy)]

#![allow(dead_code)]
#![allow(unused_variables)]
#![deny(large_enum_variant)]

enum LargeEnum {
    A(i32),
    B([i32; 8000]), //~ ERROR large enum variant found
    //~^ HELP consider boxing the large fields to reduce the total size of the enum
    //~| SUGGESTION Box<[i32; 8000]>
}

enum GenericEnum<T> {
    A(i32),
    B([i32; 8000]), //~ ERROR large enum variant found
    //~^ HELP consider boxing the large fields to reduce the total size of the enum
    //~| SUGGESTION Box<[i32; 8000]>
    C([T; 8000]),
    D(T, [i32; 8000]), //~ ERROR large enum variant found
    //~^ HELP consider boxing the large fields to reduce the total size of the enum
}

trait SomeTrait {
    type Item;
}

enum LargeEnumGeneric<A: SomeTrait> {
    Var(A::Item), // regression test, this used to ICE
}

enum AnotherLargeEnum {
    VariantOk(i32, u32),
    ContainingLargeEnum(LargeEnum), //~ ERROR large enum variant found
    //~^ HELP consider boxing the large fields to reduce the total size of the enum
    //~| SUGGESTION Box<LargeEnum>
    ContainingMoreThanOneField(i32, [i32; 8000], [i32; 9500]), //~ ERROR large enum variant found
    //~^ HELP consider boxing the large fields to reduce the total size of the enum
    VoidVariant,
    StructLikeLittle { x: i32, y: i32 },
    StructLikeLarge { x: [i32; 8000], y: i32 }, //~ ERROR large enum variant found
    //~^ HELP consider boxing the large fields to reduce the total size of the enum
    StructLikeLarge2 { //~ ERROR large enum variant found
        x:
        [i32; 8000] //~ SUGGESTION Box<[i32; 8000]>
        //~^ HELP consider boxing the large fields to reduce the total size of the enum
    },
}

fn main() {

}
<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// pretty-expanded FIXME #23616

/* Any copyright is dedicated to the Public Domain.
 * http://creativecommons.org/publicdomain/zero/1.0/ */

#![allow(warnings)]
#![feature(box_syntax, box_heap)]

// Tests that the new `box` syntax works with unique pointers.

use std::boxed::{Box, HEAP};

struct Structure {
    x: isize,
    y: isize,
}

pub fn main() {
    let x: Box<isize> = box(HEAP) 2;
    let y: Box<isize> = box 2;
    let b: Box<isize> = box()(1 + 2);
    let c = box()(3 + 4);
}
<commit_msg>Add new feature gate opt-in necessary for `new-box-syntax.rs`.<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// pretty-expanded FIXME #23616

/* Any copyright is dedicated to the Public Domain.
 * http://creativecommons.org/publicdomain/zero/1.0/ */

#![allow(warnings)]
#![feature(box_syntax, box_heap)]
#![feature(placement_in_syntax)]

// Tests that the new `box` syntax works with unique pointers.

use std::boxed::{Box, HEAP};

struct Structure {
    x: isize,
    y: isize,
}

pub fn main() {
    let x: Box<isize> = box(HEAP) 2;
    let y: Box<isize> = box 2;
    let b: Box<isize> = box()(1 + 2);
    let c = box()(3 + 4);
}
<|endoftext|>


<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! This module provides utilities to handle data across non-Rust
//! interfaces, like other programming languages and the underlying
//! operating system.  It is mainly of use for FFI (Foreign Function
//! Interface) bindings and code that needs to exchange C-like strings
//! with other languages.
//!
//! # Overview
//!
//! Rust represents owned strings with the [`String`] type, and
//! borrowed slices of strings with the [`str`] primitive.  Both are
//! always in UTF-8 encoding, and may contain nul bytes in the middle,
//! i.e. if you look at the bytes that make up the string, there may
//! be a `\0` among them.  Both `String` and `str` store their length
//! explicitly; there are no nul terminators at the end of strings
//! like in C.
//!
//! C strings are different from Rust strings:
//!
//! * **Encodings** - Rust strings are UTF-8, but C strings may use
//! other encodings.  If you are using a string from C, you should
//! check its encoding explicitly, rather than just assuming that it
//! is UTF-8 like you can do in Rust.
//!
//! * **Character size** - C strings may use `char` or `wchar_t`-sized
//! characters; please **note** that C's `char` is different from Rust's.
//! The C standard leaves the actual sizes of those types open to
//! interpretation, but defines different APIs for strings made up of
//! each character type.  Rust strings are always UTF-8, so different
//! Unicode characters will be encoded in a variable number of bytes
//! each.  The Rust type [`char`] represents a '[Unicode scalar
//! value]', which is similar to, but not the same as, a '[Unicode
//! code point]'.
//!
//! * **Nul terminators and implicit string lengths** - Often, C
//! strings are nul-terminated, i.e. they have a `\0` character at the
//! end.  The length of a string buffer is not stored, but has to be
//! calculated; to compute the length of a string, C code must
//! manually call a function like `strlen()` for `char`-based strings,
//! or `wcslen()` for `wchar_t`-based ones.  Those functions return
//! the number of characters in the string excluding the nul
//! terminator, so the buffer length is really `len+1` characters.
//! Rust strings don't have a nul terminator; their length is always
//! stored and does not need to be calculated.  While in Rust
//! accessing a string's length is a O(1) operation (becasue the
//! length is stored); in C it is an O(length) operation because the
//! length needs to be computed by scanning the string for the nul
//! terminator.
//!
//! * **Internal nul characters** - When C strings have a nul
//! terminator character, this usually means that they cannot have nul
//! characters in the middle — a nul character would essentially
//! truncate the string.  Rust strings *can* have nul characters in
//! the middle, because nul does not have to mark the end of the
//! string in Rust.
//!
//! # Representations of non-Rust strings
//!
//! [`CString`] and [`CStr`] are useful when you need to transfer
//! UTF-8 strings to and from languages with a C ABI, like Python.
//!
//! * **From Rust to C:** [`CString`] represents an owned, C-friendly
//! string: it is nul-terminated, and has no internal nul characters.
//! Rust code can create a `CString` out of a normal string (provided
//! that the string doesn't have nul characters in the middle), and
//! then use a variety of methods to obtain a raw `*mut u8` that can
//! then be passed as an argument to functions which use the C
//! conventions for strings.
//!
//! * **From C to Rust:** [`CStr`] represents a borrowed C string; it
//! is what you would use to wrap a raw `*const u8` that you got from
//! a C function.  A `CStr` is guaranteed to be a nul-terminated array
//! of bytes.  Once you have a `CStr`, you can convert it to a Rust
//! `&str` if it's valid UTF-8, or lossily convert it by adding
//! replacement characters.
//!
//! [`OsString`] and [`OsStr`] are useful when you need to transfer
//! strings to and from the operating system itself, or when capturing
//! the output of external commands.  Conversions between `OsString`,
//! `OsStr` and Rust strings work similarly to those for [`CString`]
//! and [`CStr`].
//!
//! * [`OsString`] represents an owned string in whatever
//! representation the operating system prefers.  In the Rust standard
//! library, various APIs that transfer strings to/from the operating
//! system use `OsString` instead of plain strings.  For example,
//! [`env::var_os()`] is used to query environment variables; it
//! returns an `Option<OsString>`.  If the environment variable exists
//! you will get a `Some(os_string)`, which you can *then* try to
//! convert to a Rust string.  This yields a [`Result<>`], so that
//! your code can detect errors in case the environment variable did
//! not in fact contain valid Unicode data.
//!
//! * [`OsStr`] represents a borrowed reference to a string in a
//! format that can be passed to the operating system.  It can be
//! converted into an UTF-8 Rust string slice in a similar way to
//! `OsString`.
//!
//! # Conversions
//!
//! ## On Unix
//!
//! On Unix, [`OsStr`] implements the
//! `std::os::unix:ffi::`[`OsStrExt`][unix.OsStrExt] trait, which
//! augments it with two methods, [`from_bytes`] and [`as_bytes`].
//! These do inexpensive conversions from and to UTF-8 byte slices.
//!
//! Additionally, on Unix [`OsString`] implements the
//! `std::os::unix:ffi::`[`OsStringExt`][unix.OsStringExt] trait,
//! which provides [`from_vec`] and [`into_vec`] methods that consume
//! their arguments, and take or produce vectors of [`u8`].
//!
//! ## On Windows
//!
//! On Windows, [`OsStr`] implements the
//! `std::os::windows::ffi::`[`OsStrExt`][windows.OsStrExt] trait,
//! which provides an [`encode_wide`] method.  This provides an
//! iterator that can be [`collect`]ed into a vector of [`u16`].
//!
//! Additionally, on Windows [`OsString`] implements the
//! `std::os::windows:ffi::`[`OsStringExt`][windows.OsStringExt]
//! trait, which provides a [`from_wide`] method.  The result of this
//! method is an `OsString` which can be round-tripped to a Windows
//! string losslessly.
//!
//! [`String`]: ../string/struct.String.html
//! [`str`]: ../primitive.str.html
//! [`char`]: ../primitive.char.html
//! [`u8`]: ../primitive.u8.html
//! [`u16`]: ../primitive.u16.html
//! [Unicode scalar value]: http://www.unicode.org/glossary/#unicode_scalar_value
//! [Unicode code point]: http://www.unicode.org/glossary/#code_point
//! [`CString`]: struct.CString.html
//! [`CStr`]: struct.CStr.html
//! [`OsString`]: struct.OsString.html
//! [`OsStr`]: struct.OsStr.html
//! [`env::set_var()`]: ../env/fn.set_var.html
//! [`env::var_os()`]: ../env/fn.var_os.html
//! [`Result<>`]: ../result/enum.Result.html
//! [unix.OsStringExt]: ../os/unix/ffi/trait.OsStringExt.html
//! [`from_vec`]: ../os/unix/ffi/trait.OsStringExt.html#tymethod.from_vec
//! [`into_vec`]: ../os/unix/ffi/trait.OsStringExt.html#tymethod.into_vec
//! [unix.OsStrExt]: ../os/unix/ffi/trait.OsStrExt.html
//! [`from_bytes`]: ../os/unix/ffi/trait.OsStrExt.html#tymethod.from_bytes
//! [`as_bytes`]: ../os/unix/ffi/trait.OsStrExt.html#tymethod.as_bytes
//! [`OsStrExt`]: ../os/unix/ffi/trait.OsStrExt.html
//! [windows.OsStrExt]: ../os/windows/ffi/trait.OsStrExt.html
//! [`encode_wide`]: ../os/windows/ffi/trait.OsStrExt.html#tymethod.encode_wide
//! [`collect`]: ../iter/trait.Iterator.html#method.collect
//! [windows.OsStringExt]: ../os/windows/ffi/trait.OsStringExt.html
//! [`from_wide`]: ../os/windows/ffi/trait.OsStringExt.html#tymethod.from_wide

#![stable(feature = "rust1", since = "1.0.0")]

#[stable(feature = "rust1", since = "1.0.0")]
pub use self::c_str::{CString, CStr, NulError, IntoStringError};
#[stable(feature = "cstr_from_bytes", since = "1.10.0")]
pub use self::c_str::{FromBytesWithNulError};

#[stable(feature = "rust1", since = "1.0.0")]
pub use self::os_str::{OsString, OsStr};

mod c_str;
mod os_str;
<commit_msg>ffi/mod.rs: Keep the one-sentence summary at the beginning of the module<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Utilities related to FFI bindings.
//!
//! This module provides utilities to handle data across non-Rust
//! interfaces, like other programming languages and the underlying
//! operating system.  It is mainly of use for FFI (Foreign Function
//! Interface) bindings and code that needs to exchange C-like strings
//! with other languages.
//!
//! # Overview
//!
//! Rust represents owned strings with the [`String`] type, and
//! borrowed slices of strings with the [`str`] primitive.  Both are
//! always in UTF-8 encoding, and may contain nul bytes in the middle,
//! i.e. if you look at the bytes that make up the string, there may
//! be a `\0` among them.  Both `String` and `str` store their length
//! explicitly; there are no nul terminators at the end of strings
//! like in C.
//!
//! C strings are different from Rust strings:
//!
//! * **Encodings** - Rust strings are UTF-8, but C strings may use
//! other encodings.  If you are using a string from C, you should
//! check its encoding explicitly, rather than just assuming that it
//! is UTF-8 like you can do in Rust.
//!
//! * **Character size** - C strings may use `char` or `wchar_t`-sized
//! characters; please **note** that C's `char` is different from Rust's.
//! The C standard leaves the actual sizes of those types open to
//! interpretation, but defines different APIs for strings made up of
//! each character type.  Rust strings are always UTF-8, so different
//! Unicode characters will be encoded in a variable number of bytes
//! each.  The Rust type [`char`] represents a '[Unicode scalar
//! value]', which is similar to, but not the same as, a '[Unicode
//! code point]'.
//!
//! * **Nul terminators and implicit string lengths** - Often, C
//! strings are nul-terminated, i.e. they have a `\0` character at the
//! end.  The length of a string buffer is not stored, but has to be
//! calculated; to compute the length of a string, C code must
//! manually call a function like `strlen()` for `char`-based strings,
//! or `wcslen()` for `wchar_t`-based ones.  Those functions return
//! the number of characters in the string excluding the nul
//! terminator, so the buffer length is really `len+1` characters.
//! Rust strings don't have a nul terminator; their length is always
//! stored and does not need to be calculated.  While in Rust
//! accessing a string's length is a O(1) operation (becasue the
//! length is stored); in C it is an O(length) operation because the
//! length needs to be computed by scanning the string for the nul
//! terminator.
//!
//! * **Internal nul characters** - When C strings have a nul
//! terminator character, this usually means that they cannot have nul
//! characters in the middle — a nul character would essentially
//! truncate the string.  Rust strings *can* have nul characters in
//! the middle, because nul does not have to mark the end of the
//! string in Rust.
//!
//! # Representations of non-Rust strings
//!
//! [`CString`] and [`CStr`] are useful when you need to transfer
//! UTF-8 strings to and from languages with a C ABI, like Python.
//!
//! * **From Rust to C:** [`CString`] represents an owned, C-friendly
//! string: it is nul-terminated, and has no internal nul characters.
//! Rust code can create a `CString` out of a normal string (provided
//! that the string doesn't have nul characters in the middle), and
//! then use a variety of methods to obtain a raw `*mut u8` that can
//! then be passed as an argument to functions which use the C
//! conventions for strings.
//!
//! * **From C to Rust:** [`CStr`] represents a borrowed C string; it
//! is what you would use to wrap a raw `*const u8` that you got from
//! a C function.  A `CStr` is guaranteed to be a nul-terminated array
//! of bytes.  Once you have a `CStr`, you can convert it to a Rust
//! `&str` if it's valid UTF-8, or lossily convert it by adding
//! replacement characters.
//!
//! [`OsString`] and [`OsStr`] are useful when you need to transfer
//! strings to and from the operating system itself, or when capturing
//! the output of external commands.  Conversions between `OsString`,
//! `OsStr` and Rust strings work similarly to those for [`CString`]
//! and [`CStr`].
//!
//! * [`OsString`] represents an owned string in whatever
//! representation the operating system prefers.  In the Rust standard
//! library, various APIs that transfer strings to/from the operating
//! system use `OsString` instead of plain strings.  For example,
//! [`env::var_os()`] is used to query environment variables; it
//! returns an `Option<OsString>`.  If the environment variable exists
//! you will get a `Some(os_string)`, which you can *then* try to
//! convert to a Rust string.  This yields a [`Result<>`], so that
//! your code can detect errors in case the environment variable did
//! not in fact contain valid Unicode data.
//!
//! * [`OsStr`] represents a borrowed reference to a string in a
//! format that can be passed to the operating system.  It can be
//! converted into an UTF-8 Rust string slice in a similar way to
//! `OsString`.
//!
//! # Conversions
//!
//! ## On Unix
//!
//! On Unix, [`OsStr`] implements the
//! `std::os::unix:ffi::`[`OsStrExt`][unix.OsStrExt] trait, which
//! augments it with two methods, [`from_bytes`] and [`as_bytes`].
//! These do inexpensive conversions from and to UTF-8 byte slices.
//!
//! Additionally, on Unix [`OsString`] implements the
//! `std::os::unix:ffi::`[`OsStringExt`][unix.OsStringExt] trait,
//! which provides [`from_vec`] and [`into_vec`] methods that consume
//! their arguments, and take or produce vectors of [`u8`].
//!
//! ## On Windows
//!
//! On Windows, [`OsStr`] implements the
//! `std::os::windows::ffi::`[`OsStrExt`][windows.OsStrExt] trait,
//! which provides an [`encode_wide`] method.  This provides an
//! iterator that can be [`collect`]ed into a vector of [`u16`].
//!
//! Additionally, on Windows [`OsString`] implements the
//! `std::os::windows:ffi::`[`OsStringExt`][windows.OsStringExt]
//! trait, which provides a [`from_wide`] method.  The result of this
//! method is an `OsString` which can be round-tripped to a Windows
//! string losslessly.
//!
//! [`String`]: ../string/struct.String.html
//! [`str`]: ../primitive.str.html
//! [`char`]: ../primitive.char.html
//! [`u8`]: ../primitive.u8.html
//! [`u16`]: ../primitive.u16.html
//! [Unicode scalar value]: http://www.unicode.org/glossary/#unicode_scalar_value
//! [Unicode code point]: http://www.unicode.org/glossary/#code_point
//! [`CString`]: struct.CString.html
//! [`CStr`]: struct.CStr.html
//! [`OsString`]: struct.OsString.html
//! [`OsStr`]: struct.OsStr.html
//! [`env::set_var()`]: ../env/fn.set_var.html
//! [`env::var_os()`]: ../env/fn.var_os.html
//! [`Result<>`]: ../result/enum.Result.html
//! [unix.OsStringExt]: ../os/unix/ffi/trait.OsStringExt.html
//! [`from_vec`]: ../os/unix/ffi/trait.OsStringExt.html#tymethod.from_vec
//! [`into_vec`]: ../os/unix/ffi/trait.OsStringExt.html#tymethod.into_vec
//! [unix.OsStrExt]: ../os/unix/ffi/trait.OsStrExt.html
//! [`from_bytes`]: ../os/unix/ffi/trait.OsStrExt.html#tymethod.from_bytes
//! [`as_bytes`]: ../os/unix/ffi/trait.OsStrExt.html#tymethod.as_bytes
//! [`OsStrExt`]: ../os/unix/ffi/trait.OsStrExt.html
//! [windows.OsStrExt]: ../os/windows/ffi/trait.OsStrExt.html
//! [`encode_wide`]: ../os/windows/ffi/trait.OsStrExt.html#tymethod.encode_wide
//! [`collect`]: ../iter/trait.Iterator.html#method.collect
//! [windows.OsStringExt]: ../os/windows/ffi/trait.OsStringExt.html
//! [`from_wide`]: ../os/windows/ffi/trait.OsStringExt.html#tymethod.from_wide

#![stable(feature = "rust1", since = "1.0.0")]

#[stable(feature = "rust1", since = "1.0.0")]
pub use self::c_str::{CString, CStr, NulError, IntoStringError};
#[stable(feature = "cstr_from_bytes", since = "1.10.0")]
pub use self::c_str::{FromBytesWithNulError};

#[stable(feature = "rust1", since = "1.0.0")]
pub use self::os_str::{OsString, OsStr};

mod c_str;
mod os_str;
<|endoftext|>


<commit_before>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Interfaces to the operating system provided random number
//! generators.

pub use self::imp::OsRng;

#[cfg(all(unix, not(target_os = "ios")))]
mod imp {
    use io::{IoResult, File};
    use path::Path;
    use rand::Rng;
    use rand::reader::ReaderRng;
    use result::{Ok, Err};

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed
    /// This does not block.
    #[cfg(unix)]
    pub struct OsRng {
        inner: ReaderRng<File>
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            let reader = try!(File::open(&Path::new("/dev/urandom")));
            let reader_rng = ReaderRng::new(reader);

            Ok(OsRng { inner: reader_rng })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            self.inner.next_u32()
        }
        fn next_u64(&mut self) -> u64 {
            self.inner.next_u64()
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            self.inner.fill_bytes(v)
        }
    }
}

#[cfg(target_os = "ios")]
mod imp {
    extern crate libc;

    use collections::Collection;
    use io::{IoResult};
    use kinds::marker;
    use mem;
    use os;
    use rand::Rng;
    use result::{Ok};
    use self::libc::{c_int, size_t};
    use slice::MutableSlice;

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed
    /// This does not block.
    pub struct OsRng {
        marker: marker::NoCopy
    }

    #[repr(C)]
    struct SecRandom;

    static kSecRandomDefault: *const SecRandom = 0 as *const SecRandom;

    #[link(name = "Security", kind = "framework")]
    extern "C" {
        fn SecRandomCopyBytes(rnd: *const SecRandom,
                              count: size_t, bytes: *mut u8) -> c_int;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            Ok(OsRng {marker: marker::NoCopy} )
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0u8, .. 4];
            self.fill_bytes(v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0u8, .. 8];
            self.fill_bytes(v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                SecRandomCopyBytes(kSecRandomDefault, v.len() as size_t, v.as_mut_ptr())
            };
            if ret == -1 {
                fail!("couldn't generate random bytes: {}", os::last_os_error());
            }
        }
    }
}

#[cfg(windows)]
mod imp {
    extern crate libc;

    use core_collections::Collection;
    use io::{IoResult, IoError};
    use mem;
    use ops::Drop;
    use os;
    use rand::Rng;
    use result::{Ok, Err};
    use self::libc::{DWORD, BYTE, LPCSTR, BOOL};
    use self::libc::types::os::arch::extra::{LONG_PTR};
    use slice::MutableSlice;

    type HCRYPTPROV = LONG_PTR;

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    ///
    /// This does not block.
    pub struct OsRng {
        hcryptprov: HCRYPTPROV
    }

    static PROV_RSA_FULL: DWORD = 1;
    static CRYPT_SILENT: DWORD = 64;
    static CRYPT_VERIFYCONTEXT: DWORD = 0xF0000000;

    #[allow(non_snake_case)]
    extern "system" {
        fn CryptAcquireContextA(phProv: *mut HCRYPTPROV,
                                pszContainer: LPCSTR,
                                pszProvider: LPCSTR,
                                dwProvType: DWORD,
                                dwFlags: DWORD) -> BOOL;
        fn CryptGenRandom(hProv: HCRYPTPROV,
                          dwLen: DWORD,
                          pbBuffer: *mut BYTE) -> BOOL;
        fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) -> BOOL;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            let mut hcp = 0;
            let ret = unsafe {
                CryptAcquireContextA(&mut hcp, 0 as LPCSTR, 0 as LPCSTR,
                                     PROV_RSA_FULL,
                                     CRYPT_VERIFYCONTEXT | CRYPT_SILENT)
            };

            if ret == 0 {
                Err(IoError::last_error())
            } else {
                Ok(OsRng { hcryptprov: hcp })
            }
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0u8, .. 4];
            self.fill_bytes(v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0u8, .. 8];
            self.fill_bytes(v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                CryptGenRandom(self.hcryptprov, v.len() as DWORD,
                               v.as_mut_ptr())
            };
            if ret == 0 {
                fail!("couldn't generate random bytes: {}", os::last_os_error());
            }
        }
    }

    impl Drop for OsRng {
        fn drop(&mut self) {
            let ret = unsafe {
                CryptReleaseContext(self.hcryptprov, 0)
            };
            if ret == 0 {
                fail!("couldn't release context: {}", os::last_os_error());
            }
        }
    }
}

#[cfg(test)]
mod test {
    use prelude::*;

    use super::OsRng;
    use rand::Rng;
    use task;

    #[test]
    fn test_os_rng() {
        let mut r = OsRng::new().unwrap();

        r.next_u32();
        r.next_u64();

        let mut v = [0u8, .. 1000];
        r.fill_bytes(v);
    }

    #[test]
    fn test_os_rng_tasks() {

        let mut txs = vec!();
        for _ in range(0u, 20) {
            let (tx, rx) = channel();
            txs.push(tx);
            task::spawn(proc() {
                // wait until all the tasks are ready to go.
                rx.recv();

                // deschedule to attempt to interleave things as much
                // as possible (XXX: is this a good test?)
                let mut r = OsRng::new().unwrap();
                task::deschedule();
                let mut v = [0u8, .. 1000];

                for _ in range(0u, 100) {
                    r.next_u32();
                    task::deschedule();
                    r.next_u64();
                    task::deschedule();
                    r.fill_bytes(v);
                    task::deschedule();
                }
            })
        }

        // start all the tasks
        for tx in txs.iter() {
            tx.send(())
        }
    }
}
<commit_msg>auto merge of #17814 : vhbit/rust/ios-build-fix, r=huonw<commit_after>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Interfaces to the operating system provided random number
//! generators.

pub use self::imp::OsRng;

#[cfg(all(unix, not(target_os = "ios")))]
mod imp {
    use io::{IoResult, File};
    use path::Path;
    use rand::Rng;
    use rand::reader::ReaderRng;
    use result::{Ok, Err};

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed
    /// This does not block.
    #[cfg(unix)]
    pub struct OsRng {
        inner: ReaderRng<File>
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            let reader = try!(File::open(&Path::new("/dev/urandom")));
            let reader_rng = ReaderRng::new(reader);

            Ok(OsRng { inner: reader_rng })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            self.inner.next_u32()
        }
        fn next_u64(&mut self) -> u64 {
            self.inner.next_u64()
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            self.inner.fill_bytes(v)
        }
    }
}

#[cfg(target_os = "ios")]
mod imp {
    extern crate libc;

    use collections::Collection;
    use io::{IoResult};
    use kinds::marker;
    use mem;
    use os;
    use rand::Rng;
    use result::{Ok};
    use self::libc::{c_int, size_t};
    use slice::MutableSlice;

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed
    /// This does not block.
    pub struct OsRng {
        marker: marker::NoCopy
    }

    #[repr(C)]
    struct SecRandom;

    #[allow(non_uppercase_statics)]
    static kSecRandomDefault: *const SecRandom = 0 as *const SecRandom;

    #[link(name = "Security", kind = "framework")]
    extern "C" {
        fn SecRandomCopyBytes(rnd: *const SecRandom,
                              count: size_t, bytes: *mut u8) -> c_int;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            Ok(OsRng {marker: marker::NoCopy} )
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0u8, .. 4];
            self.fill_bytes(v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0u8, .. 8];
            self.fill_bytes(v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                SecRandomCopyBytes(kSecRandomDefault, v.len() as size_t, v.as_mut_ptr())
            };
            if ret == -1 {
                fail!("couldn't generate random bytes: {}", os::last_os_error());
            }
        }
    }
}

#[cfg(windows)]
mod imp {
    extern crate libc;

    use core_collections::Collection;
    use io::{IoResult, IoError};
    use mem;
    use ops::Drop;
    use os;
    use rand::Rng;
    use result::{Ok, Err};
    use self::libc::{DWORD, BYTE, LPCSTR, BOOL};
    use self::libc::types::os::arch::extra::{LONG_PTR};
    use slice::MutableSlice;

    type HCRYPTPROV = LONG_PTR;

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    ///
    /// This does not block.
    pub struct OsRng {
        hcryptprov: HCRYPTPROV
    }

    static PROV_RSA_FULL: DWORD = 1;
    static CRYPT_SILENT: DWORD = 64;
    static CRYPT_VERIFYCONTEXT: DWORD = 0xF0000000;

    #[allow(non_snake_case)]
    extern "system" {
        fn CryptAcquireContextA(phProv: *mut HCRYPTPROV,
                                pszContainer: LPCSTR,
                                pszProvider: LPCSTR,
                                dwProvType: DWORD,
                                dwFlags: DWORD) -> BOOL;
        fn CryptGenRandom(hProv: HCRYPTPROV,
                          dwLen: DWORD,
                          pbBuffer: *mut BYTE) -> BOOL;
        fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) -> BOOL;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            let mut hcp = 0;
            let ret = unsafe {
                CryptAcquireContextA(&mut hcp, 0 as LPCSTR, 0 as LPCSTR,
                                     PROV_RSA_FULL,
                                     CRYPT_VERIFYCONTEXT | CRYPT_SILENT)
            };

            if ret == 0 {
                Err(IoError::last_error())
            } else {
                Ok(OsRng { hcryptprov: hcp })
            }
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0u8, .. 4];
            self.fill_bytes(v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0u8, .. 8];
            self.fill_bytes(v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                CryptGenRandom(self.hcryptprov, v.len() as DWORD,
                               v.as_mut_ptr())
            };
            if ret == 0 {
                fail!("couldn't generate random bytes: {}", os::last_os_error());
            }
        }
    }

    impl Drop for OsRng {
        fn drop(&mut self) {
            let ret = unsafe {
                CryptReleaseContext(self.hcryptprov, 0)
            };
            if ret == 0 {
                fail!("couldn't release context: {}", os::last_os_error());
            }
        }
    }
}

#[cfg(test)]
mod test {
    use prelude::*;

    use super::OsRng;
    use rand::Rng;
    use task;

    #[test]
    fn test_os_rng() {
        let mut r = OsRng::new().unwrap();

        r.next_u32();
        r.next_u64();

        let mut v = [0u8, .. 1000];
        r.fill_bytes(v);
    }

    #[test]
    fn test_os_rng_tasks() {

        let mut txs = vec!();
        for _ in range(0u, 20) {
            let (tx, rx) = channel();
            txs.push(tx);
            task::spawn(proc() {
                // wait until all the tasks are ready to go.
                rx.recv();

                // deschedule to attempt to interleave things as much
                // as possible (XXX: is this a good test?)
                let mut r = OsRng::new().unwrap();
                task::deschedule();
                let mut v = [0u8, .. 1000];

                for _ in range(0u, 100) {
                    r.next_u32();
                    task::deschedule();
                    r.next_u64();
                    task::deschedule();
                    r.fill_bytes(v);
                    task::deschedule();
                }
            })
        }

        // start all the tasks
        for tx in txs.iter() {
            tx.send(())
        }
    }
}
<|endoftext|>


<commit_before>//!
//! The API for communicating with devices.
//!
//! This API is provided as Traits to be implemented:
//!
//! - by the low-level layers of the FoxBox, including the adapters;
//! - by test suites and tools that need to simulate connected devices.
//!
//! In turn, this API is used to implement:
//!
//! - the public-facing REST and WebSocket API;
//! - the rules API (ThinkerBell).
//!
//!

use devices::*;
use requests::*;
use values::Value;

/// An error produced by one of the APIs in this module.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum Error {
    /// There is no such node connected to the Foxbox, even indirectly.
    NoSuchNode(NodeId),

    /// There is no such service connected to the Foxbox, even indirectly.
    NoSuchService(ServiceId),

    /// Attempting to set a value with the wrong type
    TypeError,
}

/// An event during watching.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum WatchEvent {
    /// A new value is available.
    Value {
        /// The service that sent the value.
        from: ServiceId,

        /// The actual value.
        value: Value
    },

    /// The set of devices being watched has changed, typically either
    /// because a tag was edited or because a device was
    /// removed. Payload is the id of the device that was removed.
    InputRemoved(ServiceId),

    /// The set of devices being watched has changed, typically either
    /// because a tag was edited or because a device was
    /// added. Payload is the id of the device that was added.
    InputAdded(ServiceId),
}

/// A handle to the public API.
pub trait API: Send {
    /// Get the metadata on nodes matching some conditions.
    ///
    /// A call to `API::get_nodes(vec![req1, req2, ...])` will return
    /// the metadata on all nodes matching _either_ `req1` or `req2`
    /// or ...
    ///
    /// # REST API
    ///
    /// `GET /api/v1/nodes`
    ///
    /// ## Inputs
    ///
    /// Any JSON that can be deserialized to a `Vec<NodeRequest>`. See
    /// the implementation of `NodeRequest` for details.
    ///
    /// ### Example
    ///
    /// Request all doors in the entrance (tags `door`, `entrance`)
    /// that support output service `OpenClose`
    ///
    /// ```json
    /// [{
    ///   "tags": ["entrance", "door"],
    ///   "inputs": [
    ///     {
    ///       "kind": {
    ///         "Exactly": {
    ///           "OpenClose": []
    ///         }
    ///       }
    ///     }
    ///   ]
    /// }]
    /// ```
    ///
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON representing an array of `Node`. See the implementation
    /// of `Node` for details.
    ///
    /// ### Example
    ///
    /// ```json
    /// [{
    ///   "tags": ["entrance", "door", "somevendor"],
    ///   "id: "some-node-id",
    ///   "inputs": [],
    ///   "outputs": [
    ///     "tags": [...],
    ///     "id": "some-service-id",
    ///     "node": "some-node-id",
    ///     "last_seen": "some-date",
    ///     "mechanism": {
    ///       "Output":  {
    ///         "kind": {
    ///           "OnOff": []
    ///         },
    ///         "push": [5000],
    ///         "updated": "some-date",
    ///       }
    ///     }
    ///   ]
    /// }]
    /// ```
    fn get_nodes(&self, &Vec<NodeRequest>) -> Vec<Node>;

    /// Label a set of nodes with a set of tags.
    ///
    /// A call to `API::put_node_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will label all the nodes matching _either_ `req1` or
    /// `req2` or ... with `tag1`, ... and return the number of nodes
    /// matching any of the requests.
    ///
    /// Some of the nodes may already be labelled with `tag1`, or
    /// `tag2`, ... They will not change state. They are counted in
    /// the resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if nodes
    /// are added after the call, they will not be affected.
    ///
    /// # REST API
    ///
    /// `POST /api/v1/nodes/tag`
    ///
    /// ## Inputs
    ///
    /// Any JSON that can be deserialized to
    ///
    /// ```ignore
    /// {
    ///   set: Vec<NodeRequest>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON string representing a number.
    fn put_node_tag(&self, set: &Vec<NodeRequest>, tags: &Vec<String>) -> usize;

    /// Remove a set of tags from a set of nodes.
    ///
    /// A call to `API::delete_node_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will remove from all the nodes matching _either_ `req1` or
    /// `req2` or ... all of the tags `tag1`, ... and return the number of nodes
    /// matching any of the requests.
    ///
    /// Some of the nodes may not be labelled with `tag1`, or `tag2`,
    /// ... They will not change state. They are counted in the
    /// resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if nodes
    /// are added after the call, they will not be affected.
    ///
    /// # REST API
    ///
    /// `DELETE /api/v1/nodes/tag`
    ///
    /// ## Inputs
    ///
    /// Any JSON that can be deserialized to
    ///
    /// ```ignore
    /// {
    ///   set: Vec<NodeRequest>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON representing a number.
    fn delete_node_tag(&self, set: &Vec<NodeRequest>, tags: String) -> usize;

    /// Get a list of inputs matching some conditions
    ///
    /// # REST API
    ///
    /// `GET /api/v1/services`
    fn get_input_services(&self, &Vec<InputRequest>) -> Vec<Service<Input>>;
    fn get_output_services(&self, &Vec<OutputRequest>) -> Vec<Service<Output>>;

    /// Label a set of services with a set of tags.
    ///
    /// A call to `API::put_{input, output}_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will label all the services matching _either_ `req1` or
    /// `req2` or ... with `tag1`, ... and return the number of services
    /// matching any of the requests.
    ///
    /// Some of the services may already be labelled with `tag1`, or
    /// `tag2`, ... They will not change state. They are counted in
    /// the resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if services
    /// are added after the call, they will not be affected.
    ///
    /// # REST API
    ///
    /// `POST /api/v1/services/tag`
    ///
    /// ## Inputs
    ///
    /// Any JSON that can be deserialized to
    ///
    /// ```ignore
    /// {
    ///   set: Vec<InputRequest>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    /// or
    /// ```ignore
    /// {
    ///   set: Vec<OutputRequest>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON representing a number.
    fn put_input_tag(&self, &Vec<InputRequest>, &Vec<String>) -> usize;
    fn put_output_tag(&self, &Vec<OutputRequest>, &Vec<String>) -> usize;

    /// Remove a set of tags from a set of services.
    ///
    /// A call to `API::delete_{input, output}_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will remove from all the services matching _either_ `req1` or
    /// `req2` or ... all of the tags `tag1`, ... and return the number of services
    /// matching any of the requests.
    ///
    /// Some of the services may not be labelled with `tag1`, or `tag2`,
    /// ... They will not change state. They are counted in the
    /// resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if services
    /// are added after the call, they will not be affected.
    ///
    /// # REST API
    ///
    /// `DELETE /api/v1/services/tag`
    ///
    /// ## Inputs
    ///
    /// Any JSON that can be deserialized to
    ///
    /// ```ignore
    /// {
    ///   set: Vec<InputRequest>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    /// or
    /// ```ignore
    /// {
    ///   set: Vec<OutputRequest>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON representing a number.
    fn delete_input_tag(&self, &Vec<InputRequest>, &Vec<String>) -> usize;
    fn delete_output_tag(&self, &Vec<InputRequest>, &Vec<String>) -> usize;

    /// Read the latest value from a set of services
    ///
    /// # REST API
    ///
    /// `GET /api/v1/services/value`
    fn get_service_value(&self, &Vec<InputRequest>) -> Vec<(ServiceId, Result<Value, Error>)>;

    /// Send one value to a set of services
    ///
    /// # REST API
    ///
    /// `POST /api/v1/services/value`
    fn put_service_value(&self, &Vec<OutputRequest>, Value) -> Vec<(ServiceId, Result<(), Error>)>;

    /// Watch for any change
    ///
    /// # WebSocket API
    ///
    /// `/api/v1/services/watch`
    fn register_service_watch(&self, Vec<WatchOptions>, cb: Box<FnMut(WatchEvent) + Send + 'static>) -> Self::WatchGuard;

    /// A value that causes a disconnection once it is dropped.
    type WatchGuard;
}

/// Options for watching changes in one or more services.
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct WatchOptions {
    /// The set of inputs to watch. Note that the actual inputs in the
    /// set may change over time.
    source: InputRequest,

    /// If `true`, watch as new values become available.
    should_watch_values: bool,

    /// If `true`, watch as nodes are connected/disconnected.
    should_watch_topology: bool,
}

impl WatchOptions {
    pub fn new() -> Self {
        WatchOptions {
            source: InputRequest::new(),
            should_watch_values: false,
            should_watch_topology: false,
        }
    }

    /// Restrict to input services in a given set.
    ///
    /// Also note that the actual input services that are part of the
    /// set may change with time, for instance if devices are added
    /// ore removed.  The request _is live_, i.e. the service watch
    /// will continue watching any input services that match `req`.
    pub fn with_inputs(self, req: InputRequest) -> Self {
        WatchOptions {
            source: self.source.and(req),
            ..self
        }
    }

    pub fn with_watch_values(self, should: bool) -> Self {
        WatchOptions {
            should_watch_values: should,
            ..self
        }
    }

    pub fn with_watch_topology(self, should: bool) -> Self {
        WatchOptions {
            should_watch_topology: should,
            ..self
        }
    }
}
<commit_msg>[fxbox/taxonomy] api::WatchOptions is now semi-public<commit_after>//!
//! The API for communicating with devices.
//!
//! This API is provided as Traits to be implemented:
//!
//! - by the low-level layers of the FoxBox, including the adapters;
//! - by test suites and tools that need to simulate connected devices.
//!
//! In turn, this API is used to implement:
//!
//! - the public-facing REST and WebSocket API;
//! - the rules API (ThinkerBell).
//!
//!

use devices::*;
use requests::*;
use values::Value;

/// An error produced by one of the APIs in this module.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum Error {
    /// There is no such node connected to the Foxbox, even indirectly.
    NoSuchNode(NodeId),

    /// There is no such service connected to the Foxbox, even indirectly.
    NoSuchService(ServiceId),

    /// Attempting to set a value with the wrong type
    TypeError,
}

/// An event during watching.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum WatchEvent {
    /// A new value is available.
    Value {
        /// The service that sent the value.
        from: ServiceId,

        /// The actual value.
        value: Value
    },

    /// The set of devices being watched has changed, typically either
    /// because a tag was edited or because a device was
    /// removed. Payload is the id of the device that was removed.
    InputRemoved(ServiceId),

    /// The set of devices being watched has changed, typically either
    /// because a tag was edited or because a device was
    /// added. Payload is the id of the device that was added.
    InputAdded(ServiceId),
}

/// A handle to the public API.
pub trait API: Send {
    /// Get the metadata on nodes matching some conditions.
    ///
    /// A call to `API::get_nodes(vec![req1, req2, ...])` will return
    /// the metadata on all nodes matching _either_ `req1` or `req2`
    /// or ...
    ///
    /// # REST API
    ///
    /// `GET /api/v1/nodes`
    ///
    /// ## Inputs
    ///
    /// Any JSON that can be deserialized to a `Vec<NodeRequest>`. See
    /// the implementation of `NodeRequest` for details.
    ///
    /// ### Example
    ///
    /// Request all doors in the entrance (tags `door`, `entrance`)
    /// that support output service `OpenClose`
    ///
    /// ```json
    /// [{
    ///   "tags": ["entrance", "door"],
    ///   "inputs": [
    ///     {
    ///       "kind": {
    ///         "Exactly": {
    ///           "OpenClose": []
    ///         }
    ///       }
    ///     }
    ///   ]
    /// }]
    /// ```
    ///
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON representing an array of `Node`. See the implementation
    /// of `Node` for details.
    ///
    /// ### Example
    ///
    /// ```json
    /// [{
    ///   "tags": ["entrance", "door", "somevendor"],
    ///   "id: "some-node-id",
    ///   "inputs": [],
    ///   "outputs": [
    ///     "tags": [...],
    ///     "id": "some-service-id",
    ///     "node": "some-node-id",
    ///     "last_seen": "some-date",
    ///     "mechanism": {
    ///       "Output":  {
    ///         "kind": {
    ///           "OnOff": []
    ///         },
    ///         "push": [5000],
    ///         "updated": "some-date",
    ///       }
    ///     }
    ///   ]
    /// }]
    /// ```
    fn get_nodes(&self, &Vec<NodeRequest>) -> Vec<Node>;

    /// Label a set of nodes with a set of tags.
    ///
    /// A call to `API::put_node_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will label all the nodes matching _either_ `req1` or
    /// `req2` or ... with `tag1`, ... and return the number of nodes
    /// matching any of the requests.
    ///
    /// Some of the nodes may already be labelled with `tag1`, or
    /// `tag2`, ... They will not change state. They are counted in
    /// the resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if nodes
    /// are added after the call, they will not be affected.
    ///
    /// # REST API
    ///
    /// `POST /api/v1/nodes/tag`
    ///
    /// ## Inputs
    ///
    /// Any JSON that can be deserialized to
    ///
    /// ```ignore
    /// {
    ///   set: Vec<NodeRequest>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON string representing a number.
    fn put_node_tag(&self, set: &Vec<NodeRequest>, tags: &Vec<String>) -> usize;

    /// Remove a set of tags from a set of nodes.
    ///
    /// A call to `API::delete_node_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will remove from all the nodes matching _either_ `req1` or
    /// `req2` or ... all of the tags `tag1`, ... and return the number of nodes
    /// matching any of the requests.
    ///
    /// Some of the nodes may not be labelled with `tag1`, or `tag2`,
    /// ... They will not change state. They are counted in the
    /// resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if nodes
    /// are added after the call, they will not be affected.
    ///
    /// # REST API
    ///
    /// `DELETE /api/v1/nodes/tag`
    ///
    /// ## Inputs
    ///
    /// Any JSON that can be deserialized to
    ///
    /// ```ignore
    /// {
    ///   set: Vec<NodeRequest>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON representing a number.
    fn delete_node_tag(&self, set: &Vec<NodeRequest>, tags: String) -> usize;

    /// Get a list of inputs matching some conditions
    ///
    /// # REST API
    ///
    /// `GET /api/v1/services`
    fn get_input_services(&self, &Vec<InputRequest>) -> Vec<Service<Input>>;
    fn get_output_services(&self, &Vec<OutputRequest>) -> Vec<Service<Output>>;

    /// Label a set of services with a set of tags.
    ///
    /// A call to `API::put_{input, output}_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will label all the services matching _either_ `req1` or
    /// `req2` or ... with `tag1`, ... and return the number of services
    /// matching any of the requests.
    ///
    /// Some of the services may already be labelled with `tag1`, or
    /// `tag2`, ... They will not change state. They are counted in
    /// the resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if services
    /// are added after the call, they will not be affected.
    ///
    /// # REST API
    ///
    /// `POST /api/v1/services/tag`
    ///
    /// ## Inputs
    ///
    /// Any JSON that can be deserialized to
    ///
    /// ```ignore
    /// {
    ///   set: Vec<InputRequest>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    /// or
    /// ```ignore
    /// {
    ///   set: Vec<OutputRequest>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON representing a number.
    fn put_input_tag(&self, &Vec<InputRequest>, &Vec<String>) -> usize;
    fn put_output_tag(&self, &Vec<OutputRequest>, &Vec<String>) -> usize;

    /// Remove a set of tags from a set of services.
    ///
    /// A call to `API::delete_{input, output}_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will remove from all the services matching _either_ `req1` or
    /// `req2` or ... all of the tags `tag1`, ... and return the number of services
    /// matching any of the requests.
    ///
    /// Some of the services may not be labelled with `tag1`, or `tag2`,
    /// ... They will not change state. They are counted in the
    /// resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if services
    /// are added after the call, they will not be affected.
    ///
    /// # REST API
    ///
    /// `DELETE /api/v1/services/tag`
    ///
    /// ## Inputs
    ///
    /// Any JSON that can be deserialized to
    ///
    /// ```ignore
    /// {
    ///   set: Vec<InputRequest>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    /// or
    /// ```ignore
    /// {
    ///   set: Vec<OutputRequest>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON representing a number.
    fn delete_input_tag(&self, &Vec<InputRequest>, &Vec<String>) -> usize;
    fn delete_output_tag(&self, &Vec<InputRequest>, &Vec<String>) -> usize;

    /// Read the latest value from a set of services
    ///
    /// # REST API
    ///
    /// `GET /api/v1/services/value`
    fn get_service_value(&self, &Vec<InputRequest>) -> Vec<(ServiceId, Result<Value, Error>)>;

    /// Send one value to a set of services
    ///
    /// # REST API
    ///
    /// `POST /api/v1/services/value`
    fn put_service_value(&self, &Vec<OutputRequest>, Value) -> Vec<(ServiceId, Result<(), Error>)>;

    /// Watch for any change
    ///
    /// # WebSocket API
    ///
    /// `/api/v1/services/watch`
    fn register_service_watch(&self, Vec<WatchOptions>, cb: Box<FnMut(WatchEvent) + Send + 'static>) -> Self::WatchGuard;

    /// A value that causes a disconnection once it is dropped.
    type WatchGuard;
}

/// Options for watching changes in one or more services.
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct WatchOptions {
    /// The set of inputs to watch. Note that the actual inputs in the
    /// set may change over time.
    pub source: InputRequest,

    /// If `true`, watch as new values become available.
    pub should_watch_values: bool,

    /// If `true`, watch as nodes are connected/disconnected.
    pub should_watch_topology: bool,

    /// Make sure that we can't instantiate from another crate.
    #[serde(default, skip_serializing)]
    private: (),
}

impl WatchOptions {
    pub fn new() -> Self {
        WatchOptions {
            source: InputRequest::new(),
            should_watch_values: false,
            should_watch_topology: false,
            private: (),
        }
    }

    /// Restrict to input services in a given set.
    ///
    /// Also note that the actual input services that are part of the
    /// set may change with time, for instance if devices are added
    /// ore removed.  The request _is live_, i.e. the service watch
    /// will continue watching any input services that match `req`.
    pub fn with_inputs(self, req: InputRequest) -> Self {
        WatchOptions {
            source: self.source.and(req),
            ..self
        }
    }

    pub fn with_watch_values(self, should: bool) -> Self {
        WatchOptions {
            should_watch_values: should,
            ..self
        }
    }

    pub fn with_watch_topology(self, should: bool) -> Self {
        WatchOptions {
            should_watch_topology: should,
            ..self
        }
    }
}
<|endoftext|>


<commit_before>use std::io::{BufReader, ErrorKind, Result};
use std::net::TcpStream;

use mio::{net::TcpListener, Events, Poll, PollOpt, Ready, Token};
use slab::Slab;

use birch::client::{ClientConnection, ClientEvent};
use birch::socket::{IrcReader, IrcSocketConfig, IrcWriter};

// TODO: blah
type NetworkId = usize;
type ClientId = usize;

struct Client {
    reader: BufReader<mio::net::TcpStream>,
    writer: mio::net::TcpStream,
    conn: ClientConnection,
    network: Option<NetworkId>,
}

impl Client {
    fn new(stream: &mio::net::TcpStream) -> Self {
        let reader = BufReader::new(stream.try_clone().expect("fork stream"));
        let writer = stream.try_clone().expect("fork stream");

        let conn = ClientConnection::new();

        Self {
            reader,
            writer,
            conn,
            network: None,
        }
    }
}

struct ClientManager {
    clients: Slab<(ClientId, Client)>,
}

impl ClientManager {
    fn new() -> Self {
        Self {
            clients: Slab::with_capacity(32),
        }
    }

    fn add(&mut self, client: Client) -> ClientId {
        let entry = self.clients.vacant_entry();
        let key = entry.key();
        entry.insert((key, client));

        key
    }

    fn find(&mut self, id: ClientId) -> Option<&mut Client> {
        self.clients.get_mut(id).map(|c| &mut c.1)
    }

    fn remove(&mut self, id: ClientId) -> Option<Client> {
        if !self.clients.contains(id) {
            return None;
        }

        Some(self.clients.remove(id).1)
    }

    // TODO: use an iterator
    fn with_network(&mut self, id: NetworkId) -> Vec<&mut Client> {
        self.clients
            .iter_mut()
            .map(|(_, (_, client))| client)
            .filter(|client| client.network.is_some())
            // TODO: .filter(|client| Some(id) == client.network)
            .collect()
    }
}

struct NetworkConfig<'a> {
    network_name: &'a str,
    nick: &'a str,
    socket: IrcSocketConfig,
}

struct Network<'a> {
    id: NetworkId,
    config: NetworkConfig<'a>,
    network: birch::network::NetworkConnection,

    reader: BufReader<mio::net::TcpStream>,
    writer: mio::net::TcpStream,
}

enum SocketKind {
    Listener,
    Network(std::io::BufReader<mio::net::TcpStream>, mio::net::TcpStream),
    Client(ClientId),
}

struct SocketManager {
    sockets: Slab<SocketKind>,
}

impl SocketManager {
    fn new() -> Self {
        Self {
            sockets: Slab::with_capacity(1024),
        }
    }

    fn add(&mut self, socket: SocketKind) -> Token {
        Token(self.sockets.insert(socket))
    }

    fn add_client_listener(&mut self) -> Token {
        Token(self.sockets.insert(SocketKind::Listener))
    }

    fn add_network(&mut self, stream: &mio::net::TcpStream) -> Token {
        let reader = BufReader::new(stream.try_clone().expect("fork stream"));
        let writer = stream.try_clone().expect("fork stream");

        Token(self.sockets.insert(SocketKind::Network(reader, writer)))
    }

    fn find(&mut self, token: Token) -> Option<&mut SocketKind> {
        self.sockets.get_mut(token.0)
    }

    fn remove(&mut self, token: Token) -> bool {
        if self.sockets.contains(token.0) {
            self.sockets.remove(token.0);
            true
        } else {
            false
        }
    }
}

fn main() -> Result<()> {
    let poll = Poll::new()?;
    let mut socket_manager = SocketManager::new();
    let mut client_manager = ClientManager::new();

    let config = NetworkConfig {
        network_name: "freenode",
        nick: "ep",
        socket: IrcSocketConfig {
            addr: "irc.freenode.net:6667".parse().unwrap(),
            max_retries: Some(3),
        },
    };

    let mut network = birch::network::NetworkConnection::new("ep");
    // TODO: this sucks
    network.initialize()?;

    // TODO: Wrap in retry logic
    let network_stream =
        mio::net::TcpStream::from_stream(TcpStream::connect(config.socket.addr)?)?;

    poll.register(
        &network_stream,
        socket_manager.add_network(&network_stream),
        Ready::readable(),
        PollOpt::edge(),
    )?;

    let listener = TcpListener::bind(&"127.0.0.1:9123".parse().unwrap())?;
    poll.register(
        &listener,
        socket_manager.add_client_listener(),
        Ready::readable(),
        PollOpt::edge(),
    )?;

    loop {
        let mut events = Events::with_capacity(128);
        poll.poll(&mut events, None)?;

        for ev in events {
            let mut remove_socket = false;

            let socket = socket_manager.find(ev.token());
            match socket {
                Some(SocketKind::Listener) => loop {
                    match listener.accept() {
                        Ok((ref socket, _)) => {
                            let client_id = client_manager.add(Client::new(socket));
                            let token = socket_manager.add(SocketKind::Client(client_id));

                            poll.register(
                                socket,
                                token,
                                Ready::readable(),
                                PollOpt::edge(),
                            )?;
                        }
                        Err(ref e) if e.kind() == ErrorKind::WouldBlock => break,
                        e => panic!("err={:?}", e),
                    }
                },

                Some(SocketKind::Network(ref mut reader, writer)) => loop {
                    match reader.read_message() {
                        Ok(msg) => {
                            println!("[birch <- \u{1b}[37;1mnet\u{1b}[0m] {}", msg);
                            if let Err(err) = network.handle(&msg) {
                                println!("Failed to handle message: {}", err);
                                break;
                            }

                            for msg in network.network_messages() {
                                println!("[\u{1b}[37;1mbirch\u{1b}[0m -> net] {}", msg);
                                // TODO: handle errors
                                writer.write_message(&msg)?;
                            }

                            for msg in network.user_messages() {
                                // TODO: implement this correctly
                                for client in client_manager.with_network(0) {
                                    client.writer.write_message(&msg)?;
                                }
                            }
                        }
                        Err(ref e) if e.kind() == ErrorKind::WouldBlock => break,
                        Err(e) => {
                            // TODO: Reconnection logic
                            println!("Network errored, disconnecting: {}", e);
                            remove_socket = true;
                            break;
                        }
                    }
                },
                Some(SocketKind::Client(client_id)) => {
                    let client = client_manager
                        .find(*client_id)
                        .expect("activity on unassigned client id");

                    loop {
                        match client.reader.read_message() {
                            Ok(msg) => {
                                println!(
                                    "[birch <- \u{1b}[37;1mclient({})\u{1b}[0m] {}",
                                    ev.token().0,
                                    msg
                                );

                                if let Err(err) = client.conn.handle_message(&msg) {
                                    println!("Failed to handle message: {}", err);
                                    break;
                                }

                                for event in client.conn.events() {
                                    match event {
                                        ClientEvent::WriteNetwork(ref _msg) => unimplemented!(),
                                        ClientEvent::WriteClient(ref msg) => {
                                            client.writer.write_message(msg)?
                                        }
                                        ClientEvent::RegistrationComplete => {
                                            // TODO: dynamic network
                                            // TODO: Update client's nick
                                            network
                                                .state
                                                .welcome_user(&mut client.writer)?;
                                        }
                                        ClientEvent::AuthAttempt(_auth) => {
                                            // TODO: actual auth here
                                            // TODO: set auth result back on client.conn
                                            client.network = Some(0);
                                        }
                                    }
                                }
                            }
                            Err(ref e) if e.kind() == ErrorKind::WouldBlock => break,
                            Err(e) => {
                                println!("Client errored, disconnecting: {}", e);
                                remove_socket = true;
                                break;
                            }
                        }
                    }
                }

                _ => unreachable!(),
            }

            // TODO: Deregister sockets.
            if remove_socket {
                socket_manager.remove(ev.token());
            }
        }
    }

    Ok(())
}
<commit_msg>Pull reader,writer into Socket<commit_after>use std::io::{BufReader, ErrorKind, Result};
use std::net::TcpStream;

use mio::{net::TcpListener, Events, Poll, PollOpt, Ready, Token};
use slab::Slab;

use birch::client::{ClientConnection, ClientEvent};
use birch::socket::{IrcReader, IrcSocketConfig, IrcWriter};

// TODO: blah
type NetworkId = usize;
type ClientId = usize;

struct Socket {
    reader: BufReader<mio::net::TcpStream>,
    writer: mio::net::TcpStream,
}

impl Socket {
    fn from_stream(stream: &mio::net::TcpStream) -> Result<Self> {
        let reader = BufReader::new(stream.try_clone()?);
        let writer = stream.try_clone()?;
        Ok(Self { reader, writer })
    }
}

impl std::io::Read for Socket {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        self.reader.read(buf)
    }
}

impl std::io::Write for Socket {
    fn write(&mut self, buf: &[u8]) -> Result<usize> {
        self.writer.write(buf)
    }

    fn flush(&mut self) -> Result<()> {
        self.writer.flush()
    }
}

struct Client {
    socket: Socket,
    conn: ClientConnection,
    network: Option<NetworkId>,
}

impl Client {
    fn new(stream: &mio::net::TcpStream) -> Self {
        let socket = Socket::from_stream(stream).expect("create client socket");
        let conn = ClientConnection::new();

        Self {
            socket,
            conn,
            network: None,
        }
    }
}

struct ClientManager {
    clients: Slab<(ClientId, Client)>,
}

impl ClientManager {
    fn new() -> Self {
        Self {
            clients: Slab::with_capacity(32),
        }
    }

    fn add(&mut self, client: Client) -> ClientId {
        let entry = self.clients.vacant_entry();
        let key = entry.key();
        entry.insert((key, client));

        key
    }

    fn find(&mut self, id: ClientId) -> Option<&mut Client> {
        self.clients.get_mut(id).map(|c| &mut c.1)
    }

    fn remove(&mut self, id: ClientId) -> Option<Client> {
        if !self.clients.contains(id) {
            return None;
        }

        Some(self.clients.remove(id).1)
    }

    // TODO: use an iterator
    fn with_network(&mut self, id: NetworkId) -> Vec<&mut Client> {
        self.clients
            .iter_mut()
            .map(|(_, (_, client))| client)
            .filter(|client| client.network.is_some())
            // TODO: .filter(|client| Some(id) == client.network)
            .collect()
    }
}

struct NetworkConfig<'a> {
    network_name: &'a str,
    nick: &'a str,
    socket: IrcSocketConfig,
}

struct Network<'a> {
    id: NetworkId,
    config: NetworkConfig<'a>,
    network: birch::network::NetworkConnection,
    socket: Socket,
}

enum SocketKind {
    Listener,
    Network(std::io::BufReader<mio::net::TcpStream>, mio::net::TcpStream),
    Client(ClientId),
}

struct SocketManager {
    sockets: Slab<SocketKind>,
}

impl SocketManager {
    fn new() -> Self {
        Self {
            sockets: Slab::with_capacity(1024),
        }
    }

    fn add(&mut self, socket: SocketKind) -> Token {
        Token(self.sockets.insert(socket))
    }

    fn add_client_listener(&mut self) -> Token {
        Token(self.sockets.insert(SocketKind::Listener))
    }

    fn add_network(&mut self, stream: &mio::net::TcpStream) -> Token {
        let reader = BufReader::new(stream.try_clone().expect("fork stream"));
        let writer = stream.try_clone().expect("fork stream");

        Token(self.sockets.insert(SocketKind::Network(reader, writer)))
    }

    fn find(&mut self, token: Token) -> Option<&mut SocketKind> {
        self.sockets.get_mut(token.0)
    }

    fn remove(&mut self, token: Token) -> bool {
        if self.sockets.contains(token.0) {
            self.sockets.remove(token.0);
            true
        } else {
            false
        }
    }
}

fn main() -> Result<()> {
    let poll = Poll::new()?;
    let mut socket_manager = SocketManager::new();
    let mut client_manager = ClientManager::new();

    let config = NetworkConfig {
        network_name: "freenode",
        nick: "ep",
        socket: IrcSocketConfig {
            addr: "irc.freenode.net:6667".parse().unwrap(),
            max_retries: Some(3),
        },
    };

    let mut network = birch::network::NetworkConnection::new("ep");
    // TODO: this sucks
    network.initialize()?;

    // TODO: Wrap in retry logic
    let network_stream =
        mio::net::TcpStream::from_stream(TcpStream::connect(config.socket.addr)?)?;

    poll.register(
        &network_stream,
        socket_manager.add_network(&network_stream),
        Ready::readable(),
        PollOpt::edge(),
    )?;

    let listener = TcpListener::bind(&"127.0.0.1:9123".parse().unwrap())?;
    poll.register(
        &listener,
        socket_manager.add_client_listener(),
        Ready::readable(),
        PollOpt::edge(),
    )?;

    loop {
        let mut events = Events::with_capacity(128);
        poll.poll(&mut events, None)?;

        for ev in events {
            let mut remove_socket = false;

            let socket = socket_manager.find(ev.token());
            match socket {
                Some(SocketKind::Listener) => loop {
                    match listener.accept() {
                        Ok((ref socket, _)) => {
                            let client_id = client_manager.add(Client::new(socket));
                            let token = socket_manager.add(SocketKind::Client(client_id));

                            poll.register(
                                socket,
                                token,
                                Ready::readable(),
                                PollOpt::edge(),
                            )?;
                        }
                        Err(ref e) if e.kind() == ErrorKind::WouldBlock => break,
                        e => panic!("err={:?}", e),
                    }
                },

                Some(SocketKind::Network(ref mut reader, writer)) => loop {
                    match reader.read_message() {
                        Ok(msg) => {
                            println!("[birch <- \u{1b}[37;1mnet\u{1b}[0m] {}", msg);
                            if let Err(err) = network.handle(&msg) {
                                println!("Failed to handle message: {}", err);
                                break;
                            }

                            for msg in network.network_messages() {
                                println!("[\u{1b}[37;1mbirch\u{1b}[0m -> net] {}", msg);
                                // TODO: handle errors
                                writer.write_message(&msg)?;
                            }

                            for msg in network.user_messages() {
                                // TODO: implement this correctly
                                for client in client_manager.with_network(0) {
                                    client.socket.write_message(&msg)?;
                                }
                            }
                        }
                        Err(ref e) if e.kind() == ErrorKind::WouldBlock => break,
                        Err(e) => {
                            // TODO: Reconnection logic
                            println!("Network errored, disconnecting: {}", e);
                            remove_socket = true;
                            break;
                        }
                    }
                },
                Some(SocketKind::Client(client_id)) => {
                    let client = client_manager
                        .find(*client_id)
                        .expect("activity on unassigned client id");

                    loop {
                        match client.socket.reader.read_message() {
                            Ok(msg) => {
                                println!(
                                    "[birch <- \u{1b}[37;1mclient({})\u{1b}[0m] {}",
                                    ev.token().0,
                                    msg
                                );

                                if let Err(err) = client.conn.handle_message(&msg) {
                                    println!("Failed to handle message: {}", err);
                                    break;
                                }

                                for event in client.conn.events() {
                                    match event {
                                        ClientEvent::WriteNetwork(ref _msg) => unimplemented!(),
                                        ClientEvent::WriteClient(ref msg) => {
                                            client.socket.write_message(msg)?
                                        }
                                        ClientEvent::RegistrationComplete => {
                                            // TODO: dynamic network
                                            // TODO: Update client's nick
                                            network
                                                .state
                                                .welcome_user(&mut client.socket)?;
                                        }
                                        ClientEvent::AuthAttempt(_auth) => {
                                            // TODO: actual auth here
                                            // TODO: set auth result back on client.conn
                                            client.network = Some(0);
                                        }
                                    }
                                }
                            }
                            Err(ref e) if e.kind() == ErrorKind::WouldBlock => break,
                            Err(e) => {
                                println!("Client errored, disconnecting: {}", e);
                                remove_socket = true;
                                break;
                            }
                        }
                    }
                }

                _ => unreachable!(),
            }

            // TODO: Deregister sockets.
            if remove_socket {
                socket_manager.remove(ev.token());
            }
        }
    }

    Ok(())
}
<|endoftext|>


<commit_before>// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use infer::InferCtxt;
use ty::{self, Ty, TyCtxt};
use hir::def_id::DefId;

use super::{FulfillmentContext, FulfillmentError};
use super::{ObligationCause, PredicateObligation, PendingPredicateObligation};

pub trait TraitEngine<'tcx> {
    fn normalize_projection_type<'a, 'gcx>(
        &mut self,
        infcx: &InferCtxt<'a, 'gcx, 'tcx>,
        param_env: ty::ParamEnv<'tcx>,
        projection_ty: ty::ProjectionTy<'tcx>,
        cause: ObligationCause<'tcx>,
    ) -> Ty<'tcx>;

    fn register_bound<'a, 'gcx>(
        &mut self,
        infcx: &InferCtxt<'a, 'gcx, 'tcx>,
        param_env: ty::ParamEnv<'tcx>,
        ty: Ty<'tcx>,
        def_id: DefId,
        cause: ObligationCause<'tcx>,
    );

    fn register_predicate_obligation<'a, 'gcx>(
        &mut self,
        infcx: &InferCtxt<'a, 'gcx, 'tcx>,
        obligation: PredicateObligation<'tcx>,
    );

    fn select_all_or_error<'a, 'gcx>(
        &mut self,
        infcx: &InferCtxt<'a, 'gcx, 'tcx>,
    ) -> Result<(), Vec<FulfillmentError<'tcx>>>;

    fn select_where_possible<'a, 'gcx>(
        &mut self,
        infcx: &InferCtxt<'a, 'gcx, 'tcx>,
    ) -> Result<(), Vec<FulfillmentError<'tcx>>>;

    fn pending_obligations(&self) -> Vec<PendingPredicateObligation<'tcx>>;
}

impl<'a, 'gcx, 'tcx> dyn TraitEngine<'tcx> +'tcx {
   pub fn new(_tcx: TyCtxt<'_, '_, 'tcx>) -> Box<Self + 'tcx>
   {
       Box::new(FulfillmentContext::new())
   }

   pub fn register_predicate_obligations<I>(&mut self,
                                            infcx: &InferCtxt<'a, 'gcx, 'tcx>,
                                            obligations: I)
       where I: IntoIterator<Item = PredicateObligation<'tcx>>
   {
       for obligation in obligations {
           self.register_predicate_obligation(infcx, obligation);
       }
   }
}
<commit_msg>fix `Self`<commit_after>// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use infer::InferCtxt;
use ty::{self, Ty, TyCtxt};
use hir::def_id::DefId;

use super::{FulfillmentContext, FulfillmentError};
use super::{ObligationCause, PredicateObligation, PendingPredicateObligation};

pub trait TraitEngine<'tcx> {
    fn normalize_projection_type<'a, 'gcx>(
        &mut self,
        infcx: &InferCtxt<'a, 'gcx, 'tcx>,
        param_env: ty::ParamEnv<'tcx>,
        projection_ty: ty::ProjectionTy<'tcx>,
        cause: ObligationCause<'tcx>,
    ) -> Ty<'tcx>;

    fn register_bound<'a, 'gcx>(
        &mut self,
        infcx: &InferCtxt<'a, 'gcx, 'tcx>,
        param_env: ty::ParamEnv<'tcx>,
        ty: Ty<'tcx>,
        def_id: DefId,
        cause: ObligationCause<'tcx>,
    );

    fn register_predicate_obligation<'a, 'gcx>(
        &mut self,
        infcx: &InferCtxt<'a, 'gcx, 'tcx>,
        obligation: PredicateObligation<'tcx>,
    );

    fn select_all_or_error<'a, 'gcx>(
        &mut self,
        infcx: &InferCtxt<'a, 'gcx, 'tcx>,
    ) -> Result<(), Vec<FulfillmentError<'tcx>>>;

    fn select_where_possible<'a, 'gcx>(
        &mut self,
        infcx: &InferCtxt<'a, 'gcx, 'tcx>,
    ) -> Result<(), Vec<FulfillmentError<'tcx>>>;

    fn pending_obligations(&self) -> Vec<PendingPredicateObligation<'tcx>>;
}

impl<'a, 'gcx, 'tcx> dyn TraitEngine<'tcx> +'tcx {
   pub fn new(_tcx: TyCtxt<'_, '_, 'tcx>) -> Box<Self> {
       Box::new(FulfillmentContext::new())
   }

   pub fn register_predicate_obligations<I>(&mut self,
                                            infcx: &InferCtxt<'a, 'gcx, 'tcx>,
                                            obligations: I)
       where I: IntoIterator<Item = PredicateObligation<'tcx>>
   {
       for obligation in obligations {
           self.register_predicate_obligation(infcx, obligation);
       }
   }
}
<|endoftext|>