<commit_before>//
// The core DOM types. Defines the basic DOM hierarchy as well as all the HTML elements.
//

use dom::bindings;
use dom::document::Document;
use dom::element::{Element, ElementTypeId, HTMLImageElement, HTMLImageElementTypeId};
use dom::element::{HTMLStyleElementTypeId};
use dom::window::Window;
use layout::debug::DebugMethods;
use layout::flow::FlowContext;
use newcss::complete::CompleteSelectResults;

use core::cast::transmute;
use core::ptr::null;
use geom::size::Size2D;
use js::crust::*;
use js::rust::Compartment;
use std::arc::ARC;

//
// The basic Node structure
//

/// This is what a Node looks like if you do not know what kind of node it is. To unpack it, use
/// downcast().
///
/// FIXME: This should be replaced with a trait once they can inherit from structs.
pub struct AbstractNode {
    priv obj: *mut Node
}

impl Eq for AbstractNode {
    pure fn eq(&self, other: &AbstractNode) -> bool { self.obj == other.obj }
    pure fn ne(&self, other: &AbstractNode) -> bool { self.obj != other.obj }
}

pub struct Node {
    type_id: NodeTypeId,

    parent_node: Option<AbstractNode>,
    first_child: Option<AbstractNode>,
    last_child: Option<AbstractNode>,
    next_sibling: Option<AbstractNode>,
    prev_sibling: Option<AbstractNode>,

    // You must not touch this if you are not layout.
    priv layout_data: Option<@mut LayoutData>
}

#[deriving_eq]
pub enum NodeTypeId {
    DoctypeNodeTypeId,
    CommentNodeTypeId,
    ElementNodeTypeId(ElementTypeId),
    TextNodeTypeId,
}

//
// Auxiliary layout data
//

pub struct LayoutData {
    style: Option<CompleteSelectResults>,
    flow: Option<@FlowContext>,
}

impl LayoutData {
    static pub fn new() -> LayoutData {
        LayoutData {
            style: None,
            flow: None,
        }
    }
}

//
// Basic node types
//

pub struct Doctype {
    parent: Node,
    name: ~str,
    public_id: Option<~str>,
    system_id: Option<~str>,
    force_quirks: bool
}

impl Doctype {
    static pub fn new(name: ~str,
                      public_id: Option<~str>,
                      system_id: Option<~str>,
                      force_quirks: bool)
                   -> Doctype {
        Doctype {
            parent: Node::new(DoctypeNodeTypeId),
            name: name,
            public_id: public_id,
            system_id: system_id,
            force_quirks: force_quirks,
        }
    }
}

pub struct Comment {
    parent: Node,
    text: ~str,
}

impl Comment {
    static pub fn new(text: ~str) -> Comment {
        Comment {
            parent: Node::new(CommentNodeTypeId),
            text: text
        }
    }
}

pub struct Text {
    parent: Node,
    text: ~str,
}

impl Text {
    static pub fn new(text: ~str) -> Text {
        Text {
            parent: Node::new(CommentNodeTypeId),
            text: text
        }
    }
}

impl AbstractNode {
    //
    // Convenience accessors
    //
    // FIXME: Fold these into util::tree.

    fn type_id(self)         -> NodeTypeId           { self.with_imm_node(|n| n.type_id)      }
    fn parent_node(self)     -> Option<AbstractNode> { self.with_imm_node(|n| n.parent_node)  }
    fn first_child(self)     -> Option<AbstractNode> { self.with_imm_node(|n| n.first_child)  }
    fn last_child(self)      -> Option<AbstractNode> { self.with_imm_node(|n| n.last_child)   }
    fn prev_sibling(self)    -> Option<AbstractNode> { self.with_imm_node(|n| n.prev_sibling) }
    fn next_sibling(self)    -> Option<AbstractNode> { self.with_imm_node(|n| n.next_sibling) }

    // NB: You must not call these if you are not layout. We should do something with scoping to
    // ensure this.
    fn layout_data(self)     -> @mut LayoutData {
        self.with_imm_node(|n| n.layout_data.get())
    }
    fn has_layout_data(self) -> bool {
        self.with_imm_node(|n| n.layout_data.is_some())
    }
    fn set_layout_data(self, data: @mut LayoutData) {
        self.with_mut_node(|n| n.layout_data = Some(data))
    }

    //
    // Tree operations
    //
    // FIXME: Fold this into util::tree.
    //

    fn is_leaf(self) -> bool { self.first_child().is_none() }

    // Invariant: `child` is disconnected from the document.
    fn append_child(self, child: AbstractNode) {
        assert self != child;

        do self.with_mut_node |parent_n| {
            do child.with_mut_node |child_n| {
                assert child_n.parent_node.is_none();
                assert child_n.prev_sibling.is_none();
                assert child_n.next_sibling.is_none();

                child_n.parent_node = Some(self);

                match parent_n.last_child {
                    None => parent_n.first_child = Some(child),
                    Some(last_child) => {
                        do last_child.with_mut_node |last_child_n| {
                            assert last_child_n.next_sibling.is_none();
                            last_child_n.next_sibling = Some(child);
                        }
                    }
                }

                child_n.prev_sibling = parent_n.last_child;
            }
        }
    }

    //
    // Tree traversal
    //
    // FIXME: Fold this into util::tree.
    //

    fn each_child(self, f: &fn(AbstractNode) -> bool) {
        let mut current_opt = self.first_child();
        while !current_opt.is_none() {
            let current = current_opt.get();
            if !f(current) {
                break;
            }
            current_opt = current.next_sibling();
        }
    }

    fn traverse_preorder(self, f: &fn(AbstractNode) -> bool) -> bool {
        if !f(self) {
            return false;
        }
        for self.each_child |kid| {
            if !f(kid) {
                return false;
            }
        }
        true
    }

    fn traverse_postorder(self, f: &fn(AbstractNode) -> bool) -> bool {
        for self.each_child |kid| {
            if !f(kid) {
                return false;
            }
        }
        f(self)
    }

    //
    // Downcasting borrows
    //

    fn with_imm_node<R>(self, f: &fn(&Node) -> R) -> R {
        unsafe {
            f(transmute(self.obj))
        }
    }

    fn with_mut_node<R>(self, f: &fn(&mut Node) -> R) -> R {
        unsafe {
            f(transmute(self.obj))
        }
    }

    fn is_text(self) -> bool { self.type_id() == TextNodeTypeId }

    // FIXME: This should be doing dynamic borrow checking for safety.
    fn with_imm_text<R>(self, f: &fn(&Text) -> R) -> R {
        if !self.is_text() {
            fail!(~"node is not text");
        }
        unsafe {
            f(transmute(self.obj))
        }
    }

    fn is_element(self) -> bool {
        match self.type_id() {
            ElementNodeTypeId(*) => true,
            _ => false
        }
    }

    // FIXME: This should be doing dynamic borrow checking for safety.
    fn with_imm_element<R>(self, f: &fn(&Element) -> R) -> R {
        if !self.is_element() {
            fail!(~"node is not an element");
        }
        unsafe {
            f(transmute(self.obj))
        }
    }

    // FIXME: This should be doing dynamic borrow checking for safety.
    fn as_mut_element<R>(self, f: &fn(&mut Element) -> R) -> R {
        if !self.is_element() {
            fail!(~"node is not an element");
        }
        unsafe {
            f(transmute(self.obj))
        }
    }

    fn is_image_element(self) -> bool {
        self.type_id() == ElementNodeTypeId(HTMLImageElementTypeId)
    }

    fn with_imm_image_element<R>(self, f: &fn(&HTMLImageElement) -> R) -> R {
        if !self.is_image_element() {
            fail!(~"node is not an image element");
        }
        unsafe {
            f(transmute(self.obj))
        }
    }

    fn with_mut_image_element<R>(self, f: &fn(&mut HTMLImageElement) -> R) -> R {
        if !self.is_image_element() {
            fail!(~"node is not an image element");
        }
        unsafe {
            f(transmute(self.obj))
        }
    }

    fn is_style_element(self) -> bool {
        self.type_id() == ElementNodeTypeId(HTMLStyleElementTypeId)
    }
}

impl DebugMethods for AbstractNode {
    // Dumps the subtree rooted at this node, for debugging.
    pure fn dump(&self) {
        self.dump_indent(0);
    }

    // Dumps the node tree, for debugging, with indentation.
    pure fn dump_indent(&self, indent: uint) {
        let mut s = ~"";
        for uint::range(0u, indent) |_i| {
            s += ~"    ";
        }

        s += self.debug_str();
        debug!("%s", s);

        // FIXME: this should have a pure version?
        unsafe {
            for self.each_child() |kid| {
                kid.dump_indent(indent + 1u)
            }
        }
    }

    pure fn debug_str(&self) -> ~str {
        // Unsafe due to the call to type_id().
        unsafe {
            fmt!("%?", self.type_id())
        }
    }
}

impl Node {
    static pub unsafe fn as_abstract_node<N>(node: ~N) -> AbstractNode {
        // This surrenders memory management of the node!
        AbstractNode {
            obj: transmute(node)
        }
    }

    static pub fn new(type_id: NodeTypeId) -> Node {
        Node {
            type_id: type_id,

            parent_node: None,
            first_child: None,
            last_child: None,
            next_sibling: None,
            prev_sibling: None,

            layout_data: None,
        }
    }
}

pub fn define_bindings(compartment: @mut Compartment, doc: @Document, win: @Window) {
    bindings::window::init(compartment, win);
    bindings::document::init(compartment, doc);
    bindings::node::init(compartment);
    bindings::element::init(compartment);
}
<commit_msg>Fix crashes from incorrect transmutation and traversal routines.<commit_after>//
// The core DOM types. Defines the basic DOM hierarchy as well as all the HTML elements.
//

use dom::bindings;
use dom::document::Document;
use dom::element::{Element, ElementTypeId, HTMLImageElement, HTMLImageElementTypeId};
use dom::element::{HTMLStyleElementTypeId};
use dom::window::Window;
use layout::debug::DebugMethods;
use layout::flow::FlowContext;
use newcss::complete::CompleteSelectResults;

use core::cast::transmute;
use core::ptr::null;
use geom::size::Size2D;
use js::crust::*;
use js::rust::Compartment;
use std::arc::ARC;

//
// The basic Node structure
//

/// This is what a Node looks like if you do not know what kind of node it is. To unpack it, use
/// downcast().
///
/// FIXME: This should be replaced with a trait once they can inherit from structs.
pub struct AbstractNode {
    priv obj: *mut Node
}

impl Eq for AbstractNode {
    pure fn eq(&self, other: &AbstractNode) -> bool { self.obj == other.obj }
    pure fn ne(&self, other: &AbstractNode) -> bool { self.obj != other.obj }
}

pub struct Node {
    type_id: NodeTypeId,

    parent_node: Option<AbstractNode>,
    first_child: Option<AbstractNode>,
    last_child: Option<AbstractNode>,
    next_sibling: Option<AbstractNode>,
    prev_sibling: Option<AbstractNode>,

    // You must not touch this if you are not layout.
    priv layout_data: Option<@mut LayoutData>
}

#[deriving_eq]
pub enum NodeTypeId {
    DoctypeNodeTypeId,
    CommentNodeTypeId,
    ElementNodeTypeId(ElementTypeId),
    TextNodeTypeId,
}

//
// Auxiliary layout data
//

pub struct LayoutData {
    style: Option<CompleteSelectResults>,
    flow: Option<@FlowContext>,
}

impl LayoutData {
    static pub fn new() -> LayoutData {
        LayoutData {
            style: None,
            flow: None,
        }
    }
}

//
// Basic node types
//

pub struct Doctype {
    parent: Node,
    name: ~str,
    public_id: Option<~str>,
    system_id: Option<~str>,
    force_quirks: bool
}

impl Doctype {
    static pub fn new(name: ~str,
                      public_id: Option<~str>,
                      system_id: Option<~str>,
                      force_quirks: bool)
                   -> Doctype {
        Doctype {
            parent: Node::new(DoctypeNodeTypeId),
            name: name,
            public_id: public_id,
            system_id: system_id,
            force_quirks: force_quirks,
        }
    }
}

pub struct Comment {
    parent: Node,
    text: ~str,
}

impl Comment {
    static pub fn new(text: ~str) -> Comment {
        Comment {
            parent: Node::new(CommentNodeTypeId),
            text: text
        }
    }
}

pub struct Text {
    parent: Node,
    text: ~str,
}

impl Text {
    static pub fn new(text: ~str) -> Text {
        Text {
            parent: Node::new(CommentNodeTypeId),
            text: text
        }
    }
}

impl AbstractNode {
    //
    // Convenience accessors
    //
    // FIXME: Fold these into util::tree.

    fn type_id(self)         -> NodeTypeId           { self.with_imm_node(|n| n.type_id)      }
    fn parent_node(self)     -> Option<AbstractNode> { self.with_imm_node(|n| n.parent_node)  }
    fn first_child(self)     -> Option<AbstractNode> { self.with_imm_node(|n| n.first_child)  }
    fn last_child(self)      -> Option<AbstractNode> { self.with_imm_node(|n| n.last_child)   }
    fn prev_sibling(self)    -> Option<AbstractNode> { self.with_imm_node(|n| n.prev_sibling) }
    fn next_sibling(self)    -> Option<AbstractNode> { self.with_imm_node(|n| n.next_sibling) }

    // NB: You must not call these if you are not layout. We should do something with scoping to
    // ensure this.
    fn layout_data(self)     -> @mut LayoutData {
        self.with_imm_node(|n| n.layout_data.get())
    }
    fn has_layout_data(self) -> bool {
        self.with_imm_node(|n| n.layout_data.is_some())
    }
    fn set_layout_data(self, data: @mut LayoutData) {
        self.with_mut_node(|n| n.layout_data = Some(data))
    }

    //
    // Tree operations
    //
    // FIXME: Fold this into util::tree.
    //

    fn is_leaf(self) -> bool { self.first_child().is_none() }

    // Invariant: `child` is disconnected from the document.
    fn append_child(self, child: AbstractNode) {
        assert self != child;

        do self.with_mut_node |parent_n| {
            do child.with_mut_node |child_n| {
                assert child_n.parent_node.is_none();
                assert child_n.prev_sibling.is_none();
                assert child_n.next_sibling.is_none();

                child_n.parent_node = Some(self);

                match parent_n.last_child {
                    None => parent_n.first_child = Some(child),
                    Some(last_child) => {
                        do last_child.with_mut_node |last_child_n| {
                            assert last_child_n.next_sibling.is_none();
                            last_child_n.next_sibling = Some(child);
                        }
                    }
                }

                child_n.prev_sibling = parent_n.last_child;
            }
        }
    }

    //
    // Tree traversal
    //
    // FIXME: Fold this into util::tree.
    //

    fn each_child(self, f: &fn(AbstractNode) -> bool) {
        let mut current_opt = self.first_child();
        while !current_opt.is_none() {
            let current = current_opt.get();
            if !f(current) {
                break;
            }
            current_opt = current.next_sibling();
        }
    }

    fn traverse_preorder(self, f: &fn(AbstractNode) -> bool) -> bool {
        if !f(self) {
            return false;
        }
        for self.each_child |kid| {
            if !kid.traverse_preorder(f) {
                return false;
            }
        }
        true
    }

    fn traverse_postorder(self, f: &fn(AbstractNode) -> bool) -> bool {
        for self.each_child |kid| {
            if !kid.traverse_postorder(f) {
                return false;
            }
        }
        f(self)
    }

    //
    // Downcasting borrows
    //

    fn transmute<T, R>(self, f: &fn(&T) -> R) -> R {
        unsafe {
            let box: *bindings::utils::rust_box<T> = transmute(self.obj);
            f(&(*box).payload)
        }
    }

    fn transmute_mut<T, R>(self, f: &fn(&mut T) -> R) -> R {
        unsafe {
            let box: *bindings::utils::rust_box<T> = transmute(self.obj);
            f(cast::transmute(&(*box).payload))
        }
    }

    fn with_imm_node<R>(self, f: &fn(&Node) -> R) -> R {
        self.transmute(f)
    }

    fn with_mut_node<R>(self, f: &fn(&mut Node) -> R) -> R {
        self.transmute_mut(f)
    }

    fn is_text(self) -> bool { self.type_id() == TextNodeTypeId }

    // FIXME: This should be doing dynamic borrow checking for safety.
    fn with_imm_text<R>(self, f: &fn(&Text) -> R) -> R {
        if !self.is_text() {
            fail!(~"node is not text");
        }
        self.transmute(f)
    }

    fn is_element(self) -> bool {
        match self.type_id() {
            ElementNodeTypeId(*) => true,
            _ => false
        }
    }

    // FIXME: This should be doing dynamic borrow checking for safety.
    fn with_imm_element<R>(self, f: &fn(&Element) -> R) -> R {
        if !self.is_element() {
            fail!(~"node is not an element");
        }
        self.transmute(f)
    }

    // FIXME: This should be doing dynamic borrow checking for safety.
    fn as_mut_element<R>(self, f: &fn(&mut Element) -> R) -> R {
        if !self.is_element() {
            fail!(~"node is not an element");
        }
        self.transmute_mut(f)
    }

    fn is_image_element(self) -> bool {
        self.type_id() == ElementNodeTypeId(HTMLImageElementTypeId)
    }

    fn with_imm_image_element<R>(self, f: &fn(&HTMLImageElement) -> R) -> R {
        if !self.is_image_element() {
            fail!(~"node is not an image element");
        }
        self.transmute(f)
    }

    fn with_mut_image_element<R>(self, f: &fn(&mut HTMLImageElement) -> R) -> R {
        if !self.is_image_element() {
            fail!(~"node is not an image element");
        }
        self.transmute_mut(f)
    }

    fn is_style_element(self) -> bool {
        self.type_id() == ElementNodeTypeId(HTMLStyleElementTypeId)
    }
}

impl DebugMethods for AbstractNode {
    // Dumps the subtree rooted at this node, for debugging.
    pure fn dump(&self) {
        self.dump_indent(0);
    }

    // Dumps the node tree, for debugging, with indentation.
    pure fn dump_indent(&self, indent: uint) {
        let mut s = ~"";
        for uint::range(0u, indent) |_i| {
            s += ~"    ";
        }

        s += self.debug_str();
        debug!("%s", s);

        // FIXME: this should have a pure version?
        unsafe {
            for self.each_child() |kid| {
                kid.dump_indent(indent + 1u)
            }
        }
    }

    pure fn debug_str(&self) -> ~str {
        // Unsafe due to the call to type_id().
        unsafe {
            fmt!("%?", self.type_id())
        }
    }
}

impl Node {
    static pub unsafe fn as_abstract_node<N>(node: ~N) -> AbstractNode {
        // This surrenders memory management of the node!
        AbstractNode {
            obj: transmute(node)
        }
    }

    static pub fn new(type_id: NodeTypeId) -> Node {
        Node {
            type_id: type_id,

            parent_node: None,
            first_child: None,
            last_child: None,
            next_sibling: None,
            prev_sibling: None,

            layout_data: None,
        }
    }
}

pub fn define_bindings(compartment: @mut Compartment, doc: @Document, win: @Window) {
    bindings::window::init(compartment, win);
    bindings::document::init(compartment, doc);
    bindings::node::init(compartment);
    bindings::element::init(compartment);
}
<|endoftext|>


<commit_before>//! Lua interpreter setup and configuration reading.

mod config;
mod utils;

use self::config::{get_config, load_config};
pub use self::utils::*;
pub use self::config::log_error;

use clap::ArgMatches;
use glib::MainLoop;
use rlua::{self, AnyUserData, Lua, Table, Value};

use std::{cell::{Cell, RefCell}, io::{self, Read}, fs::File, path::PathBuf};

use common::signal;

/// Path to the Awesome shims.
const SHIMS_PATH: &str = "../../tests/awesome/tests/examples/shims/";
/// Shims to load
const SHIMS: [&str; 12] = [
    "awesome",
    "root",
    "tag",
    "screen",
    "client",
    "mouse",
    "drawin",
    "button",
    "keygrabber",
    "mousegrabber",
    "key"
];

thread_local! {
    // NOTE The debug library does some powerful reflection that can do crazy things,
    // which is why it's unsafe to load.

    /// Global Lua state.
    pub static LUA: RefCell<Lua> = RefCell::new(unsafe { Lua::new_with_debug() });

    /// If set then we have restarted the Lua thread. We need to replace LUA when it's not borrowed.
    pub static NEXT_LUA: Cell<bool> = Cell::new(false);

    /// Main GLib loop
    static MAIN_LOOP: RefCell<MainLoop> = RefCell::new(MainLoop::new(None, false));
}

/// Loads shim code to act like Awesome.
///
/// To be compatible this must eventually be removed.
///
/// Best way to help out: comment out one of these lines, fix what breaks.
fn load_shims(lua: &Lua) {
    let globals = lua.globals();
    let package: Table = globals.get("package").unwrap();
    let mut path = package.get::<_, String>("path").unwrap();
    path.push_str(&format!(";{0}/?.lua;{0}/?/init.lua", SHIMS_PATH));
    package.set("path", path).unwrap();
    let shims_path = PathBuf::from(SHIMS_PATH);
    for shim in SHIMS.iter() {
        let mut path = shims_path.clone();
        path.push(format!("{}.lua", shim));
        let shims_path_str = path.to_str().unwrap();
        let mut file = File::open(path.clone())
            .expect(&format!("Could not open {}", shims_path_str));
        let mut contents = String::new();
        file.read_to_string(&mut contents)
            .expect(&format!("Could not read {}", shims_path_str));
        let obj = lua.exec::<rlua::Value>(contents.as_str(), None)
            .expect(&format!("Could not read {}", shims_path_str));
        globals.set(*shim, obj)
            .expect("Could not set global object");
    }
}

/// Sets up the Lua environment for the user code.
///
/// This environment is also necessary for some Wayland callbacks,
/// so it should be called as soon as possible.
pub fn init_awesome_libraries(lib_paths: &[&str]) {
    info!("Setting up Awesome libraries");
    LUA.with(|lua| {
        register_libraries(&*lua.borrow(), lib_paths)
            .expect("Could not register lua libraries");
    });
}

/// Runs user code from the config through the awesome compatibility layer.
///
/// It then enters the glib/wayland main loop to listen for events.
pub fn run_awesome(matches: ArgMatches) {
    LUA.with(|lua| {
        let mut lua = lua.borrow_mut();
        info!("Loading Awesome configuration...");
        let lib_paths = matches.values_of("lua lib search")
            .unwrap_or_default()
            .collect::<Vec<_>>();
        let config = matches.value_of("config");
        load_config(&mut *lua, config, lib_paths.as_slice());
        load_shims(&mut *lua);
    });
    enter_glib_loop();
}

fn emit_refresh(lua: &Lua) {
    if let Err(err) = signal::global_emit_signal(lua, ("refresh".to_owned(), Value::Nil)) {
        error!("Internal error while emitting 'refresh' signal: {}", err);
    }
}

/// Main loop of the Lua thread:
///
/// * Initialise the Lua state
/// * Run a GMainLoop
pub fn enter_glib_loop() {
    MAIN_LOOP.with(|main_loop| main_loop.borrow().run());
}

pub fn terminate() {
    MAIN_LOOP.with(|main_loop| main_loop.borrow().quit())
}

/// Checks that the first configuration file used is syntactically correct.
///
/// If the inner io::Result is not `Ok(())` we could not read any config files.
pub fn syntax_check(cmdline_path: Option<&str>) -> Result<(), io::Result<rlua::Error>> {
    let (path, mut file) = get_config(cmdline_path).map_err(Err)?;
    let mut file_contents = String::new();
    file.read_to_string(&mut file_contents).map_err(Err)?;
    LUA.with(|lua| {
        let lua = lua.borrow();
        let res = lua.load(file_contents.as_str(), path.to_str())
            .map(|_| ())
            .map_err(|err| Ok(err));
        res
    })
}

/// Register all the Rust functions for the lua libraries
pub fn register_libraries(lua: &Lua, lib_paths: &[&str]) -> rlua::Result<()> {
    trace!("Setting up Lua libraries");
    // TODO Is this awesome init code necessary?
    let init_code = include_str!("../../../lib/lua/init.lua");
    lua.exec::<()>(init_code, Some("init.lua"))?;
    let globals = lua.globals();
    globals.set("type", lua.create_function(type_override)?)?;
    init_libs(&lua, lib_paths).expect("Could not initialize awesome compatibility modules");
    Ok(())
}

fn init_libs(lua: &Lua, lib_paths: &[&str]) -> rlua::Result<()> {
    use ::{*, objects::*};
    setup_awesome_path(lua, lib_paths)?;
    setup_global_signals(lua)?;
    setup_xcb_connection(lua)?;
    button::init(lua)?;
    awesome::init(lua)?;
    key::init(lua)?;
    client::init(lua)?;
    screen::init(lua)?;
    keygrabber::init(lua)?;
    root::init(lua)?;
    mouse::init(lua)?;
    tag::init(lua)?;
    drawin::init(lua)?;
    drawable::init(lua)?;
    mousegrabber::init(lua)?;
    dbus::lua_init(lua)?;
    Ok(())
}

/// This function behaves just like Lua's built-in type() function, but also
/// recognises classes and returns special names for them.
fn type_override(_lua: &Lua, arg: Value) -> rlua::Result<String> {
    // Lua's type() returns the result of lua_typename(), but rlua does not make
    // that available to us, so write our own.
    Ok(match arg {
           Value::Error(e) => return Err(e),
           Value::Nil => "nil",
           Value::Boolean(_) => "boolean",
           Value::LightUserData(_) => "userdata",
           Value::Integer(_) => "number",
           Value::Number(_) => "number",
           Value::String(_) => "string",
           Value::Function(_) => "function",
           Value::Thread(_) => "thread",
           Value::Table(_) => "table",
           Value::UserData(o) => {
               // Handle our own objects specially: Get the object's class from its user
               // value's metatable's __class entry. Then get the class name
               // from the class's user value's metatable's name entry.
               return o.get_user_value::<Table>()
                       .ok()
                       .and_then(|table| table.get_metatable())
                       .and_then(|meta| meta.raw_get::<_, AnyUserData>("__class").ok())
                       .and_then(|class| class.get_user_value::<Table>().ok())
                       .map(|table| table.raw_get("name"))
                       .unwrap_or_else(|| Ok("userdata".into()))
           }
       }.into())
}
<commit_msg>Fixed list length<commit_after>//! Lua interpreter setup and configuration reading.

mod config;
mod utils;

use self::config::{get_config, load_config};
pub use self::utils::*;
pub use self::config::log_error;

use clap::ArgMatches;
use glib::MainLoop;
use rlua::{self, AnyUserData, Lua, Table, Value};

use std::{cell::{Cell, RefCell}, io::{self, Read}, fs::File, path::PathBuf};

use common::signal;

/// Path to the Awesome shims.
const SHIMS_PATH: &str = "../../tests/awesome/tests/examples/shims/";
/// Shims to load
const SHIMS: [&str; 11] = [
    "awesome",
    "root",
    "tag",
    "screen",
    "client",
    "mouse",
    "drawin",
    "button",
    "keygrabber",
    "mousegrabber",
    "key"
];

thread_local! {
    // NOTE The debug library does some powerful reflection that can do crazy things,
    // which is why it's unsafe to load.

    /// Global Lua state.
    pub static LUA: RefCell<Lua> = RefCell::new(unsafe { Lua::new_with_debug() });

    /// If set then we have restarted the Lua thread. We need to replace LUA when it's not borrowed.
    pub static NEXT_LUA: Cell<bool> = Cell::new(false);

    /// Main GLib loop
    static MAIN_LOOP: RefCell<MainLoop> = RefCell::new(MainLoop::new(None, false));
}

/// Loads shim code to act like Awesome.
///
/// To be compatible this must eventually be removed.
///
/// Best way to help out: comment out one of these lines, fix what breaks.
fn load_shims(lua: &Lua) {
    let globals = lua.globals();
    let package: Table = globals.get("package").unwrap();
    let mut path = package.get::<_, String>("path").unwrap();
    path.push_str(&format!(";{0}/?.lua;{0}/?/init.lua", SHIMS_PATH));
    package.set("path", path).unwrap();
    let shims_path = PathBuf::from(SHIMS_PATH);
    for shim in SHIMS.iter() {
        let mut path = shims_path.clone();
        path.push(format!("{}.lua", shim));
        let shims_path_str = path.to_str().unwrap();
        let mut file = File::open(path.clone())
            .expect(&format!("Could not open {}", shims_path_str));
        let mut contents = String::new();
        file.read_to_string(&mut contents)
            .expect(&format!("Could not read {}", shims_path_str));
        let obj = lua.exec::<rlua::Value>(contents.as_str(), None)
            .expect(&format!("Could not read {}", shims_path_str));
        globals.set(*shim, obj)
            .expect("Could not set global object");
    }
}

/// Sets up the Lua environment for the user code.
///
/// This environment is also necessary for some Wayland callbacks,
/// so it should be called as soon as possible.
pub fn init_awesome_libraries(lib_paths: &[&str]) {
    info!("Setting up Awesome libraries");
    LUA.with(|lua| {
        register_libraries(&*lua.borrow(), lib_paths)
            .expect("Could not register lua libraries");
    });
}

/// Runs user code from the config through the awesome compatibility layer.
///
/// It then enters the glib/wayland main loop to listen for events.
pub fn run_awesome(matches: ArgMatches) {
    LUA.with(|lua| {
        let mut lua = lua.borrow_mut();
        info!("Loading Awesome configuration...");
        let lib_paths = matches.values_of("lua lib search")
            .unwrap_or_default()
            .collect::<Vec<_>>();
        let config = matches.value_of("config");
        load_config(&mut *lua, config, lib_paths.as_slice());
        load_shims(&mut *lua);
    });
    enter_glib_loop();
}

fn emit_refresh(lua: &Lua) {
    if let Err(err) = signal::global_emit_signal(lua, ("refresh".to_owned(), Value::Nil)) {
        error!("Internal error while emitting 'refresh' signal: {}", err);
    }
}

/// Main loop of the Lua thread:
///
/// * Initialise the Lua state
/// * Run a GMainLoop
pub fn enter_glib_loop() {
    MAIN_LOOP.with(|main_loop| main_loop.borrow().run());
}

pub fn terminate() {
    MAIN_LOOP.with(|main_loop| main_loop.borrow().quit())
}

/// Checks that the first configuration file used is syntactically correct.
///
/// If the inner io::Result is not `Ok(())` we could not read any config files.
pub fn syntax_check(cmdline_path: Option<&str>) -> Result<(), io::Result<rlua::Error>> {
    let (path, mut file) = get_config(cmdline_path).map_err(Err)?;
    let mut file_contents = String::new();
    file.read_to_string(&mut file_contents).map_err(Err)?;
    LUA.with(|lua| {
        let lua = lua.borrow();
        let res = lua.load(file_contents.as_str(), path.to_str())
            .map(|_| ())
            .map_err(|err| Ok(err));
        res
    })
}

/// Register all the Rust functions for the lua libraries
pub fn register_libraries(lua: &Lua, lib_paths: &[&str]) -> rlua::Result<()> {
    trace!("Setting up Lua libraries");
    // TODO Is this awesome init code necessary?
    let init_code = include_str!("../../../lib/lua/init.lua");
    lua.exec::<()>(init_code, Some("init.lua"))?;
    let globals = lua.globals();
    globals.set("type", lua.create_function(type_override)?)?;
    init_libs(&lua, lib_paths).expect("Could not initialize awesome compatibility modules");
    Ok(())
}

fn init_libs(lua: &Lua, lib_paths: &[&str]) -> rlua::Result<()> {
    use ::{*, objects::*};
    setup_awesome_path(lua, lib_paths)?;
    setup_global_signals(lua)?;
    setup_xcb_connection(lua)?;
    button::init(lua)?;
    awesome::init(lua)?;
    key::init(lua)?;
    client::init(lua)?;
    screen::init(lua)?;
    keygrabber::init(lua)?;
    root::init(lua)?;
    mouse::init(lua)?;
    tag::init(lua)?;
    drawin::init(lua)?;
    drawable::init(lua)?;
    mousegrabber::init(lua)?;
    dbus::lua_init(lua)?;
    Ok(())
}

/// This function behaves just like Lua's built-in type() function, but also
/// recognises classes and returns special names for them.
fn type_override(_lua: &Lua, arg: Value) -> rlua::Result<String> {
    // Lua's type() returns the result of lua_typename(), but rlua does not make
    // that available to us, so write our own.
    Ok(match arg {
           Value::Error(e) => return Err(e),
           Value::Nil => "nil",
           Value::Boolean(_) => "boolean",
           Value::LightUserData(_) => "userdata",
           Value::Integer(_) => "number",
           Value::Number(_) => "number",
           Value::String(_) => "string",
           Value::Function(_) => "function",
           Value::Thread(_) => "thread",
           Value::Table(_) => "table",
           Value::UserData(o) => {
               // Handle our own objects specially: Get the object's class from its user
               // value's metatable's __class entry. Then get the class name
               // from the class's user value's metatable's name entry.
               return o.get_user_value::<Table>()
                       .ok()
                       .and_then(|table| table.get_metatable())
                       .and_then(|meta| meta.raw_get::<_, AnyUserData>("__class").ok())
                       .and_then(|class| class.get_user_value::<Table>().ok())
                       .map(|table| table.raw_get("name"))
                       .unwrap_or_else(|| Ok("userdata".into()))
           }
       }.into())
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

// Servo, the mighty web browser engine from the future.
//
// This is a very simple library that wires all of Servo's components
// together as type `Browser`, along with a generic client
// implementing the `WindowMethods` trait, to create a working web
// browser.
//
// The `Browser` type is responsible for configuring a
// `Constellation`, which does the heavy lifting of coordinating all
// of Servo's internal subsystems, including the `ScriptTask` and the
// `LayoutTask`, as well maintains the navigation context.
//
// The `Browser` is fed events from a generic type that implements the
// `WindowMethods` trait.

extern crate gaol;
extern crate libc;
#[macro_use]
extern crate util as _util;

mod export {
    extern crate canvas;
    extern crate canvas_traits;
    extern crate compositing;
    extern crate devtools;
    extern crate devtools_traits;
    extern crate euclid;
    extern crate gfx;
    extern crate gleam;
    extern crate ipc_channel;
    extern crate layers;
    extern crate layout;
    extern crate msg;
    extern crate net;
    extern crate net_traits;
    extern crate profile;
    extern crate profile_traits;
    extern crate script;
    extern crate script_traits;
    extern crate style;
    extern crate url;
}

#[cfg(feature = "webdriver")]
extern crate webdriver_server;

#[cfg(feature = "webdriver")]
fn webdriver(port: u16, constellation: Sender<ConstellationMsg>) {
    webdriver_server::start_server(port, constellation);
}

#[cfg(not(feature = "webdriver"))]
fn webdriver(_port: u16, _constellation: Sender<ConstellationMsg>) { }

use compositing::CompositorEventListener;
use compositing::compositor_task::InitialCompositorState;
use compositing::constellation::InitialConstellationState;
use compositing::pipeline::UnprivilegedPipelineContent;
use compositing::sandboxing;
use compositing::windowing::WindowEvent;
use compositing::windowing::WindowMethods;
use compositing::{CompositorProxy, CompositorTask, Constellation};
use gaol::sandbox::{ChildSandbox, ChildSandboxMethods};
use gfx::font_cache_task::FontCacheTask;
use ipc_channel::ipc::{self, IpcSender};
use msg::constellation_msg::CompositorMsg as ConstellationMsg;
use net::image_cache_task::new_image_cache_task;
use net::resource_task::new_resource_task;
use net::storage_task::StorageTaskFactory;
use net_traits::storage_task::StorageTask;
use profile::mem as profile_mem;
use profile::time as profile_time;
use profile_traits::mem;
use profile_traits::time;
use std::borrow::Borrow;
use std::rc::Rc;
use std::sync::mpsc::Sender;
use util::opts;

pub use _util as util;
pub use export::canvas;
pub use export::canvas_traits;
pub use export::compositing;
pub use export::devtools;
pub use export::devtools_traits;
pub use export::euclid;
pub use export::gfx;
pub use export::gleam::gl;
pub use export::ipc_channel;
pub use export::layers;
pub use export::layout;
pub use export::msg;
pub use export::net;
pub use export::net_traits;
pub use export::profile;
pub use export::profile_traits;
pub use export::script;
pub use export::script_traits;
pub use export::style;
pub use export::url;

pub struct Browser {
    compositor: Box<CompositorEventListener + 'static>,
}

/// The in-process interface to Servo.
///
/// It does everything necessary to render the web, primarily
/// orchestrating the interaction between JavaScript, CSS layout,
/// rendering, and the client window.
///
/// Clients create a `Browser` for a given reference-counted type
/// implementing `WindowMethods`, which is the bridge to whatever
/// application Servo is embedded in. Clients then create an event
/// loop to pump messages between the embedding application and
/// various browser components.
impl Browser {
    pub fn new<Window>(window: Option<Rc<Window>>) -> Browser
                       where Window: WindowMethods + 'static {
        // Global configuration options, parsed from the command line.
        let opts = opts::get();

        script::init();

        // Get both endpoints of a special channel for communication between
        // the client window and the compositor. This channel is unique because
        // messages to client may need to pump a platform-specific event loop
        // to deliver the message.
        let (compositor_proxy, compositor_receiver) =
            WindowMethods::create_compositor_channel(&window);
        let supports_clipboard = match window {
            Some(ref win_rc) => {
                let win: &Window = win_rc.borrow();
                win.supports_clipboard()
            }
            None => false
        };
        let time_profiler_chan = profile_time::Profiler::create(opts.time_profiler_period);
        let mem_profiler_chan = profile_mem::Profiler::create(opts.mem_profiler_period);
        let devtools_chan = opts.devtools_port.map(|port| {
            devtools::start_server(port)
        });

        // Create the constellation, which maintains the engine
        // pipelines, including the script and layout threads, as well
        // as the navigation context.
        let constellation_chan = create_constellation(opts.clone(),
                                                      compositor_proxy.clone_compositor_proxy(),
                                                      time_profiler_chan.clone(),
                                                      mem_profiler_chan.clone(),
                                                      devtools_chan,
                                                      supports_clipboard);

        if cfg!(feature = "webdriver") {
            if let Some(port) = opts.webdriver_port {
                webdriver(port, constellation_chan.clone());
            }
        }

        // The compositor coordinates with the client window to create the final
        // rendered page and display it somewhere.
        let compositor = CompositorTask::create(window, InitialCompositorState {
            sender: compositor_proxy,
            receiver: compositor_receiver,
            constellation_chan: constellation_chan,
            time_profiler_chan: time_profiler_chan,
            mem_profiler_chan: mem_profiler_chan,
        });

        Browser {
            compositor: compositor,
        }
    }

    pub fn handle_events(&mut self, events: Vec<WindowEvent>) -> bool {
        self.compositor.handle_events(events)
    }

    pub fn repaint_synchronously(&mut self) {
        self.compositor.repaint_synchronously()
    }

    pub fn pinch_zoom_level(&self) -> f32 {
        self.compositor.pinch_zoom_level()
    }

    pub fn request_title_for_main_frame(&self) {
        self.compositor.title_for_main_frame()
    }
}

fn create_constellation(opts: opts::Opts,
                        compositor_proxy: Box<CompositorProxy + Send>,
                        time_profiler_chan: time::ProfilerChan,
                        mem_profiler_chan: mem::ProfilerChan,
                        devtools_chan: Option<Sender<devtools_traits::DevtoolsControlMsg>>,
                        supports_clipboard: bool) -> Sender<ConstellationMsg> {
    let resource_task = new_resource_task(opts.user_agent.clone(), devtools_chan.clone());

    let image_cache_task = new_image_cache_task(resource_task.clone());
    let font_cache_task = FontCacheTask::new(resource_task.clone());
    let storage_task: StorageTask = StorageTaskFactory::new();

    let initial_state = InitialConstellationState {
        compositor_proxy: compositor_proxy,
        devtools_chan: devtools_chan,
        image_cache_task: image_cache_task,
        font_cache_task: font_cache_task,
        resource_task: resource_task,
        storage_task: storage_task,
        time_profiler_chan: time_profiler_chan,
        mem_profiler_chan: mem_profiler_chan,
        supports_clipboard: supports_clipboard,
    };
    let constellation_chan =
        Constellation::<layout::layout_task::LayoutTask,
                        script::script_task::ScriptTask>::start(initial_state);

    // Send the URL command to the constellation.
    match opts.url {
        Some(url) => {
            constellation_chan.send(ConstellationMsg::InitLoadUrl(url)).unwrap();
        },
        None => ()
    };

    constellation_chan
}

/// Content process entry point.
pub fn run_content_process(token: String) {
    let (unprivileged_content_sender, unprivileged_content_receiver) =
        ipc::channel::<UnprivilegedPipelineContent>().unwrap();
    let connection_bootstrap: IpcSender<IpcSender<UnprivilegedPipelineContent>> =
        IpcSender::connect(token).unwrap();
    connection_bootstrap.send(unprivileged_content_sender).unwrap();

    let unprivileged_content = unprivileged_content_receiver.recv().unwrap();
    opts::set_defaults(unprivileged_content.opts());

    // Enter the sandbox if necessary.
    if opts::get().sandbox {
        ChildSandbox::new(sandboxing::content_process_sandbox_profile()).activate().unwrap();
    }

    script::init();

    unprivileged_content.start_all::<layout::layout_task::LayoutTask,
                                     script::script_task::ScriptTask>(true);
}

<commit_msg>1. converted the first comments in servo/lib.rs into doc comments. 2. moved doc comment of impl Browser to pub struct Browser.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/// Servo, the mighty web browser engine from the future.
///
/// This is a very simple library that wires all of Servo's components
/// together as type `Browser`, along with a generic client
/// implementing the `WindowMethods` trait, to create a working web
/// browser.
///
/// The `Browser` type is responsible for configuring a
/// `Constellation`, which does the heavy lifting of coordinating all
/// of Servo's internal subsystems, including the `ScriptTask` and the
/// `LayoutTask`, as well maintains the navigation context.
///
/// The `Browser` is fed events from a generic type that implements the
/// `WindowMethods` trait.

extern crate gaol;
extern crate libc;
#[macro_use]
extern crate util as _util;

mod export {
    extern crate canvas;
    extern crate canvas_traits;
    extern crate compositing;
    extern crate devtools;
    extern crate devtools_traits;
    extern crate euclid;
    extern crate gfx;
    extern crate gleam;
    extern crate ipc_channel;
    extern crate layers;
    extern crate layout;
    extern crate msg;
    extern crate net;
    extern crate net_traits;
    extern crate profile;
    extern crate profile_traits;
    extern crate script;
    extern crate script_traits;
    extern crate style;
    extern crate url;
}

#[cfg(feature = "webdriver")]
extern crate webdriver_server;

#[cfg(feature = "webdriver")]
fn webdriver(port: u16, constellation: Sender<ConstellationMsg>) {
    webdriver_server::start_server(port, constellation);
}

#[cfg(not(feature = "webdriver"))]
fn webdriver(_port: u16, _constellation: Sender<ConstellationMsg>) { }

use compositing::CompositorEventListener;
use compositing::compositor_task::InitialCompositorState;
use compositing::constellation::InitialConstellationState;
use compositing::pipeline::UnprivilegedPipelineContent;
use compositing::sandboxing;
use compositing::windowing::WindowEvent;
use compositing::windowing::WindowMethods;
use compositing::{CompositorProxy, CompositorTask, Constellation};
use gaol::sandbox::{ChildSandbox, ChildSandboxMethods};
use gfx::font_cache_task::FontCacheTask;
use ipc_channel::ipc::{self, IpcSender};
use msg::constellation_msg::CompositorMsg as ConstellationMsg;
use net::image_cache_task::new_image_cache_task;
use net::resource_task::new_resource_task;
use net::storage_task::StorageTaskFactory;
use net_traits::storage_task::StorageTask;
use profile::mem as profile_mem;
use profile::time as profile_time;
use profile_traits::mem;
use profile_traits::time;
use std::borrow::Borrow;
use std::rc::Rc;
use std::sync::mpsc::Sender;
use util::opts;

pub use _util as util;
pub use export::canvas;
pub use export::canvas_traits;
pub use export::compositing;
pub use export::devtools;
pub use export::devtools_traits;
pub use export::euclid;
pub use export::gfx;
pub use export::gleam::gl;
pub use export::ipc_channel;
pub use export::layers;
pub use export::layout;
pub use export::msg;
pub use export::net;
pub use export::net_traits;
pub use export::profile;
pub use export::profile_traits;
pub use export::script;
pub use export::script_traits;
pub use export::style;
pub use export::url;

/// The in-process interface to Servo.
///
/// It does everything necessary to render the web, primarily
/// orchestrating the interaction between JavaScript, CSS layout,
/// rendering, and the client window.
///
/// Clients create a `Browser` for a given reference-counted type
/// implementing `WindowMethods`, which is the bridge to whatever
/// application Servo is embedded in. Clients then create an event
/// loop to pump messages between the embedding application and
/// various browser components.

pub struct Browser {
    compositor: Box<CompositorEventListener + 'static>,
}

impl Browser {
    pub fn new<Window>(window: Option<Rc<Window>>) -> Browser
                       where Window: WindowMethods + 'static {
        // Global configuration options, parsed from the command line.
        let opts = opts::get();

        script::init();

        // Get both endpoints of a special channel for communication between
        // the client window and the compositor. This channel is unique because
        // messages to client may need to pump a platform-specific event loop
        // to deliver the message.
        let (compositor_proxy, compositor_receiver) =
            WindowMethods::create_compositor_channel(&window);
        let supports_clipboard = match window {
            Some(ref win_rc) => {
                let win: &Window = win_rc.borrow();
                win.supports_clipboard()
            }
            None => false
        };
        let time_profiler_chan = profile_time::Profiler::create(opts.time_profiler_period);
        let mem_profiler_chan = profile_mem::Profiler::create(opts.mem_profiler_period);
        let devtools_chan = opts.devtools_port.map(|port| {
            devtools::start_server(port)
        });

        // Create the constellation, which maintains the engine
        // pipelines, including the script and layout threads, as well
        // as the navigation context.
        let constellation_chan = create_constellation(opts.clone(),
                                                      compositor_proxy.clone_compositor_proxy(),
                                                      time_profiler_chan.clone(),
                                                      mem_profiler_chan.clone(),
                                                      devtools_chan,
                                                      supports_clipboard);

        if cfg!(feature = "webdriver") {
            if let Some(port) = opts.webdriver_port {
                webdriver(port, constellation_chan.clone());
            }
        }

        // The compositor coordinates with the client window to create the final
        // rendered page and display it somewhere.
        let compositor = CompositorTask::create(window, InitialCompositorState {
            sender: compositor_proxy,
            receiver: compositor_receiver,
            constellation_chan: constellation_chan,
            time_profiler_chan: time_profiler_chan,
            mem_profiler_chan: mem_profiler_chan,
        });

        Browser {
            compositor: compositor,
        }
    }

    pub fn handle_events(&mut self, events: Vec<WindowEvent>) -> bool {
        self.compositor.handle_events(events)
    }

    pub fn repaint_synchronously(&mut self) {
        self.compositor.repaint_synchronously()
    }

    pub fn pinch_zoom_level(&self) -> f32 {
        self.compositor.pinch_zoom_level()
    }

    pub fn request_title_for_main_frame(&self) {
        self.compositor.title_for_main_frame()
    }
}

fn create_constellation(opts: opts::Opts,
                        compositor_proxy: Box<CompositorProxy + Send>,
                        time_profiler_chan: time::ProfilerChan,
                        mem_profiler_chan: mem::ProfilerChan,
                        devtools_chan: Option<Sender<devtools_traits::DevtoolsControlMsg>>,
                        supports_clipboard: bool) -> Sender<ConstellationMsg> {
    let resource_task = new_resource_task(opts.user_agent.clone(), devtools_chan.clone());

    let image_cache_task = new_image_cache_task(resource_task.clone());
    let font_cache_task = FontCacheTask::new(resource_task.clone());
    let storage_task: StorageTask = StorageTaskFactory::new();

    let initial_state = InitialConstellationState {
        compositor_proxy: compositor_proxy,
        devtools_chan: devtools_chan,
        image_cache_task: image_cache_task,
        font_cache_task: font_cache_task,
        resource_task: resource_task,
        storage_task: storage_task,
        time_profiler_chan: time_profiler_chan,
        mem_profiler_chan: mem_profiler_chan,
        supports_clipboard: supports_clipboard,
    };
    let constellation_chan =
        Constellation::<layout::layout_task::LayoutTask,
                        script::script_task::ScriptTask>::start(initial_state);

    // Send the URL command to the constellation.
    match opts.url {
        Some(url) => {
            constellation_chan.send(ConstellationMsg::InitLoadUrl(url)).unwrap();
        },
        None => ()
    };

    constellation_chan
}

/// Content process entry point.
pub fn run_content_process(token: String) {
    let (unprivileged_content_sender, unprivileged_content_receiver) =
        ipc::channel::<UnprivilegedPipelineContent>().unwrap();
    let connection_bootstrap: IpcSender<IpcSender<UnprivilegedPipelineContent>> =
        IpcSender::connect(token).unwrap();
    connection_bootstrap.send(unprivileged_content_sender).unwrap();

    let unprivileged_content = unprivileged_content_receiver.recv().unwrap();
    opts::set_defaults(unprivileged_content.opts());

    // Enter the sandbox if necessary.
    if opts::get().sandbox {
        ChildSandbox::new(sandboxing::content_process_sandbox_profile()).activate().unwrap();
    }

    script::init();

    unprivileged_content.start_all::<layout::layout_task::LayoutTask,
                                     script::script_task::ScriptTask>(true);
}

<|endoftext|>


<commit_before>// crypto_auth_hmacsha512.h

pub const crypto_auth_hmacsha512_BYTES: usize = 64;
pub const crypto_auth_hmacsha512_KEYBYTES: usize = 32;

extern {
    pub fn crypto_auth_hmacsha512(
        a: *mut [u8; crypto_auth_hmacsha512_BYTES],
        m: *const u8,
        mlen: c_ulonglong,
        k: *const [u8; crypto_auth_hmacsha512_KEYBYTES]) -> c_int;
    pub fn crypto_auth_hmacsha512_verify(
        a: *const [u8; crypto_auth_hmacsha512_BYTES],
        m: *const u8,
        mlen: c_ulonglong,
        k: *const [u8; crypto_auth_hmacsha512_KEYBYTES]) -> c_int;
    pub fn crypto_auth_hmacsha512_bytes() -> size_t;
    pub fn crypto_auth_hmacsha512_keybytes() -> size_t;
}

#[test]
fn test_crypto_auth_hmacsha512_bytes() {
    assert!(unsafe { crypto_auth_hmacsha512_bytes() as usize } ==
            crypto_auth_hmacsha512_BYTES)
}
#[test]
fn test_crypto_auth_hmacsha512_keybytes() {
    assert!(unsafe { crypto_auth_hmacsha512_keybytes() as usize } ==
            crypto_auth_hmacsha512_KEYBYTES)
}
<commit_msg>libsodium-sys: definitions from crypto_auth_hmacsha512.h complete<commit_after>// crypto_auth_hmacsha512.h

#[repr(C)]
#[derive(Copy)]
pub struct crypto_auth_hmacsha512_state {
    ictx: crypto_hash_sha512_state,
    octx: crypto_hash_sha512_state,
}

pub const crypto_auth_hmacsha512_BYTES: usize = 64;
pub const crypto_auth_hmacsha512_KEYBYTES: usize = 32;

extern {
    pub fn crypto_auth_hmacsha512_bytes() -> size_t;
    pub fn crypto_auth_hmacsha512_keybytes() -> size_t;
    pub fn crypto_auth_hmacsha512(
        a: *mut [u8; crypto_auth_hmacsha512_BYTES],
        m: *const u8,
        mlen: c_ulonglong,
        k: *const [u8; crypto_auth_hmacsha512_KEYBYTES]) -> c_int;
    pub fn crypto_auth_hmacsha512_verify(
        a: *const [u8; crypto_auth_hmacsha512_BYTES],
        m: *const u8,
        mlen: c_ulonglong,
        k: *const [u8; crypto_auth_hmacsha512_KEYBYTES]) -> c_int;
    pub fn crypto_auth_hmacsha512_init(
        state: *mut crypto_auth_hmacsha512_state,
        key: *const u8,
        keylen: size_t) -> c_int;
    pub fn crypto_auth_hmacsha512_update(
        state: *mut crypto_auth_hmacsha512_state,
        m: *const u8,
        mlen: c_ulonglong) -> c_int;
    pub fn crypto_auth_hmacsha512_final(
        state: *mut crypto_auth_hmacsha512_state,
        a: *mut [u8; crypto_auth_hmacsha512_BYTES]) -> c_int;
}

#[test]
fn test_crypto_auth_hmacsha512_bytes() {
    assert!(unsafe { crypto_auth_hmacsha512_bytes() as usize } ==
            crypto_auth_hmacsha512_BYTES)
}
#[test]
fn test_crypto_auth_hmacsha512_keybytes() {
    assert!(unsafe { crypto_auth_hmacsha512_keybytes() as usize } ==
            crypto_auth_hmacsha512_KEYBYTES)
}
<|endoftext|>


<commit_before>//! Support Vector Classifier using the `libsvm` library.
//!
//! Both dense and sparse models are supported.

use prelude::*;

use super::ffi;
pub use super::ffi::KernelType;

use utils::{check_data_dimensionality, check_matched_dimensions};

#[derive(Clone)]
#[derive(RustcEncodable, RustcDecodable)]
/// Hyperparameters for the SVC model.
pub struct Hyperparameters {
    dim: usize,
    num_classes: usize,
    svm_parameter: ffi::SvmParameter,
}

impl Hyperparameters {
    pub fn new(dim: usize, kernel: KernelType, num_classes: usize) -> Hyperparameters {
        Hyperparameters {
            dim: dim,
            num_classes: num_classes,
            svm_parameter: ffi::SvmParameter::new(ffi::SvmType::C_SVC, kernel, num_classes, dim),
        }
    }

    /// Set the regularization parameter `C`; smaller values
    /// mean more regularization.
    /// Default is `1.0`.
    pub fn C(&mut self, C: f64) -> &mut Hyperparameters {
        self.svm_parameter.C = C;
        self
    }

    /// Set the degree of the polynomial kernel. No effect on other
    /// kernels. Default: 3.
    pub fn degree(&mut self, degree: i32) -> &mut Hyperparameters {
        self.svm_parameter.degree = degree;
        self
    }

    /// Set the gamma parameter of the RBF kernel.
    /// Default is `1 / self.dim`.
    pub fn gamma(&mut self, gamma: f64) -> &mut Hyperparameters {
        self.svm_parameter.gamma = gamma;
        self
    }

    /// Set the coef0 parameter for the sigmoid kernel.
    /// Default is `0.0`.
    pub fn coef0(&mut self, coef0: f64) -> &mut Hyperparameters {
        self.svm_parameter.coef0 = coef0;
        self
    }

    /// Set the `libsvm` cache size, in megabytes.
    /// Default is `100.0`.
    pub fn cache_size(&mut self, cache_size: f64) -> &mut Hyperparameters {
        self.svm_parameter.cache_size = cache_size;
        self
    }

    /// Build the SVC model. `libsvm` natively supports multiclass
    /// problems via one-vs-one (OvO) estimation, so no one-vs-rest
    /// wrapper is provided.
    pub fn build(&self) -> SVC {
        SVC {
            dim: self.dim,
            hyperparams: self.to_owned(),
            model: None,
        }
    }

    fn svm_parameter(&self) -> &ffi::SvmParameter {
        &self.svm_parameter
    }
}

/// Support Vector Classifier provided by the `libsvm` library.
#[derive(Clone)]
#[derive(RustcEncodable, RustcDecodable)]
pub struct SVC {
    dim: usize,
    hyperparams: Hyperparameters,
    model: Option<ffi::SvmModel>,
}

macro_rules! impl_supervised_model {
    ($x_type:ty) => {
        impl<'a> SupervisedModel<&'a $x_type> for SVC {
            fn fit(&mut self, X: &$x_type, y: &Array) -> Result<(), &'static str> {

                try!(check_data_dimensionality(self.dim, X));
                try!(check_matched_dimensions(X, y));

                let svm_params = self.hyperparams.svm_parameter();

                self.model = Some(try!(ffi::fit(X, y, &svm_params)));

                Ok(())
            }

            fn decision_function(&self, X: &$x_type) -> Result<Array, &'static str> {

                try!(check_data_dimensionality(self.dim, X));

                match self.model {
                    Some(ref model) => {
                        let (decision_function, _)
                            = ffi::predict(model, X);
                        Ok(decision_function)
                    },
                    None => Err("Model must be fit before predicting.")
                }
            }

            fn predict(&self, X: &$x_type) -> Result<Array, &'static str> {

                match self.model {
                    Some(ref model) => {
                        let (_, predicted_class)
                            = ffi::predict(model, X);
                        Ok(predicted_class)
                    },
                    None => Err("Model must be fit before predicting.")
                }
            }
        }
    }
}

impl_supervised_model!(Array);
impl_supervised_model!(SparseRowArray);

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

    use rand::{StdRng, SeedableRng};

    use prelude::*;

    use cross_validation::cross_validation::CrossValidation;
    use datasets::iris::load_data;
    use metrics::accuracy_score;

    use bincode;

    #[cfg(feature = "all_tests")]
    use datasets::newsgroups;

    macro_rules! test_iris_kernel {
        ($kernel:expr, $fn_name:ident) => {
            #[test]
            fn $fn_name() {
                let (data, target) = load_data();

                let mut test_accuracy = 0.0;
                let mut train_accuracy = 0.0;

                let no_splits = 10;

                let mut cv = CrossValidation::new(data.rows(),
                                                  no_splits);
                cv.set_rng(StdRng::from_seed(&[100]));

                for (train_idx, test_idx) in cv {

                    let x_train = data.get_rows(&train_idx);
                    let x_test = data.get_rows(&test_idx);

                    let y_train = target.get_rows(&train_idx);

                    let mut model = Hyperparameters::new(data.cols(), $kernel, 3)
                        .build();

                    model.fit(&x_train, &y_train).unwrap();

                    let y_hat = model.predict(&x_test).unwrap();

                    test_accuracy += accuracy_score(
                        &target.get_rows(&test_idx),
                        &y_hat);
                    train_accuracy += accuracy_score(
                        &y_train,
                        &model.predict(&x_train).unwrap());
                }

                test_accuracy /= no_splits as f32;
                train_accuracy /= no_splits as f32;

                println!("Accuracy {}", test_accuracy);
                println!("Train accuracy {}", train_accuracy);
                assert!(test_accuracy > 0.97);
            }
        }
    }

    test_iris_kernel!(KernelType::Linear, test_iris_linear);
    test_iris_kernel!(KernelType::Polynomial, test_iris_polynomial);
    test_iris_kernel!(KernelType::RBF, test_iris_rbf);

    #[test]
    fn test_sparse_iris() {
        let (dense_data, target) = load_data();
        let data = SparseRowArray::from(&dense_data);

        let mut test_accuracy = 0.0;
        let mut train_accuracy = 0.0;

        let no_splits = 10;

        let mut cv = CrossValidation::new(data.rows(), no_splits);
        cv.set_rng(StdRng::from_seed(&[100]));

        for (train_idx, test_idx) in cv {

            let x_train = data.get_rows(&train_idx);
            let x_test = data.get_rows(&test_idx);

            let y_train = target.get_rows(&train_idx);

            let mut model = Hyperparameters::new(data.cols(), KernelType::Linear, 3).build();

            model.fit(&x_train, &y_train).unwrap();

            let y_hat = model.predict(&x_test).unwrap();

            test_accuracy += accuracy_score(&target.get_rows(&test_idx), &y_hat);
            train_accuracy += accuracy_score(&y_train, &model.predict(&x_train).unwrap());
        }

        test_accuracy /= no_splits as f32;
        train_accuracy /= no_splits as f32;

        println!("Accuracy {}", test_accuracy);
        println!("Train accuracy {}", train_accuracy);
        assert!(test_accuracy > 0.97);
    }

    #[test]
    fn serialization() {
        let (data, target) = load_data();

        let mut test_accuracy = 0.0;
        let mut train_accuracy = 0.0;

        let no_splits = 10;

        let mut cv = CrossValidation::new(data.rows(), no_splits);
        cv.set_rng(StdRng::from_seed(&[100]));

        for (train_idx, test_idx) in cv {

            let x_train = data.get_rows(&train_idx);
            let x_test = data.get_rows(&test_idx);

            let y_train = target.get_rows(&train_idx);

            let mut model = Hyperparameters::new(data.cols(), KernelType::Linear, 3).build();

            model.fit(&x_train, &y_train).unwrap();

            let encoded = bincode::rustc_serialize::encode(&model, bincode::SizeLimit::Infinite)
                .unwrap();
            let decoded: SVC = bincode::rustc_serialize::decode(&encoded).unwrap();

            let y_hat = decoded.predict(&x_test).unwrap();

            test_accuracy += accuracy_score(&target.get_rows(&test_idx), &y_hat);
            train_accuracy += accuracy_score(&y_train, &decoded.predict(&x_train).unwrap());
        }

        test_accuracy /= no_splits as f32;
        train_accuracy /= no_splits as f32;

        println!("Accuracy {}", test_accuracy);
        println!("Train accuracy {}", train_accuracy);
        assert!(test_accuracy > 0.97);
    }

    #[test]
    #[cfg(feature = "all_tests")]
    fn test_newsgroups() {

        let (X, target) = newsgroups::load_data();

        let no_splits = 2;
        let mut test_accuracy = 0.0;

        let mut cv = CrossValidation::new(X.rows(), no_splits);
        cv.set_rng(StdRng::from_seed(&[100]));

        for (train_idx, test_idx) in cv {

            let x_train = X.get_rows(&train_idx);
            let x_test = X.get_rows(&test_idx);

            let y_train = target.get_rows(&train_idx);

            let mut model = Hyperparameters::new(X.cols(), KernelType::Linear, 20).build();

            model.fit(&x_train, &y_train).unwrap();

            let y_hat = model.predict(&x_test).unwrap();

            test_accuracy += accuracy_score(&target.get_rows(&test_idx), &y_hat);
        }

        test_accuracy /= no_splits as f32;
        println!("{}", test_accuracy);

        // This could definitely be improved
        // with better hyperparameter choice.
        assert!(test_accuracy > 0.8);
    }
}
<commit_msg>Add svm example<commit_after>//! Support Vector Classifier using the `libsvm` library.
//!
//! Both dense and sparse models are supported.
//!
//! # Examples
//!
//! ```
//! use rustlearn::prelude::*; use rustlearn::datasets::iris;
//! use rustlearn::svm::libsvm::svc::{Hyperparameters, KernelType};
//!
//! let (X, y) = iris::load_data();
//!
//! let mut model = Hyperparameters::new(4, KernelType::Linear, 4)
//!     .C(0.3)
//!     .build();
//!
//! model.fit(&X, &y).unwrap();
//!
//! let prediction = model.predict(&X).unwrap();
//! ```

use prelude::*;

use super::ffi;
pub use super::ffi::KernelType;

use utils::{check_data_dimensionality, check_matched_dimensions};

#[derive(Clone)]
#[derive(RustcEncodable, RustcDecodable)]
/// Hyperparameters for the SVC model.
pub struct Hyperparameters {
    dim: usize,
    num_classes: usize,
    svm_parameter: ffi::SvmParameter,
}

impl Hyperparameters {
    pub fn new(dim: usize, kernel: KernelType, num_classes: usize) -> Hyperparameters {
        Hyperparameters {
            dim: dim,
            num_classes: num_classes,
            svm_parameter: ffi::SvmParameter::new(ffi::SvmType::C_SVC, kernel, num_classes, dim),
        }
    }

    /// Set the regularization parameter `C`; smaller values
    /// mean more regularization.
    /// Default is `1.0`.
    pub fn C(&mut self, C: f64) -> &mut Hyperparameters {
        self.svm_parameter.C = C;
        self
    }

    /// Set the degree of the polynomial kernel. No effect on other
    /// kernels. Default: 3.
    pub fn degree(&mut self, degree: i32) -> &mut Hyperparameters {
        self.svm_parameter.degree = degree;
        self
    }

    /// Set the gamma parameter of the RBF kernel.
    /// Default is `1 / self.dim`.
    pub fn gamma(&mut self, gamma: f64) -> &mut Hyperparameters {
        self.svm_parameter.gamma = gamma;
        self
    }

    /// Set the coef0 parameter for the sigmoid kernel.
    /// Default is `0.0`.
    pub fn coef0(&mut self, coef0: f64) -> &mut Hyperparameters {
        self.svm_parameter.coef0 = coef0;
        self
    }

    /// Set the `libsvm` cache size, in megabytes.
    /// Default is `100.0`.
    pub fn cache_size(&mut self, cache_size: f64) -> &mut Hyperparameters {
        self.svm_parameter.cache_size = cache_size;
        self
    }

    /// Build the SVC model. `libsvm` natively supports multiclass
    /// problems via one-vs-one (OvO) estimation, so no one-vs-rest
    /// wrapper is provided.
    pub fn build(&self) -> SVC {
        SVC {
            dim: self.dim,
            hyperparams: self.to_owned(),
            model: None,
        }
    }

    fn svm_parameter(&self) -> &ffi::SvmParameter {
        &self.svm_parameter
    }
}

/// Support Vector Classifier provided by the `libsvm` library.
#[derive(Clone)]
#[derive(RustcEncodable, RustcDecodable)]
pub struct SVC {
    dim: usize,
    hyperparams: Hyperparameters,
    model: Option<ffi::SvmModel>,
}

macro_rules! impl_supervised_model {
    ($x_type:ty) => {
        impl<'a> SupervisedModel<&'a $x_type> for SVC {
            fn fit(&mut self, X: &$x_type, y: &Array) -> Result<(), &'static str> {

                try!(check_data_dimensionality(self.dim, X));
                try!(check_matched_dimensions(X, y));

                let svm_params = self.hyperparams.svm_parameter();

                self.model = Some(try!(ffi::fit(X, y, &svm_params)));

                Ok(())
            }

            fn decision_function(&self, X: &$x_type) -> Result<Array, &'static str> {

                try!(check_data_dimensionality(self.dim, X));

                match self.model {
                    Some(ref model) => {
                        let (decision_function, _)
                            = ffi::predict(model, X);
                        Ok(decision_function)
                    },
                    None => Err("Model must be fit before predicting.")
                }
            }

            fn predict(&self, X: &$x_type) -> Result<Array, &'static str> {

                match self.model {
                    Some(ref model) => {
                        let (_, predicted_class)
                            = ffi::predict(model, X);
                        Ok(predicted_class)
                    },
                    None => Err("Model must be fit before predicting.")
                }
            }
        }
    }
}

impl_supervised_model!(Array);
impl_supervised_model!(SparseRowArray);

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

    use rand::{StdRng, SeedableRng};

    use prelude::*;

    use cross_validation::cross_validation::CrossValidation;
    use datasets::iris::load_data;
    use metrics::accuracy_score;

    use bincode;

    #[cfg(feature = "all_tests")]
    use datasets::newsgroups;

    macro_rules! test_iris_kernel {
        ($kernel:expr, $fn_name:ident) => {
            #[test]
            fn $fn_name() {
                let (data, target) = load_data();

                let mut test_accuracy = 0.0;
                let mut train_accuracy = 0.0;

                let no_splits = 10;

                let mut cv = CrossValidation::new(data.rows(),
                                                  no_splits);
                cv.set_rng(StdRng::from_seed(&[100]));

                for (train_idx, test_idx) in cv {

                    let x_train = data.get_rows(&train_idx);
                    let x_test = data.get_rows(&test_idx);

                    let y_train = target.get_rows(&train_idx);

                    let mut model = Hyperparameters::new(data.cols(), $kernel, 3)
                        .build();

                    model.fit(&x_train, &y_train).unwrap();

                    let y_hat = model.predict(&x_test).unwrap();

                    test_accuracy += accuracy_score(
                        &target.get_rows(&test_idx),
                        &y_hat);
                    train_accuracy += accuracy_score(
                        &y_train,
                        &model.predict(&x_train).unwrap());
                }

                test_accuracy /= no_splits as f32;
                train_accuracy /= no_splits as f32;

                println!("Accuracy {}", test_accuracy);
                println!("Train accuracy {}", train_accuracy);
                assert!(test_accuracy > 0.97);
            }
        }
    }

    test_iris_kernel!(KernelType::Linear, test_iris_linear);
    test_iris_kernel!(KernelType::Polynomial, test_iris_polynomial);
    test_iris_kernel!(KernelType::RBF, test_iris_rbf);

    #[test]
    fn test_sparse_iris() {
        let (dense_data, target) = load_data();
        let data = SparseRowArray::from(&dense_data);

        let mut test_accuracy = 0.0;
        let mut train_accuracy = 0.0;

        let no_splits = 10;

        let mut cv = CrossValidation::new(data.rows(), no_splits);
        cv.set_rng(StdRng::from_seed(&[100]));

        for (train_idx, test_idx) in cv {

            let x_train = data.get_rows(&train_idx);
            let x_test = data.get_rows(&test_idx);

            let y_train = target.get_rows(&train_idx);

            let mut model = Hyperparameters::new(data.cols(), KernelType::Linear, 3).build();

            model.fit(&x_train, &y_train).unwrap();

            let y_hat = model.predict(&x_test).unwrap();

            test_accuracy += accuracy_score(&target.get_rows(&test_idx), &y_hat);
            train_accuracy += accuracy_score(&y_train, &model.predict(&x_train).unwrap());
        }

        test_accuracy /= no_splits as f32;
        train_accuracy /= no_splits as f32;

        println!("Accuracy {}", test_accuracy);
        println!("Train accuracy {}", train_accuracy);
        assert!(test_accuracy > 0.97);
    }

    #[test]
    fn serialization() {
        let (data, target) = load_data();

        let mut test_accuracy = 0.0;
        let mut train_accuracy = 0.0;

        let no_splits = 10;

        let mut cv = CrossValidation::new(data.rows(), no_splits);
        cv.set_rng(StdRng::from_seed(&[100]));

        for (train_idx, test_idx) in cv {

            let x_train = data.get_rows(&train_idx);
            let x_test = data.get_rows(&test_idx);

            let y_train = target.get_rows(&train_idx);

            let mut model = Hyperparameters::new(data.cols(), KernelType::Linear, 3).build();

            model.fit(&x_train, &y_train).unwrap();

            let encoded = bincode::rustc_serialize::encode(&model, bincode::SizeLimit::Infinite)
                .unwrap();
            let decoded: SVC = bincode::rustc_serialize::decode(&encoded).unwrap();

            let y_hat = decoded.predict(&x_test).unwrap();

            test_accuracy += accuracy_score(&target.get_rows(&test_idx), &y_hat);
            train_accuracy += accuracy_score(&y_train, &decoded.predict(&x_train).unwrap());
        }

        test_accuracy /= no_splits as f32;
        train_accuracy /= no_splits as f32;

        println!("Accuracy {}", test_accuracy);
        println!("Train accuracy {}", train_accuracy);
        assert!(test_accuracy > 0.97);
    }

    #[test]
    #[cfg(feature = "all_tests")]
    fn test_newsgroups() {

        let (X, target) = newsgroups::load_data();

        let no_splits = 2;
        let mut test_accuracy = 0.0;

        let mut cv = CrossValidation::new(X.rows(), no_splits);
        cv.set_rng(StdRng::from_seed(&[100]));

        for (train_idx, test_idx) in cv {

            let x_train = X.get_rows(&train_idx);
            let x_test = X.get_rows(&test_idx);

            let y_train = target.get_rows(&train_idx);

            let mut model = Hyperparameters::new(X.cols(), KernelType::Linear, 20).build();

            model.fit(&x_train, &y_train).unwrap();

            let y_hat = model.predict(&x_test).unwrap();

            test_accuracy += accuracy_score(&target.get_rows(&test_idx), &y_hat);
        }

        test_accuracy /= no_splits as f32;
        println!("{}", test_accuracy);

        // This could definitely be improved
        // with better hyperparameter choice.
        assert!(test_accuracy > 0.8);
    }
}
<|endoftext|>


<commit_before>use mio_uds::UnixStream;
use mio::Poll;
use libc::{self,c_char,uint32_t,int32_t,pid_t};
use std::io;
use std::ffi::CString;
use std::iter::repeat;
use std::ptr::null_mut;
use std::process::Command;
use std::net::ToSocketAddrs;
use std::os::unix::process::CommandExt;
use std::os::unix::io::{AsRawFd,FromRawFd};
use nix;
use nix::unistd::*;
use nix::fcntl::{fcntl,FcntlArg,FdFlag,FD_CLOEXEC};

use sozu_command::config::Config;
use sozu_command::channel::Channel;
use sozu::network::session::Session;
use sozu_command::messages::{OrderMessage,OrderMessageAnswer};
use sozu::network::{http,tls};
use sozu::network::proxy::Server;

use logging;
use command::Worker;

pub fn start_workers(config: &Config) -> nix::Result<Vec<Worker>> {
  let mut workers = Vec::new();
  for index in 0..config.worker_count.unwrap_or(1) {
    match start_worker_process(&index.to_string(), config) {
      Ok((pid, command)) => {
        let w =  Worker::new(index as u32, pid, command, config);
        workers.push(w);
      },
      Err(e) => return Err(e)
    };
  }
  Ok(workers)
}

pub fn start_worker(id: u32, config: &Config) -> nix::Result<Worker> {
  match start_worker_process(&id.to_string(), config) {
    Ok((pid, command)) => {
      let w = Worker::new(id, pid, command, config);
      Ok(w)
    },
    Err(e) => Err(e)
  }
}

fn generate_channels() -> io::Result<(Channel<OrderMessage,OrderMessageAnswer>, Channel<OrderMessageAnswer,OrderMessage>)> {
  let (command,proxy) = try!(UnixStream::pair());
  //FIXME: configurable buffer size
  let proxy_channel   = Channel::new(proxy, 10000, 20000);
  let command_channel = Channel::new(command, 10000, 20000);
  Ok((command_channel, proxy_channel))
}

pub fn begin_worker_process(fd: i32, id: &str, channel_buffer_size: usize) {
  let mut command: Channel<OrderMessageAnswer,Config> = Channel::new(
    unsafe { UnixStream::from_raw_fd(fd) },
    channel_buffer_size,
    channel_buffer_size * 2
  );

  command.set_nonblocking(false);

  let proxy_config = command.read_message().expect("worker could not read configuration from socket");
  //println!("got message: {:?}", proxy_config);

  logging::setup(format!("{}-{}", "TAG", id), &proxy_config.log_level, &proxy_config.log_target);

  command.set_nonblocking(true);
  let command: Channel<OrderMessageAnswer,OrderMessage> = command.into();

  if let Some(ref metrics) = proxy_config.metrics.as_ref() {
    metrics_set_up!(&metrics.address[..], metrics.port);
    gauge!("sozu.worker.TEST", 42);
  }

  let mut event_loop  = Poll::new().expect("could not create event loop");

  let http_session = proxy_config.http.and_then(|conf| conf.to_http()).and_then(|http_conf| {
    let max_connections = http_conf.max_connections;
    let max_listeners = 1;
    http::ServerConfiguration::new(http_conf, &mut event_loop, 1 + max_listeners).map(|configuration| {
      Session::new(1, max_connections, 0, configuration, &mut event_loop)
    }).ok()
  });

  let https_session = proxy_config.https.and_then(|conf| conf.to_tls()).and_then(|https_conf| {
    let max_connections = https_conf.max_connections;
    let max_listeners   = 1;
    tls::ServerConfiguration::new(https_conf, 6148914691236517205, &mut event_loop, 1 + max_listeners + 6148914691236517205).map(|configuration| {
      Session::new(max_listeners, max_connections, 6148914691236517205, configuration, &mut event_loop)
    }).ok()
  });
  //TODO: implement for TCP

  let mut server = Server::new(event_loop, command, http_session, https_session, None);
  info!("starting event loop");
  server.run();
  info!("ending event loop");
}

pub fn start_worker_process(id: &str, config: &Config) -> nix::Result<(pid_t, Channel<OrderMessage,OrderMessageAnswer>)> {
  trace!("parent({})", unsafe { libc::getpid() });

  let (server, client) = UnixStream::pair().unwrap();

  // FD_CLOEXEC is set by default on every fd in Rust standard lib,
  // so we need to remove the flag on the client, otherwise
  // it won't be accessible
  let cl_flags = fcntl(client.as_raw_fd(), FcntlArg::F_GETFD).unwrap();
  let mut new_cl_flags = FdFlag::from_bits(cl_flags).unwrap();
  new_cl_flags.remove(FD_CLOEXEC);
  fcntl(client.as_raw_fd(), FcntlArg::F_SETFD(new_cl_flags));

  let channel_buffer_size = config.channel_buffer_size.unwrap_or(10000);
  let channel_max_buffer_size = channel_buffer_size * 2;

  let mut command: Channel<Config,OrderMessageAnswer> = Channel::new(
    server,
    channel_buffer_size,
    channel_max_buffer_size
  );
  command.set_nonblocking(false);

  let path = unsafe { get_executable_path() };

  info!("launching worker");
  match fork() {
    Ok(ForkResult::Parent{ child }) => {
      info!("worker launched: {}", child);
      command.write_message(config);
      command.set_nonblocking(true);

      let command: Channel<OrderMessage,OrderMessageAnswer> = command.into();
      Ok((child, command))
    },
    Ok(ForkResult::Child) => {
      trace!("child({}):\twill spawn a child", unsafe { libc::getpid() });
      Command::new(path.to_str().unwrap())
        .arg("worker")
        .arg("--fd")
        .arg(client.as_raw_fd().to_string())
        .arg("--id")
        .arg(id)
        .arg("--channel-buffer-size")
        .arg(channel_buffer_size.to_string())
        .exec();

      unreachable!();
    },
    Err(e) => {
      error!("Error during fork(): {}", e);
      Err(e)
    }
  }
}

#[cfg(target_os = "linux")]
pub unsafe fn get_executable_path() -> CString {
  let capacity = 2000;
  let mut temp:Vec<u8> = Vec::with_capacity(capacity);
  temp.extend(repeat(0).take(capacity));
  let mut pathbuf = CString::from_vec_unchecked(temp);
  let ptr = pathbuf.into_raw();

  let proc_path = CString::new("/proc/self/exe").unwrap();
  let sz = libc::readlink( proc_path.as_ptr(), ptr, 1999);
  let path = CString::from_raw(ptr);
  path
}

#[cfg(target_os = "macos")]
extern {
  pub fn _NSGetExecutablePath(buf: *mut c_char, size: *mut uint32_t) -> int32_t;
}

#[cfg(target_os = "macos")]
pub unsafe fn get_executable_path() -> CString {
  let capacity = 2000;
  let mut temp:Vec<u8> = Vec::with_capacity(capacity);
  temp.extend(repeat(0).take(capacity));
  let pathbuf = CString::from_vec_unchecked(temp);
  let ptr = pathbuf.into_raw();

  let mut size:uint32_t = capacity as u32;
  if _NSGetExecutablePath(ptr, &mut size) == 0 {

    let mut temp2:Vec<u8> = Vec::with_capacity(capacity);
    temp2.extend(repeat(0).take(capacity));
    let pathbuf2 = CString::from_vec_unchecked(temp2);
    let ptr2 = pathbuf2.into_raw();

    if libc::realpath(ptr, ptr2) != null_mut() {
      let path = CString::from_raw(ptr2);
      path
    } else {
      panic!();
    }
  } else {
    panic!("buffer too small");
  }
}
<commit_msg>mark a worker's command channel as readable at startup<commit_after>use mio_uds::UnixStream;
use mio::{Poll,Ready};
use libc::{self,c_char,uint32_t,int32_t,pid_t};
use std::io;
use std::ffi::CString;
use std::iter::repeat;
use std::ptr::null_mut;
use std::process::Command;
use std::net::ToSocketAddrs;
use std::os::unix::process::CommandExt;
use std::os::unix::io::{AsRawFd,FromRawFd};
use nix;
use nix::unistd::*;
use nix::fcntl::{fcntl,FcntlArg,FdFlag,FD_CLOEXEC};

use sozu_command::config::Config;
use sozu_command::channel::Channel;
use sozu::network::session::Session;
use sozu_command::messages::{OrderMessage,OrderMessageAnswer};
use sozu::network::{http,tls};
use sozu::network::proxy::Server;

use logging;
use command::Worker;

pub fn start_workers(config: &Config) -> nix::Result<Vec<Worker>> {
  let mut workers = Vec::new();
  for index in 0..config.worker_count.unwrap_or(1) {
    match start_worker_process(&index.to_string(), config) {
      Ok((pid, command)) => {
        let w =  Worker::new(index as u32, pid, command, config);
        workers.push(w);
      },
      Err(e) => return Err(e)
    };
  }
  Ok(workers)
}

pub fn start_worker(id: u32, config: &Config) -> nix::Result<Worker> {
  match start_worker_process(&id.to_string(), config) {
    Ok((pid, command)) => {
      let w = Worker::new(id, pid, command, config);
      Ok(w)
    },
    Err(e) => Err(e)
  }
}

fn generate_channels() -> io::Result<(Channel<OrderMessage,OrderMessageAnswer>, Channel<OrderMessageAnswer,OrderMessage>)> {
  let (command,proxy) = try!(UnixStream::pair());
  //FIXME: configurable buffer size
  let proxy_channel   = Channel::new(proxy, 10000, 20000);
  let command_channel = Channel::new(command, 10000, 20000);
  Ok((command_channel, proxy_channel))
}

pub fn begin_worker_process(fd: i32, id: &str, channel_buffer_size: usize) {
  let mut command: Channel<OrderMessageAnswer,Config> = Channel::new(
    unsafe { UnixStream::from_raw_fd(fd) },
    channel_buffer_size,
    channel_buffer_size * 2
  );

  command.set_nonblocking(false);

  let proxy_config = command.read_message().expect("worker could not read configuration from socket");
  //println!("got message: {:?}", proxy_config);

  logging::setup(format!("{}-{}", "TAG", id), &proxy_config.log_level, &proxy_config.log_target);
  info!("starting...");

  command.set_nonblocking(true);
  let mut command: Channel<OrderMessageAnswer,OrderMessage> = command.into();

  if let Some(ref metrics) = proxy_config.metrics.as_ref() {
    metrics_set_up!(&metrics.address[..], metrics.port);
    gauge!("sozu.worker.TEST", 42);
  }

  let mut event_loop  = Poll::new().expect("could not create event loop");

  let http_session = proxy_config.http.and_then(|conf| conf.to_http()).and_then(|http_conf| {
    let max_connections = http_conf.max_connections;
    let max_listeners = 1;
    http::ServerConfiguration::new(http_conf, &mut event_loop, 1 + max_listeners).map(|configuration| {
      Session::new(1, max_connections, 0, configuration, &mut event_loop)
    }).ok()
  });

  let https_session = proxy_config.https.and_then(|conf| conf.to_tls()).and_then(|https_conf| {
    let max_connections = https_conf.max_connections;
    let max_listeners   = 1;
    tls::ServerConfiguration::new(https_conf, 6148914691236517205, &mut event_loop, 1 + max_listeners + 6148914691236517205).map(|configuration| {
      Session::new(max_listeners, max_connections, 6148914691236517205, configuration, &mut event_loop)
    }).ok()
  });
  //TODO: implement for TCP

  command.readiness.insert(Ready::readable());
  let mut server = Server::new(event_loop, command, http_session, https_session, None);
  info!("starting event loop");
  server.run();
  info!("ending event loop");
}

pub fn start_worker_process(id: &str, config: &Config) -> nix::Result<(pid_t, Channel<OrderMessage,OrderMessageAnswer>)> {
  trace!("parent({})", unsafe { libc::getpid() });

  let (server, client) = UnixStream::pair().unwrap();

  // FD_CLOEXEC is set by default on every fd in Rust standard lib,
  // so we need to remove the flag on the client, otherwise
  // it won't be accessible
  let cl_flags = fcntl(client.as_raw_fd(), FcntlArg::F_GETFD).unwrap();
  let mut new_cl_flags = FdFlag::from_bits(cl_flags).unwrap();
  new_cl_flags.remove(FD_CLOEXEC);
  fcntl(client.as_raw_fd(), FcntlArg::F_SETFD(new_cl_flags));

  let channel_buffer_size = config.channel_buffer_size.unwrap_or(10000);
  let channel_max_buffer_size = channel_buffer_size * 2;

  let mut command: Channel<Config,OrderMessageAnswer> = Channel::new(
    server,
    channel_buffer_size,
    channel_max_buffer_size
  );
  command.set_nonblocking(false);

  let path = unsafe { get_executable_path() };

  info!("launching worker");
  match fork() {
    Ok(ForkResult::Parent{ child }) => {
      info!("worker launched: {}", child);
      command.write_message(config);
      command.set_nonblocking(true);

      let command: Channel<OrderMessage,OrderMessageAnswer> = command.into();
      Ok((child, command))
    },
    Ok(ForkResult::Child) => {
      trace!("child({}):\twill spawn a child", unsafe { libc::getpid() });
      Command::new(path.to_str().unwrap())
        .arg("worker")
        .arg("--fd")
        .arg(client.as_raw_fd().to_string())
        .arg("--id")
        .arg(id)
        .arg("--channel-buffer-size")
        .arg(channel_buffer_size.to_string())
        .exec();

      unreachable!();
    },
    Err(e) => {
      error!("Error during fork(): {}", e);
      Err(e)
    }
  }
}

#[cfg(target_os = "linux")]
pub unsafe fn get_executable_path() -> CString {
  let capacity = 2000;
  let mut temp:Vec<u8> = Vec::with_capacity(capacity);
  temp.extend(repeat(0).take(capacity));
  let mut pathbuf = CString::from_vec_unchecked(temp);
  let ptr = pathbuf.into_raw();

  let proc_path = CString::new("/proc/self/exe").unwrap();
  let sz = libc::readlink( proc_path.as_ptr(), ptr, 1999);
  let path = CString::from_raw(ptr);
  path
}

#[cfg(target_os = "macos")]
extern {
  pub fn _NSGetExecutablePath(buf: *mut c_char, size: *mut uint32_t) -> int32_t;
}

#[cfg(target_os = "macos")]
pub unsafe fn get_executable_path() -> CString {
  let capacity = 2000;
  let mut temp:Vec<u8> = Vec::with_capacity(capacity);
  temp.extend(repeat(0).take(capacity));
  let pathbuf = CString::from_vec_unchecked(temp);
  let ptr = pathbuf.into_raw();

  let mut size:uint32_t = capacity as u32;
  if _NSGetExecutablePath(ptr, &mut size) == 0 {

    let mut temp2:Vec<u8> = Vec::with_capacity(capacity);
    temp2.extend(repeat(0).take(capacity));
    let pathbuf2 = CString::from_vec_unchecked(temp2);
    let ptr2 = pathbuf2.into_raw();

    if libc::realpath(ptr, ptr2) != null_mut() {
      let path = CString::from_raw(ptr2);
      path
    } else {
      panic!();
    }
  } else {
    panic!("buffer too small");
  }
}
<|endoftext|>


<commit_before>use crate::{test_utils::TestRandom, Epoch};
use bls::Signature;
use rand::RngCore;
use serde_derive::{Deserialize, Serialize};
use ssz::TreeHash;
use ssz_derive::{Decode, Encode, SignedRoot, TreeHash};
use test_random_derive::TestRandom;

/// An exit voluntarily submitted a validator who wishes to withdraw.
///
/// Spec v0.4.0
#[derive(
    Debug,
    PartialEq,
    Clone,
    Serialize,
    Deserialize,
    Encode,
    Decode,
    TreeHash,
    TestRandom,
    SignedRoot,
)]
pub struct VoluntaryExit {
    pub epoch: Epoch,
    pub validator_index: u64,
    pub signature: Signature,
}

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

    ssz_tests!(VoluntaryExit);
}
<commit_msg>Fast-forward unchanged exit to v0.5.0<commit_after>use crate::{test_utils::TestRandom, Epoch};
use bls::Signature;
use rand::RngCore;
use serde_derive::{Deserialize, Serialize};
use ssz::TreeHash;
use ssz_derive::{Decode, Encode, SignedRoot, TreeHash};
use test_random_derive::TestRandom;

/// An exit voluntarily submitted a validator who wishes to withdraw.
///
/// Spec v0.5.0
#[derive(
    Debug,
    PartialEq,
    Clone,
    Serialize,
    Deserialize,
    Encode,
    Decode,
    TreeHash,
    TestRandom,
    SignedRoot,
)]
pub struct VoluntaryExit {
    pub epoch: Epoch,
    pub validator_index: u64,
    pub signature: Signature,
}

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

    ssz_tests!(VoluntaryExit);
}
<|endoftext|>


<commit_before>use mat::*;
use quat::*;
use vec::*;

// TODO

#[test]
fn test_Quat() {
    let a = Quat { s: 1f, v: Vec3 { x: 2f, y: 3f, z: 4f } };

    assert a == Quat::from_sv(1f, Vec3::new(2f, 3f, 4f));
    assert a == Quat::new(1f, 2f, 3f, 4f);

    // assert Quat::zero()     == Quat::new(0f, 0f, 0f, 0f);
    // assert Quat::identity() == Quat::new(1f, 0f, 0f, 0f);

    assert a.s == 1f;
    assert a.v.x == 2f;
    assert a.v.y == 3f;
    assert a.v.z == 4f;
    assert a[0] == 1f;
    assert a[1] == 2f;
    assert a[2] == 3f;
    assert a[3] == 4f;

    // TODO
}<commit_msg>Add more Quaternion unit tests.<commit_after>use mat::*;
use quat::*;
use vec::*;
use funs::exponential::sqrt;

// TODO

#[test]
fn test_Quat() {
    let a = Quat { s: 1f, v: Vec3 { x: 2f, y: 3f, z: 4f } };

    assert a == Quat::from_sv(1f, Vec3::new(2f, 3f, 4f));
    assert a == Quat::new(1f, 2f, 3f, 4f);

    assert Quat::zero()     == Quat::new(0f, 0f, 0f, 0f);
    assert Quat::identity() == Quat::new(1f, 0f, 0f, 0f);

    assert a.s == 1f;
    assert a.v.x == 2f;
    assert a.v.y == 3f;
    assert a.v.z == 4f;
    assert a[0] == 1f;
    assert a[1] == 2f;
    assert a[2] == 3f;
    assert a[3] == 4f;
    // TODO
}

#[test]
fn test_quat_2() {
    let v = Vec3::new(1.0, 0.0, 0.0);

    // let q: Quat<float> = Quaternion::from_axis_angle(&Vec3::new(0.0, 0.0, -1.0), Degrees(-90.0));
    let q = Quat::from_axis_angle(&Vec3::new(0.0, 0.0, -1.0), Degrees(-45.0));

    // http://www.wolframalpha.com/input/?i={1,0}+rotate+-45+degrees
    assert q.mul_v(&v).fuzzy_eq(&Vec3::new(1.0/sqrt(&2.0), 1.0/sqrt(&2.0), 0.0));
    assert q.mul_v(&v).length() == v.length();
    assert q.to_mat3().fuzzy_eq(&Mat3::new( 1.0/sqrt(&2.0), 1.0/sqrt(&2.0), 0.0,
                                           -1.0/sqrt(&2.0), 1.0/sqrt(&2.0), 0.0,
                                                       0.0,            0.0, 1.0));
}

/*

Here is what I use to test my quaternions:

* First, rotate an arbitrary vector around an arbitrary axis using an arbitrary angle (of course with a quaternion).

* Then compare the original to the result vector, considering length and angle. If the length is constant and the angle is as desired, everything is fine and you are "green".

* Now generate a series of rotation quaternions and concatenate them. Transform an arbitrary vector with it.

* Now use each individual transformation of that series to transform the vector again, but this time checking angle and length like in the single transformation case. Only proceed while you stay "green".

* Finally, compare both results. If they match, you are "green".

*/<|endoftext|>