<commit_before>use std::rc::*;

use super::treenode::*;

///
/// Represents the address of a node relative to another node
///
pub enum TreeAddress {
    /// Selects this node
    Here,

    /// Selects a child of this node by index, then selects a new address from there
    ChildAtIndex(usize, Box<TreeAddress>),

    /// Selects a child of this node by tag name, then selects a new address from there
    ChildWithTag(String, Box<TreeAddress>),

    /// Selects a child of this node by looking up the 'nth' child with the specified tag, then selects a new address from there
    ChildWithIndexedTag(String, usize, Box<TreeAddress>)
}

impl TreeNodeIndex for TreeAddress {
    fn lookup_index(&self, parent_node: &Rc<TreeNode>) -> Option<Rc<TreeNode>> {
        match *self {
            TreeAddress::Here => Some(parent_node.to_owned()),

            TreeAddress::ChildAtIndex(ref pos, ref next) => {
                (*pos).lookup_index(parent_node).and_then(|new_parent| {
                    (*next).lookup_index(&new_parent)
                })
            },

            TreeAddress::ChildWithTag(ref name, ref next) => {
                (&**name).lookup_index(parent_node).and_then(|new_parent| {
                    (*next).lookup_index(&new_parent)
                })
            },

            TreeAddress::ChildWithIndexedTag(ref name, ref pos, ref next) => {
                let mut current = parent_node.get_child_ref();
                let mut remaining = *pos;

                loop {
                    match current.to_owned() {
                        Some(ref current_ref) => {
                            if current_ref.get_tag() == name {
                                if remaining == 0 {
                                    return (*next).lookup_index(current_ref);
                                }

                                remaining = remaining-1;
                            }

                            current = current_ref.get_sibling_ref();
                        },

                        None => {
                            return None;
                        }
                    }
                }
            }
        }
    }
}

#[cfg(test)]
mod treeaddress_test {
    #[macro_use]
    use super::super::super::tree::*;

    #[test]
    fn lookup_here() {
        let someTree = tree!("Here", "There", "Everywhere");

        assert!(someTree.get_child_ref_at(TreeAddress::Here).unwrap().get_tag() == "Here");
    }

    #[test]
    fn lookup_child() {
        let someTree = tree!("Here", "There", "Everywhere");

        assert!(someTree.get_child_ref_at(TreeAddress::ChildAtIndex(0, Box::new(TreeAddress::Here))).unwrap().get_tag() == "There");
        assert!(someTree.get_child_ref_at(TreeAddress::ChildAtIndex(1, Box::new(TreeAddress::Here))).unwrap().get_tag() == "Everywhere");
    }

    #[test]
    fn lookup_tag() {
        let someTree = tree!("Here", "There", "Everywhere");

        assert!(someTree.get_child_ref_at(TreeAddress::ChildWithTag("There".to_string(), Box::new(TreeAddress::Here))).unwrap().get_tag() == "There");
        assert!(someTree.get_child_ref_at(TreeAddress::ChildWithTag("Everywhere".to_string(), Box::new(TreeAddress::Here))).unwrap().get_tag() == "Everywhere");
    }

    #[test]
    fn lookup_indexed_tag() {
        let someTree = tree!("Here", ("Tag", "First"), ("Tag", "Second"));

        assert!(someTree.get_child_ref_at(TreeAddress::ChildWithIndexedTag("Tag".to_string(), 0, Box::new(TreeAddress::Here))).unwrap().get_value().to_str("") == "First");
        assert!(someTree.get_child_ref_at(TreeAddress::ChildWithIndexedTag("Tag".to_string(), 1, Box::new(TreeAddress::Here))).unwrap().get_value().to_str("") == "Second");
    }

    #[test]
    fn lookup_grandchild() {
        let someTree = tree!("Here", tree!("There", "Everywhere"));

        assert!(someTree.get_child_ref_at(TreeAddress::ChildWithTag("There".to_string(), Box::new(TreeAddress::ChildAtIndex(0, Box::new(TreeAddress::Here))))).unwrap().get_tag() == "Everywhere");
    }
}
<commit_msg>Add a bunch of traits and implementations so that tree addresses can be represented more concisely.<commit_after>use std::rc::*;

use super::treenode::*;

///
/// Represents the address of a node relative to another node
///
#[derive(Clone)]
pub enum TreeAddress {
    /// Selects this node
    Here,

    /// Selects a child of this node by index, then selects a new address from there
    ChildAtIndex(usize, Box<TreeAddress>),

    /// Selects a child of this node by tag name, then selects a new address from there
    ChildWithTag(String, Box<TreeAddress>),

    /// Selects a child of this node by looking up the 'nth' child with the specified tag, then selects a new address from there
    ChildWithIndexedTag(String, usize, Box<TreeAddress>)
}

impl TreeNodeIndex for TreeAddress {
    fn lookup_index(&self, parent_node: &Rc<TreeNode>) -> Option<Rc<TreeNode>> {
        match *self {
            TreeAddress::Here => Some(parent_node.to_owned()),

            TreeAddress::ChildAtIndex(ref pos, ref next) => {
                (*pos).lookup_index(parent_node).and_then(|new_parent| {
                    (*next).lookup_index(&new_parent)
                })
            },

            TreeAddress::ChildWithTag(ref name, ref next) => {
                (&**name).lookup_index(parent_node).and_then(|new_parent| {
                    (*next).lookup_index(&new_parent)
                })
            },

            TreeAddress::ChildWithIndexedTag(ref name, ref pos, ref next) => {
                let mut current = parent_node.get_child_ref();
                let mut remaining = *pos;

                loop {
                    match current.to_owned() {
                        Some(ref current_ref) => {
                            if current_ref.get_tag() == name {
                                if remaining == 0 {
                                    return (*next).lookup_index(current_ref);
                                }

                                remaining = remaining-1;
                            }

                            current = current_ref.get_sibling_ref();
                        },

                        None => {
                            return None;
                        }
                    }
                }
            }
        }
    }
}

///
/// Structure representing a tag with an index
///
pub struct TagIndex<'a>(&'a str, usize);

///
/// Structure representing a shorthand address
///
/// This has `TreeNodeIndex` implemented on it, so `treenode.get_child_ref_at(Addr(0, ()))` will work
///
pub struct Addr<TFirst: ToTreeAddress, TSecond: ToTreeAddress>(TFirst, TSecond);

///
/// Trait that is implemented by types that can be converted to tree addresses
///
pub trait ToTreeAddress {
    fn to_tree_address(&self) -> TreeAddress;
    fn to_tree_address_then(&self, then: TreeAddress) -> TreeAddress;
}

impl ToTreeAddress for () {
    #[inline]
    fn to_tree_address(&self) -> TreeAddress {
        TreeAddress::Here
    }

    #[inline]
    fn to_tree_address_then(&self, then: TreeAddress) -> TreeAddress {
        then
    }
}

impl ToTreeAddress for usize {
    #[inline]
    fn to_tree_address(&self) -> TreeAddress {
        TreeAddress::ChildAtIndex(*self, Box::new(TreeAddress::Here))
    }

    #[inline]
    fn to_tree_address_then(&self, then: TreeAddress) -> TreeAddress {
        TreeAddress::ChildAtIndex(*self, Box::new(then))
    }
}

impl<'a> ToTreeAddress for TagIndex<'a> {
    #[inline]
    fn to_tree_address(&self) -> TreeAddress {
        let TagIndex(ref tag, ref pos) = *self;
        TreeAddress::ChildWithIndexedTag((*tag).to_string(), *pos, Box::new(TreeAddress::Here))
    }

    #[inline]
    fn to_tree_address_then(&self, then: TreeAddress) -> TreeAddress {
        let TagIndex(ref tag, ref pos) = *self;
        TreeAddress::ChildWithIndexedTag((*tag).to_string(), *pos, Box::new(then))
    }
}

impl<'a> ToTreeAddress for &'a str {
    #[inline]
    fn to_tree_address(&self) -> TreeAddress {
        TreeAddress::ChildWithTag((*self).to_string(), Box::new(TreeAddress::Here))
    }

    #[inline]
    fn to_tree_address_then(&self, then: TreeAddress) -> TreeAddress {
        TreeAddress::ChildWithTag((*self).to_string(), Box::new(then))
    }
}

impl ToTreeAddress for TreeAddress {
    #[inline]
    fn to_tree_address(&self) -> TreeAddress {
        (*self).to_owned()
    }

    fn to_tree_address_then(&self, then: TreeAddress) -> TreeAddress {
        match *self {
            TreeAddress::Here                                                   => then,
            TreeAddress::ChildAtIndex(ref index, ref old_then)                  => TreeAddress::ChildAtIndex(*index, Box::new((*old_then).to_tree_address_then(then))),
            TreeAddress::ChildWithTag(ref tag, ref old_then)                    => TreeAddress::ChildWithTag((*tag).to_owned(), Box::new((*old_then).to_tree_address_then(then))),
            TreeAddress::ChildWithIndexedTag(ref tag, ref index, ref old_then)  => TreeAddress::ChildWithIndexedTag((*tag).to_owned(), *index, Box::new((*old_then).to_tree_address_then(then)))
        }
    }
}

impl<TFirst: ToTreeAddress, TSecond: ToTreeAddress> ToTreeAddress for (TFirst, TSecond) {
    #[inline]
    fn to_tree_address(&self) -> TreeAddress {
        let (ref first, ref second) = *self;

        first.to_tree_address_then(second.to_tree_address())
    }

    #[inline]
    fn to_tree_address_then(&self, then: TreeAddress) -> TreeAddress {
        self.to_tree_address().to_tree_address_then(then)
    }
}

impl<TFirst: ToTreeAddress, TSecond: ToTreeAddress> ToTreeAddress for Addr<TFirst, TSecond> {
    #[inline]
    fn to_tree_address(&self) -> TreeAddress {
        let Addr(ref first, ref second) = *self;

        first.to_tree_address_then(second.to_tree_address())
    }

    #[inline]
    fn to_tree_address_then(&self, then: TreeAddress) -> TreeAddress {
        self.to_tree_address().to_tree_address_then(then)
    }
}

impl<TFirst: ToTreeAddress, TSecond: ToTreeAddress> TreeNodeIndex for Addr<TFirst, TSecond> {
    #[inline]
    fn lookup_index(&self, parent_node: &Rc<TreeNode>) -> Option<Rc<TreeNode>> {
        let Addr(ref first, ref second) = *self;

        first.to_tree_address_then(second.to_tree_address()).lookup_index(parent_node)
    }
}

#[cfg(test)]
mod treeaddress_test {
    #[macro_use]
    use super::super::super::tree::*;

    #[test]
    fn lookup_here() {
        let someTree = tree!("Here", "There", "Everywhere");

        assert!(someTree.get_child_ref_at(TreeAddress::Here).unwrap().get_tag() == "Here");
    }

    #[test]
    fn lookup_child() {
        let someTree = tree!("Here", "There", "Everywhere");

        assert!(someTree.get_child_ref_at(Addr(0, ())).unwrap().get_tag() == "There");
        assert!(someTree.get_child_ref_at(Addr(1, ())).unwrap().get_tag() == "Everywhere");
    }

    #[test]
    fn lookup_tag() {
        let someTree = tree!("Here", "There", "Everywhere");

        assert!(someTree.get_child_ref_at(Addr("There", ())).unwrap().get_tag() == "There");
        assert!(someTree.get_child_ref_at(Addr("Everywhere", ())).unwrap().get_tag() == "Everywhere");
    }

    #[test]
    fn lookup_indexed_tag() {
        let someTree = tree!("Here", ("Tag", "First"), ("Tag", "Second"));

        assert!(someTree.get_child_ref_at(Addr(TagIndex("Tag", 0), ())).unwrap().get_value().to_str("") == "First");
        assert!(someTree.get_child_ref_at(Addr(TagIndex("Tag", 1), ())).unwrap().get_value().to_str("") == "Second");
    }

    #[test]
    fn lookup_grandchild() {
        let someTree = tree!("Here", tree!("There", "Everywhere"));

        assert!(someTree.get_child_ref_at(Addr("There", (0, ()))).unwrap().get_tag() == "Everywhere");
    }
}
<|endoftext|>


<commit_before>extern crate rustbox;
extern crate regex;

use std::cmp::min;
use std::error::Error;
use self::rustbox::{Color, RustBox, Key};
use self::rustbox::Event::KeyEvent;
use self::regex::Regex;

// Error

// Screen Status
pub enum Status {
    Selected(String),
    Escaped,
    Continue,
    Quit,
    Error,
}

trait Print {
    fn print_line(&self, y: usize, item: &str, fg: Color, bg: Color);
    fn print_lines(&self, item: &str, fg: Color, bg: Color);
}

impl Print for RustBox {

    fn print_line(&self, y: usize, item: &str, fg: Color, bg: Color) {
        for x in 0..(self.width()) {
            let ch = item.chars().nth(x).unwrap_or(' ');
            self.print_char(x, y, rustbox::RB_NORMAL, fg, bg, ch);
        }
    }

    fn print_lines(&self, item: &str, fg: Color, bg: Color) {

        for(n, line) in item.split("\n").enumerate() {
            self.print_line(n, line, fg, bg);
        }
    }
}

pub struct Screen {
    body:     String,
    lines:    Vec<String>,
    prompt:   String,
    // offset: usize,
    y_offset: usize,
    filtered: Vec<String>,
    query:    String,
    cursor:   usize,
    rustbox:  RustBox
}

impl Screen {

    pub fn new() -> Screen {

        let rustbox = match RustBox::init(Default::default()) {
            Result::Ok(v) => v,
            Result::Err(e) => panic!("{}", e),
        };

        Screen {
            body: String::new(),
            lines: vec!(),
            filtered: vec!(),
            prompt: "🍓  ".to_owned(),
            y_offset: 1,
            query: String::new(),
            cursor: 0,
            // offset: 0,
            rustbox: rustbox
        }
    }

    pub fn update_screen(&mut self, body: &str, lines: &Vec<String>) {
        self.y_offset = body.lines().count() + 1;
        self.body = body.to_string();
        self.cursor = 0;
        self.query = String::new();
        self.lines = lines.to_owned();
        self.filtered = self.lines.clone();
    }

    pub fn render(&self, item: &str) -> Status {

        self.rustbox.clear();

        self.rustbox.print_lines(item, Color::Blue, Color::Black);

        self.rustbox.present();

        match self.rustbox.poll_event(false) {

            Ok(KeyEvent(Key::Char('q'))) => Status::Quit,
            _ => Status::Escaped
        }
    }

    pub fn select_line(&mut self) -> Status {

        loop {

            self.render_items();

            match self.rustbox.poll_event(false) {
                Err(err) => panic!("{:?}", err),
                Ok(event) => match self.handle_event(event) {
                    Ok(Status::Selected(s)) => return Status::Selected(s),
                    Ok(Status::Quit) => return Status::Quit,
                    _ => (),
                }
            }
        }
    }

    fn handle_event(&mut self, event: rustbox::Event) -> Result<Status, Box<Error>> {

        match event {
            KeyEvent(Key::Enter)     => Ok(Status::Selected(self.filtered[self.cursor].to_owned())),
            KeyEvent(Key::Esc)       => Ok(Status::Escaped),
            KeyEvent(Key::Char('q')) => Ok(Status::Quit),
            KeyEvent(Key::Char(c))   => self.append_query(c).and(Ok(Status::Continue)),
            KeyEvent(Key::Backspace) => self.remove_query().and(Ok(Status::Continue)),
            KeyEvent(Key::Up) |
            KeyEvent(Key::Ctrl('p')) => {
                self.cursor_up();
                Ok(Status::Continue)
            },
            KeyEvent(Key::Down) |
            KeyEvent(Key::Ctrl('n')) => {
                self.cursor_down();
                Ok(Status::Continue)
            },
            _ => Ok(Status::Continue),
        }
    }

    fn append_query(&mut self, c: char) -> Result<(), Box<Error>> {

        self.query.push(c);
        self.apply_filter()
    }

    fn remove_query(&mut self) -> Result<(), Box<Error>> {

        if self.query.is_empty() {
            return Ok(());
        }

        let idx = self.query.len() - 1;
        self.query.remove(idx);
        self.apply_filter()
    }

    fn apply_filter(&mut self) -> Result<(), Box<Error>> {
        self.filtered = if self.query.len() == 0 {
            self.lines.clone()
        } else {
            let re = try!(Regex::new(self.query.as_str()));
            self.lines.iter().filter(|&input| re.is_match(input)).cloned().collect()
        };

        self.cursor = 0;

        Ok(())
    }

    fn cursor_up(&mut self) {

        if self.cursor != 0 { self.cursor -= 1; }
    }

    fn cursor_down(&mut self) {

        let height = self.rustbox.height();

        self.cursor = min(
            (self.cursor + 1),
            min(
                (self.filtered.len() - 1),
                (height - 1)
            )
        );
    }

    fn render_items(&self) {

        self.rustbox.clear();

        for(y, item) in self.filtered.iter().enumerate() {
            if y == self.cursor {
                self.rustbox.print_line(y + self.y_offset, &format!("[{0}]: {1}", y, &item), Color::Black, Color::Green);
            } else {
                self.rustbox.print_line(y + self.y_offset, &format!("[{0}]: {1}", y, &item), Color::Blue, Color::Black);
            }
        }

        // print query line and move the cursor to end.
        let query_str = format!("{}{}", self.prompt, self.query);
        self.rustbox.print_lines(&self.body, Color::Green, Color::Black);
        self.rustbox.print_line(self.y_offset - 1, &query_str, Color::Blue, Color::Black);
        self.rustbox.present();
    }

}

<commit_msg>Fold string if line length that longer than window width<commit_after>extern crate rustbox;
extern crate regex;

use std::cmp::min;
use std::error::Error;
use self::rustbox::{Color, RustBox, Key};
use self::rustbox::Event::KeyEvent;
use self::regex::Regex;

// Error

// Screen Status
pub enum Status {
    Selected(String),
    Escaped,
    Continue,
    Quit,
    Error,
}

trait Print {
    fn print_line(&self, y: usize, item: &str, fg: Color, bg: Color);
    fn print_lines(&self, item: &str, fg: Color, bg: Color);
}

impl Print for RustBox {

    fn print_line(&self, y: usize, item: &str, fg: Color, bg: Color) {
        for x in 0..(self.width()) {
            let ch = item.chars().nth(x).unwrap_or(' ');
            self.print_char(x, y, rustbox::RB_NORMAL, fg, bg, ch);
        }
    }

    fn print_lines(&self, item: &str, fg: Color, bg: Color) {

        let mut cursor = 0;

        for line in item.split("\n") {

            // fold string if line lingth longer than window widht
            if line.chars().count() > self.width() {

                let (first, last) = line.split_at(self.width());
                self.print_line(cursor,    first, fg, bg);
                self.print_line(cursor + 1, last, fg, bg);
                cursor += 2;
                continue;

            }

            self.print_line(cursor, line, fg, bg);
            cursor += 1;
        }
    }
}

pub struct Screen {
    body:     String,
    lines:    Vec<String>,
    prompt:   String,
    // offset: usize,
    y_offset: usize,
    filtered: Vec<String>,
    query:    String,
    cursor:   usize,
    rustbox:  RustBox
}

impl Screen {

    pub fn new() -> Screen {

        let rustbox = match RustBox::init(Default::default()) {
            Result::Ok(v) => v,
            Result::Err(e) => panic!("{}", e),
        };

        Screen {
            body: String::new(),
            lines: vec!(),
            filtered: vec!(),
            prompt: "🍓  ".to_owned(),
            y_offset: 1,
            query: String::new(),
            cursor: 0,
            // offset: 0,
            rustbox: rustbox
        }
    }

    pub fn update_screen(&mut self, body: &str, lines: &Vec<String>) {
        self.y_offset = body.lines().count() + 1;
        self.body = body.to_string();
        self.cursor = 0;
        self.query = String::new();
        self.lines = lines.to_owned();
        self.filtered = self.lines.clone();
    }

    pub fn render(&self, item: &str) -> Status {

        self.rustbox.clear();

        self.rustbox.print_lines(item, Color::Blue, Color::Black);

        self.rustbox.present();

        match self.rustbox.poll_event(false) {

            Ok(KeyEvent(Key::Char('q'))) => Status::Quit,
            _ => Status::Escaped
        }
    }

    pub fn select_line(&mut self) -> Status {

        loop {

            self.render_items();

            match self.rustbox.poll_event(false) {
                Err(err) => panic!("{:?}", err),
                Ok(event) => match self.handle_event(event) {
                    Ok(Status::Selected(s)) => return Status::Selected(s),
                    Ok(Status::Quit) => return Status::Quit,
                    _ => (),
                }
            }
        }
    }

    fn handle_event(&mut self, event: rustbox::Event) -> Result<Status, Box<Error>> {

        match event {
            KeyEvent(Key::Enter)     => Ok(Status::Selected(self.filtered[self.cursor].to_owned())),
            KeyEvent(Key::Esc)       => Ok(Status::Escaped),
            KeyEvent(Key::Char('q')) => Ok(Status::Quit),
            KeyEvent(Key::Char(c))   => self.append_query(c).and(Ok(Status::Continue)),
            KeyEvent(Key::Backspace) => self.remove_query().and(Ok(Status::Continue)),
            KeyEvent(Key::Up) |
            KeyEvent(Key::Ctrl('p')) => {
                self.cursor_up();
                Ok(Status::Continue)
            },
            KeyEvent(Key::Down) |
            KeyEvent(Key::Ctrl('n')) => {
                self.cursor_down();
                Ok(Status::Continue)
            },
            _ => Ok(Status::Continue),
        }
    }

    fn append_query(&mut self, c: char) -> Result<(), Box<Error>> {

        self.query.push(c);
        self.apply_filter()
    }

    fn remove_query(&mut self) -> Result<(), Box<Error>> {

        if self.query.is_empty() {
            return Ok(());
        }

        let idx = self.query.len() - 1;
        self.query.remove(idx);
        self.apply_filter()
    }

    fn apply_filter(&mut self) -> Result<(), Box<Error>> {
        self.filtered = if self.query.len() == 0 {
            self.lines.clone()
        } else {
            let re = try!(Regex::new(self.query.as_str()));
            self.lines.iter().filter(|&input| re.is_match(input)).cloned().collect()
        };

        self.cursor = 0;

        Ok(())
    }

    fn cursor_up(&mut self) {

        if self.cursor != 0 { self.cursor -= 1; }
    }

    fn cursor_down(&mut self) {

        let height = self.rustbox.height();

        self.cursor = min(
            (self.cursor + 1),
            min(
                (self.filtered.len() - 1),
                (height - 1)
            )
        );
    }

    fn render_items(&self) {

        self.rustbox.clear();

        for(y, item) in self.filtered.iter().enumerate() {
            if y == self.cursor {
                self.rustbox.print_line(y + self.y_offset, &format!("[{0}]: {1}", y, &item), Color::Black, Color::Green);
            } else {
                self.rustbox.print_line(y + self.y_offset, &format!("[{0}]: {1}", y, &item), Color::Blue, Color::Black);
            }
        }

        // print query line and move the cursor to end.
        let query_str = format!("{}{}", self.prompt, self.query);
        self.rustbox.print_lines(&self.body, Color::Green, Color::Black);
        self.rustbox.print_line(self.y_offset - 1, &query_str, Color::Blue, Color::Black);
        self.rustbox.present();
    }

}

<|endoftext|>


<commit_before>use std::path::*;
use std::io::{Result, Write};

use analysis::rust_type::AsStr;
use env::Env;
use file_saver::*;
use library;
use nameutil::*;
use super::ffi_type::*;
use super::statics;
use super::super::general;

pub fn generate(env: &Env) {
    println!("generating sys for {}", env.config.library_name);

    let path =  PathBuf::from(&env.config.target_path)
        .join(file_name_sys(&env.config.library_name, "lib"));
    println!("Generating file {:?}", path);

    save_to_file(path, &mut |w| generate_funcs(w, env));
}

fn generate_funcs<W: Write>(w: &mut W, env: &Env) -> Result<()>{
    try!(general::start_comments(w, &env.config));

    try!(statics::generate(w));

    let ns_id = library::MAIN_NAMESPACE;
    let ns = env.library.namespace(ns_id);

    try!(writeln!(w, ""));
    try!(writeln!(w, "extern \"C\" {{"));
    try!(generate_classes_funcs(w, env, ns_id, ns));

    //TODO: other functions
    try!(writeln!(w, "\n}}"));

    Ok(())
}
fn generate_classes_funcs<W: Write>(w: &mut W, env: &Env, ns_id: u16, ns:&library::Namespace) -> Result<()> {
    let mut vec: Vec<(library::TypeId, &library::Class)> = Vec::with_capacity(ns.types.len());
    for id in 0..ns.types.len() {
        let tid = library::TypeId { ns_id: ns_id, id: id as u32 };
        if let &library::Type::Class(ref klass) = env.library.type_(tid) {
            vec.push((tid, klass));
        }
    }
    vec.sort_by(|&(_, klass1), &(_, klass2)| klass1.glib_type_name.cmp(&klass2.glib_type_name));

    for (_, ref klass) in vec {
        try!(generate_class_funcs(w, env, klass));
    }

    Ok(())
}

fn generate_class_funcs<W: Write>(w: &mut W, env: &Env, klass: &library::Class) -> Result<()> {
    try!(writeln!(w, ""));
    try!(writeln!(w, "    //========================================================================="));
    try!(writeln!(w, "    // {}", klass.glib_type_name));
    try!(writeln!(w, "    //========================================================================="));
    try!(writeln!(w, "    pub fn {:<36}() -> GType;", klass.glib_get_type));

    for func in &klass.functions {
        let decl = function_declaration(env, func);
        try!(writeln!(w, "    {}", decl));
    }

    Ok(())
}

fn function_declaration(env: &Env, func: &library::Function) -> String {
    let (mut commented, ret_str) = function_return_value(env, func);

    let mut parameter_strs: Vec<String> = Vec::new();
    for par in &func.parameters {
        let (c, par_str) = function_parameter(env, par);
        parameter_strs.push(par_str);
        if c { commented = true; }
    }

    let commented_str = if commented { "//" } else { "" };
    format!("{}pub fn {:<36}({}){};", commented_str, func.c_identifier,
        parameter_strs.connect(", "), ret_str)
}

fn function_return_value(env: &Env, func: &library::Function) -> (bool, String) {
    if func.ret.typ == Default::default() { return (false, String::new()) }
    let ffi_type = ffi_type(env, func.ret.typ);
    let commented = ffi_type.is_err();
    (commented, format!(" -> {}", ffi_type.as_str()))
}

fn function_parameter(env: &Env, par: &library::Parameter) -> (bool, String) {
    let ffi_type = ffi_type(env, par.typ);
    let commented = ffi_type.is_err();
    (commented, format!("{}: {}", general::fix_parameter_name(&par.name), ffi_type.as_str()))
}
<commit_msg>Extract prepare_classes from generate_classes_funcs<commit_after>use std::path::*;
use std::io::{Result, Write};

use analysis::rust_type::AsStr;
use env::Env;
use file_saver::*;
use library;
use nameutil::*;
use super::ffi_type::*;
use super::statics;
use super::super::general;

pub fn generate(env: &Env) {
    println!("generating sys for {}", env.config.library_name);

    let path =  PathBuf::from(&env.config.target_path)
        .join(file_name_sys(&env.config.library_name, "lib"));
    println!("Generating file {:?}", path);

    save_to_file(path, &mut |w| generate_funcs(w, env));
}

fn generate_funcs<W: Write>(w: &mut W, env: &Env) -> Result<()>{
    try!(general::start_comments(w, &env.config));

    try!(statics::generate(w));

    let ns_id = library::MAIN_NAMESPACE;
    let classes = prepare_classes(env, ns_id);

    try!(writeln!(w, ""));
    try!(writeln!(w, "extern \"C\" {{"));
    try!(generate_classes_funcs(w, env, classes));

    //TODO: other functions
    try!(writeln!(w, "\n}}"));

    Ok(())
}

fn prepare_classes(env: &Env, ns_id: u16) -> Vec<&library::Class> {
    let ns = env.library.namespace(ns_id);
    let mut vec: Vec<&library::Class> = Vec::with_capacity(ns.types.len());
    for id in 0..ns.types.len() {
        let tid = library::TypeId { ns_id: ns_id, id: id as u32 };
        if let &library::Type::Class(ref klass) = env.library.type_(tid) {
            vec.push(klass);
        }
    }
    vec.sort_by(|ref klass1, ref klass2| klass1.glib_type_name.cmp(&klass2.glib_type_name));
    vec
}

fn generate_classes_funcs<W: Write>(w: &mut W, env: &Env, classes: Vec<&library::Class>) -> Result<()> {
    for klass in classes {
        try!(generate_class_funcs(w, env, klass));
    }

    Ok(())
}

fn generate_class_funcs<W: Write>(w: &mut W, env: &Env, klass: &library::Class) -> Result<()> {
    try!(writeln!(w, ""));
    try!(writeln!(w, "    //========================================================================="));
    try!(writeln!(w, "    // {}", klass.glib_type_name));
    try!(writeln!(w, "    //========================================================================="));
    try!(writeln!(w, "    pub fn {:<36}() -> GType;", klass.glib_get_type));

    for func in &klass.functions {
        let decl = function_declaration(env, func);
        try!(writeln!(w, "    {}", decl));
    }

    Ok(())
}

fn function_declaration(env: &Env, func: &library::Function) -> String {
    let (mut commented, ret_str) = function_return_value(env, func);

    let mut parameter_strs: Vec<String> = Vec::new();
    for par in &func.parameters {
        let (c, par_str) = function_parameter(env, par);
        parameter_strs.push(par_str);
        if c { commented = true; }
    }

    let commented_str = if commented { "//" } else { "" };
    format!("{}pub fn {:<36}({}){};", commented_str, func.c_identifier,
        parameter_strs.connect(", "), ret_str)
}

fn function_return_value(env: &Env, func: &library::Function) -> (bool, String) {
    if func.ret.typ == Default::default() { return (false, String::new()) }
    let ffi_type = ffi_type(env, func.ret.typ);
    let commented = ffi_type.is_err();
    (commented, format!(" -> {}", ffi_type.as_str()))
}

fn function_parameter(env: &Env, par: &library::Parameter) -> (bool, String) {
    let ffi_type = ffi_type(env, par.typ);
    let commented = ffi_type.is_err();
    (commented, format!("{}: {}", general::fix_parameter_name(&par.name), ffi_type.as_str()))
}
<|endoftext|>


<commit_before>extern crate tempfile;
extern crate zmq;

use std::collections::HashMap;
use std::io::Read;
use std::sync::Arc;
use std::sync::Mutex;
use time;

use backend;
use dispatcher::server;
use helpers;
use helpers::{NewTaskMessage, TaskProgress, TaskReport, TaskStatus};
use models::Service;
use std::error::Error;
use zmq::SNDMORE;

/// Specifies the binding and operation parameters for a ZMQ ventilator component
pub struct Ventilator {
  /// port to listen on
  pub port: usize,
  /// the size of the dispatch queue
  /// (also the batch size for Task store queue requests)
  pub queue_size: usize,
  /// size of an individual message chunk sent via zeromq
  /// (keep this small to avoid large RAM use, increase to reduce network bandwidth)
  pub message_size: usize,
  /// address for the Task store postgres endpoint
  pub backend_address: String,
}

impl Ventilator {
  /// Starts a new dispatch `Server` (ZMQ Ventilator), to serve tasks to processing workers.
  /// The ventilator shares state with other manager threads via queues for tasks in progress,
  /// as well as a queue for completed tasks pending persisting to disk.
  /// A job limit can be provided as a termination condition for the sink server.
  pub fn start(
    &self,
    services_arc: Arc<Mutex<HashMap<String, Option<Service>>>>,
    progress_queue_arc: Arc<Mutex<HashMap<i64, TaskProgress>>>,
    done_queue_arc: Arc<Mutex<Vec<TaskReport>>>,
    job_limit: Option<usize>,
  ) -> Result<(), Box<Error>>
  {
    // We have a Ventilator-exclusive "queues" stack for tasks to be dispatched
    let mut queues: HashMap<String, Vec<TaskProgress>> = HashMap::new();
    // Assuming this is the only And tidy up the postgres tasks:
    let backend = backend::from_address(&self.backend_address);
    backend.clear_limbo_tasks()?;
    // Ok, let's bind to a port and start broadcasting
    let context = zmq::Context::new();
    let ventilator = context.socket(zmq::ROUTER)?;
    let port_str = self.port.to_string();
    let address = "tcp://*:".to_string() + &port_str;
    assert!(ventilator.bind(&address).is_ok());
    let mut source_job_count: usize = 0;

    loop {
      let mut msg = zmq::Message::new()?;
      let mut identity = zmq::Message::new()?;
      ventilator.recv(&mut identity, 0)?;
      ventilator.recv(&mut msg, 0)?;
      let service_name = msg.as_str().unwrap_or_default().to_string();
      // println!("Task requested for service: {}", service_name.clone());
      let request_time = time::get_time();
      source_job_count += 1;

      let mut dispatched_task_opt: Option<TaskProgress> = None;
      // Requests for unknown service names will be silently ignored.
      if let Some(service) = server::get_sync_service(&service_name, &services_arc, &backend) {
        if !queues.contains_key(&service_name) {
          queues.insert(service_name.clone(), Vec::new());
        }
        let mut task_queue: &mut Vec<TaskProgress> = queues
          .get_mut(&service_name)
          .unwrap_or_else(|| panic!("Could not obtain queue mutex lock in main ventilator loop"));
        if task_queue.is_empty() {
          println!(
            "No tasks in task queue, fetching up to {:?} more from backend...",
            self.queue_size
          );
          // Refetch a new batch of tasks
          let now = time::get_time().sec;
          let fetched_tasks = backend
            .fetch_tasks(&service, self.queue_size)
            .unwrap_or(Vec::new());
          task_queue.extend(fetched_tasks.into_iter().map(|task| TaskProgress {
            task,
            created_at: now,
            retries: 0,
          }));

          // This is a good time to also take care that none of the old tasks are dead in the
          // progress queue since the re-fetch happens infrequently, and directly
          // implies the progress queue will grow
          let expired_tasks = server::timeout_progress_tasks(&progress_queue_arc);
          for expired_t in expired_tasks {
            if expired_t.retries > 1 {
              // Too many retries, mark as fatal failure
              server::push_done_queue(
                &done_queue_arc,
                TaskReport {
                  task: expired_t.task.clone(),
                  status: TaskStatus::Fatal,
                  messages: vec![NewTaskMessage::new(
                    expired_t.task.id,
                    "fatal",
                    "cortex".to_string(),
                    "never_completed_with_retries".to_string(),
                    String::new(),
                  )],
                },
              );
            } else {
              // We can still retry, re-add to the dispatch queue
              task_queue.push(TaskProgress {
                task: expired_t.task,
                created_at: expired_t.created_at,
                retries: expired_t.retries + 1,
              });
            }
          }
        }
        ventilator.send_msg(identity, SNDMORE)?;
        if let Some(current_task_progress) = task_queue.pop() {
          dispatched_task_opt = Some(current_task_progress.clone());

          let current_task = current_task_progress.task;
          let taskid = current_task.id;
          let serviceid = current_task.service_id;

          ventilator.send_str(&taskid.to_string(), SNDMORE)?;
          if serviceid == 1 {
            // No payload needed for init
            ventilator.send(&[], 0)?;
          } else {
            // Regular services fetch the task payload and transfer it to the worker
            let file_opt = helpers::prepare_input_stream(&current_task);
            if file_opt.is_ok() {
              let mut file = file_opt?;
              let mut total_outgoing: usize = 0;
              loop {
                // Stream input data via zmq
                let mut data = vec![0; self.message_size];
                let size = file.read(&mut data)?;
                total_outgoing += size;
                data.truncate(size);

                if size < self.message_size {
                  // If exhausted, send the last frame
                  ventilator.send(&data, 0)?;
                  // And terminate
                  break;
                } else {
                  // If more to go, send the frame and indicate there's more to come
                  ventilator.send(&data, SNDMORE)?;
                }
              }
              let responded_time = time::get_time();
              let request_duration = (responded_time - request_time).num_milliseconds();
              println!(
                "Source job {}, message size: {}, took {}ms.",
                source_job_count, total_outgoing, request_duration
              );
            } else {
              ventilator.send(&[], 0)?;
            }
          }
        } else {
          println!("No jobs in queue, sent mock task reply.");
          ventilator.send_str("0", SNDMORE)?;
          ventilator.send(&[], 0)?;
        }
      }
      // Record that a task has been dispatched in the progress queue
      if let Some(dispatched_task) = dispatched_task_opt {
        server::push_progress_task(&progress_queue_arc, dispatched_task);
      }
      if let Some(limit_number) = job_limit {
        if source_job_count >= limit_number {
          println!(
            "Manager job limit of {:?} reached, terminating Ventilator thread...",
            limit_number
          );
          break;
        }
      }
    }
    Ok(())
  }
}
<commit_msg>name the service for which the queue is empty<commit_after>extern crate tempfile;
extern crate zmq;

use std::collections::HashMap;
use std::io::Read;
use std::sync::Arc;
use std::sync::Mutex;
use time;

use backend;
use dispatcher::server;
use helpers;
use helpers::{NewTaskMessage, TaskProgress, TaskReport, TaskStatus};
use models::Service;
use std::error::Error;
use zmq::SNDMORE;

/// Specifies the binding and operation parameters for a ZMQ ventilator component
pub struct Ventilator {
  /// port to listen on
  pub port: usize,
  /// the size of the dispatch queue
  /// (also the batch size for Task store queue requests)
  pub queue_size: usize,
  /// size of an individual message chunk sent via zeromq
  /// (keep this small to avoid large RAM use, increase to reduce network bandwidth)
  pub message_size: usize,
  /// address for the Task store postgres endpoint
  pub backend_address: String,
}

impl Ventilator {
  /// Starts a new dispatch `Server` (ZMQ Ventilator), to serve tasks to processing workers.
  /// The ventilator shares state with other manager threads via queues for tasks in progress,
  /// as well as a queue for completed tasks pending persisting to disk.
  /// A job limit can be provided as a termination condition for the sink server.
  pub fn start(
    &self,
    services_arc: Arc<Mutex<HashMap<String, Option<Service>>>>,
    progress_queue_arc: Arc<Mutex<HashMap<i64, TaskProgress>>>,
    done_queue_arc: Arc<Mutex<Vec<TaskReport>>>,
    job_limit: Option<usize>,
  ) -> Result<(), Box<Error>>
  {
    // We have a Ventilator-exclusive "queues" stack for tasks to be dispatched
    let mut queues: HashMap<String, Vec<TaskProgress>> = HashMap::new();
    // Assuming this is the only And tidy up the postgres tasks:
    let backend = backend::from_address(&self.backend_address);
    backend.clear_limbo_tasks()?;
    // Ok, let's bind to a port and start broadcasting
    let context = zmq::Context::new();
    let ventilator = context.socket(zmq::ROUTER)?;
    let port_str = self.port.to_string();
    let address = "tcp://*:".to_string() + &port_str;
    assert!(ventilator.bind(&address).is_ok());
    let mut source_job_count: usize = 0;

    loop {
      let mut msg = zmq::Message::new()?;
      let mut identity = zmq::Message::new()?;
      ventilator.recv(&mut identity, 0)?;
      ventilator.recv(&mut msg, 0)?;
      let service_name = msg.as_str().unwrap_or_default().to_string();
      // println!("Task requested for service: {}", service_name.clone());
      let request_time = time::get_time();
      source_job_count += 1;

      let mut dispatched_task_opt: Option<TaskProgress> = None;
      // Requests for unknown service names will be silently ignored.
      if let Some(service) = server::get_sync_service(&service_name, &services_arc, &backend) {
        if !queues.contains_key(&service_name) {
          queues.insert(service_name.clone(), Vec::new());
        }
        let mut task_queue: &mut Vec<TaskProgress> = queues
          .get_mut(&service_name)
          .unwrap_or_else(|| panic!("Could not obtain queue mutex lock in main ventilator loop"));
        if task_queue.is_empty() {
          println!(
            "No tasks in task queue for service {:?}, fetching up to {:?} more from backend...",
            service_name, self.queue_size
          );
          // Refetch a new batch of tasks
          let now = time::get_time().sec;
          let fetched_tasks = backend
            .fetch_tasks(&service, self.queue_size)
            .unwrap_or(Vec::new());
          task_queue.extend(fetched_tasks.into_iter().map(|task| TaskProgress {
            task,
            created_at: now,
            retries: 0,
          }));

          // This is a good time to also take care that none of the old tasks are dead in the
          // progress queue since the re-fetch happens infrequently, and directly
          // implies the progress queue will grow
          let expired_tasks = server::timeout_progress_tasks(&progress_queue_arc);
          for expired_t in expired_tasks {
            if expired_t.retries > 1 {
              // Too many retries, mark as fatal failure
              server::push_done_queue(
                &done_queue_arc,
                TaskReport {
                  task: expired_t.task.clone(),
                  status: TaskStatus::Fatal,
                  messages: vec![NewTaskMessage::new(
                    expired_t.task.id,
                    "fatal",
                    "cortex".to_string(),
                    "never_completed_with_retries".to_string(),
                    String::new(),
                  )],
                },
              );
            } else {
              // We can still retry, re-add to the dispatch queue
              task_queue.push(TaskProgress {
                task: expired_t.task,
                created_at: expired_t.created_at,
                retries: expired_t.retries + 1,
              });
            }
          }
        }
        ventilator.send_msg(identity, SNDMORE)?;
        if let Some(current_task_progress) = task_queue.pop() {
          dispatched_task_opt = Some(current_task_progress.clone());

          let current_task = current_task_progress.task;
          let taskid = current_task.id;
          let serviceid = current_task.service_id;

          ventilator.send_str(&taskid.to_string(), SNDMORE)?;
          if serviceid == 1 {
            // No payload needed for init
            ventilator.send(&[], 0)?;
          } else {
            // Regular services fetch the task payload and transfer it to the worker
            let file_opt = helpers::prepare_input_stream(&current_task);
            if file_opt.is_ok() {
              let mut file = file_opt?;
              let mut total_outgoing: usize = 0;
              loop {
                // Stream input data via zmq
                let mut data = vec![0; self.message_size];
                let size = file.read(&mut data)?;
                total_outgoing += size;
                data.truncate(size);

                if size < self.message_size {
                  // If exhausted, send the last frame
                  ventilator.send(&data, 0)?;
                  // And terminate
                  break;
                } else {
                  // If more to go, send the frame and indicate there's more to come
                  ventilator.send(&data, SNDMORE)?;
                }
              }
              let responded_time = time::get_time();
              let request_duration = (responded_time - request_time).num_milliseconds();
              println!(
                "Source job {}, message size: {}, took {}ms.",
                source_job_count, total_outgoing, request_duration
              );
            } else {
              ventilator.send(&[], 0)?;
            }
          }
        } else {
          println!("No jobs in queue, sent mock task reply.");
          ventilator.send_str("0", SNDMORE)?;
          ventilator.send(&[], 0)?;
        }
      }
      // Record that a task has been dispatched in the progress queue
      if let Some(dispatched_task) = dispatched_task_opt {
        server::push_progress_task(&progress_queue_arc, dispatched_task);
      }
      if let Some(limit_number) = job_limit {
        if source_job_count >= limit_number {
          println!(
            "Manager job limit of {:?} reached, terminating Ventilator thread...",
            limit_number
          );
          break;
        }
      }
    }
    Ok(())
  }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 William (B.J.) Snow Orvis
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! The Mandelbrot fractal is an iterated function system defined over the
//! complex number function:
//! ```
//! f(z) = z^2 + c
//! ```
//! A given point, which corresponds to `c`, belongs to the Mandelbrot set if
//! iterating on f(0) converges. That is, f(0), f(f(0)), f(f(f(0))), ...
//! converges. Alternately, if it diverges (trends towards a value of ∞ ), then
//! a point `c` is not in the Mandelbrot set.

use super::*;
use super::super::geometry;

pub struct Mandelbrot {
    max_iters: u64,
    power: u64,
}

impl Mandelbrot {
    /// Creates a specification for a member of the mandelbrot family of fractals.
    ///
    /// `max_iterations` specifies the cutoff iteration for deciding whether a complex number
    /// escapes or has converged.
    ///
    /// `power` specifies the exponent used in the mandelbrot equation to generalize it into a
    /// [Multibrot set](https://en.wikipedia.org/wiki/Multibrot_set). The traditional mandelbrot
    /// fractal has an exponent of 2, but this allows for the exploration of fractals with an
    /// exponent of 3, 4, etc.
    pub fn new(max_iterations: u64, power: u64) -> Mandelbrot {
        Mandelbrot {
            max_iters: max_iterations,
            power: power,
        }
    }
}

impl EscapeTime for Mandelbrot {
    fn max_iterations(&self) -> u64 {
        self.max_iters
    }

    fn default_view_area(&self) -> [Complex64; 2] {
        [Complex64::new(-2.0, 1.0), Complex64::new(1.0, -1.0)]
    }

    fn iterate(&self, c: Complex64, z: Complex64) -> Complex64 {
        geometry::cpow(z, self.power) + c
    }
}

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

    #[test]
    fn test_test_point() {
        let mb = Mandelbrot::new(100);
        assert!(mb.test_point(Complex64::new(0.0, 0.0)).0);
        assert!(mb.test_point(Complex64::new(-1.0, 0.0)).0);
        assert!(!mb.test_point(Complex64::new(1.0, 0.0)).0);
        assert!(!mb.test_point(Complex64::new(-0.8, 0.35)).0);
    }
}
<commit_msg>Fixing a test case for mandelbrot<commit_after>// Copyright (c) 2016 William (B.J.) Snow Orvis
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! The Mandelbrot fractal is an iterated function system defined over the
//! complex number function:
//! ```
//! f(z) = z^2 + c
//! ```
//! A given point, which corresponds to `c`, belongs to the Mandelbrot set if
//! iterating on f(0) converges. That is, f(0), f(f(0)), f(f(f(0))), ...
//! converges. Alternately, if it diverges (trends towards a value of ∞ ), then
//! a point `c` is not in the Mandelbrot set.

use super::*;
use super::super::geometry;

pub struct Mandelbrot {
    max_iters: u64,
    power: u64,
}

impl Mandelbrot {
    /// Creates a specification for a member of the mandelbrot family of fractals.
    ///
    /// `max_iterations` specifies the cutoff iteration for deciding whether a complex number
    /// escapes or has converged.
    ///
    /// `power` specifies the exponent used in the mandelbrot equation to generalize it into a
    /// [Multibrot set](https://en.wikipedia.org/wiki/Multibrot_set). The traditional mandelbrot
    /// fractal has an exponent of 2, but this allows for the exploration of fractals with an
    /// exponent of 3, 4, etc.
    pub fn new(max_iterations: u64, power: u64) -> Mandelbrot {
        Mandelbrot {
            max_iters: max_iterations,
            power: power,
        }
    }
}

impl EscapeTime for Mandelbrot {
    fn max_iterations(&self) -> u64 {
        self.max_iters
    }

    fn default_view_area(&self) -> [Complex64; 2] {
        [Complex64::new(-2.0, 1.0), Complex64::new(1.0, -1.0)]
    }

    fn iterate(&self, c: Complex64, z: Complex64) -> Complex64 {
        geometry::cpow(z, self.power) + c
    }
}

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

    #[test]
    fn test_test_point() {
        let mb = Mandelbrot::new(100, 2);
        assert!(mb.test_point(Complex64::new(0.0, 0.0)).0);
        assert!(mb.test_point(Complex64::new(-1.0, 0.0)).0);
        assert!(!mb.test_point(Complex64::new(1.0, 0.0)).0);
        assert!(!mb.test_point(Complex64::new(-0.8, 0.35)).0);
    }
}
<|endoftext|>


<commit_before>extern crate futures;
extern crate env_logger;
extern crate futuremio;
extern crate ssl;

#[macro_use]
extern crate cfg_if;

use std::io::{Write, ErrorKind, Error};
use std::net::ToSocketAddrs;

use futures::Future;
use futures::stream::Stream;
use futures::io::{self, Ready};

macro_rules! t {
    ($e:expr) => (match $e {
        Ok(e) => e,
        Err(e) => panic!("{} failed with {:?}", stringify!($e), e),
    })
}

cfg_if! {
    if #[cfg(any(feature = "force-openssl",
                 all(not(target_os = "macos"),
                     not(target_os = "windows"))))] {
        extern crate openssl;

        use openssl::ssl as ossl;

        fn assert_bad_hostname_error(err: &Error) {
            let err = err.get_ref().unwrap();
            let errs = match *err.downcast_ref::<ossl::Error>().unwrap() {
                ossl::Error::Ssl(ref v) => v,
                ref e => panic!("not an ssl eror: {:?}", e),
            };
            assert!(errs.iter().any(|e| {
                e.reason() == "certificate verify failed"
            }), "bad errors: {:?}", errs);
        }
    } else if #[cfg(target_os = "macos")] {
        extern crate security_framework;

        use security_framework::base::Error as SfError;

        fn assert_bad_hostname_error(err: &Error) {
            let err = err.get_ref().unwrap();
            let err = err.downcast_ref::<SfError>().unwrap();
            assert_eq!(err.message().unwrap(), "invalid certificate chain");
        }
    } else {
    }
}

#[test]
fn fetch_google() {
    drop(env_logger::init());

    // First up, resolve google.com
    let addr = t!("google.com:443".to_socket_addrs()).next().unwrap();

    // Create an event loop and connect a socket to our resolved address.c
    let mut l = t!(futuremio::Loop::new());
    let client = l.handle().tcp_connect(&addr);

    // Send off the request by first negotiating an SSL handshake, then writing
    // of our request, then flushing, then finally read off the response.
    let data = client.and_then(move |socket| {
        t!(ssl::ClientContext::new()).handshake("google.com", socket)
    }).and_then(|socket| {
        write_all(socket, b"GET / HTTP/1.0\r\n\r\n")
    }).and_then(|socket| {
        io::flush(socket)
    }).and_then(|socket| {
        io::read_to_end(socket, Vec::new())
    });

    let data = t!(l.run(data));
    assert!(data.starts_with(b"HTTP/1.0 200 OK"));
    assert!(data.ends_with(b""));
}

#[test]
fn wrong_hostname_error() {
    drop(env_logger::init());

    let addr = t!("google.com:443".to_socket_addrs()).next().unwrap();

    let mut l = t!(futuremio::Loop::new());
    let client = l.handle().tcp_connect(&addr);
    let data = client.and_then(move |socket| {
        t!(ssl::ClientContext::new()).handshake("rust-lang.org", socket)
    });

    let res = l.run(data);
    assert_bad_hostname_error(&res.err().unwrap());
}

fn write_all<W>(mut socket: W, mut data: &'static [u8])
                -> Box<Future<Item=W, Error=Error>>
    where W: Write + Stream<Item=Ready, Error=Error>,
{
    while data.len() > 0 {
        match socket.write(data) {
            Ok(n) => {
                println!("wrote: {}", n);
                data = &data[n..];
            }
            Err(ref e) if e.kind() == ErrorKind::WouldBlock => break,
            Err(e) => return futures::failed(e).boxed(),
        }
    }
    if data.len() == 0 {
        futures::finished(socket).boxed()
    } else {
        socket.into_future().map_err(|e| e.0).and_then(move |(_, w)| {
            write_all(w, data)
        }).boxed()
    }
}
<commit_msg>Better error message in wrong_hostname_error test<commit_after>extern crate futures;
extern crate env_logger;
extern crate futuremio;
extern crate ssl;

#[macro_use]
extern crate cfg_if;

use std::io::{Write, ErrorKind, Error};
use std::net::ToSocketAddrs;

use futures::Future;
use futures::stream::Stream;
use futures::io::{self, Ready};

macro_rules! t {
    ($e:expr) => (match $e {
        Ok(e) => e,
        Err(e) => panic!("{} failed with {:?}", stringify!($e), e),
    })
}

cfg_if! {
    if #[cfg(any(feature = "force-openssl",
                 all(not(target_os = "macos"),
                     not(target_os = "windows"))))] {
        extern crate openssl;

        use openssl::ssl as ossl;

        fn assert_bad_hostname_error(err: &Error) {
            let err = err.get_ref().unwrap();
            let errs = match *err.downcast_ref::<ossl::Error>().unwrap() {
                ossl::Error::Ssl(ref v) => v,
                ref e => panic!("not an ssl eror: {:?}", e),
            };
            assert!(errs.iter().any(|e| {
                e.reason() == "certificate verify failed"
            }), "bad errors: {:?}", errs);
        }
    } else if #[cfg(target_os = "macos")] {
        extern crate security_framework;

        use security_framework::base::Error as SfError;

        fn assert_bad_hostname_error(err: &Error) {
            let err = err.get_ref().unwrap();
            let err = err.downcast_ref::<SfError>().unwrap();
            assert_eq!(err.message().unwrap(), "invalid certificate chain");
        }
    } else {
    }
}

#[test]
fn fetch_google() {
    drop(env_logger::init());

    // First up, resolve google.com
    let addr = t!("google.com:443".to_socket_addrs()).next().unwrap();

    // Create an event loop and connect a socket to our resolved address.c
    let mut l = t!(futuremio::Loop::new());
    let client = l.handle().tcp_connect(&addr);

    // Send off the request by first negotiating an SSL handshake, then writing
    // of our request, then flushing, then finally read off the response.
    let data = client.and_then(move |socket| {
        t!(ssl::ClientContext::new()).handshake("google.com", socket)
    }).and_then(|socket| {
        write_all(socket, b"GET / HTTP/1.0\r\n\r\n")
    }).and_then(|socket| {
        io::flush(socket)
    }).and_then(|socket| {
        io::read_to_end(socket, Vec::new())
    });

    let data = t!(l.run(data));
    assert!(data.starts_with(b"HTTP/1.0 200 OK"));
    assert!(data.ends_with(b""));
}

#[test]
fn wrong_hostname_error() {
    drop(env_logger::init());

    let addr = t!("google.com:443".to_socket_addrs()).next().unwrap();

    let mut l = t!(futuremio::Loop::new());
    let client = l.handle().tcp_connect(&addr);
    let data = client.and_then(move |socket| {
        t!(ssl::ClientContext::new()).handshake("rust-lang.org", socket)
    });

    let res = l.run(data);
    assert!(res.is_err());
    assert_bad_hostname_error(&res.err().unwrap());
}

fn write_all<W>(mut socket: W, mut data: &'static [u8])
                -> Box<Future<Item=W, Error=Error>>
    where W: Write + Stream<Item=Ready, Error=Error>,
{
    while data.len() > 0 {
        match socket.write(data) {
            Ok(n) => {
                println!("wrote: {}", n);
                data = &data[n..];
            }
            Err(ref e) if e.kind() == ErrorKind::WouldBlock => break,
            Err(e) => return futures::failed(e).boxed(),
        }
    }
    if data.len() == 0 {
        futures::finished(socket).boxed()
    } else {
        socket.into_future().map_err(|e| e.0).and_then(move |(_, w)| {
            write_all(w, data)
        }).boxed()
    }
}
<|endoftext|>


<commit_before>#![feature(io)]

extern crate compiler;
extern crate argparse;
extern crate walkdir;
extern crate term;

use argparse::ArgumentParser;
use walkdir::WalkDir;
use std::process::Command;
use std::borrow::Borrow;

mod tool
{
    use super::test::Test;

    /// A constant.
    #[derive(Copy,Clone,Debug,PartialEq,Eq)]
    pub enum Constant
    {
        /// The path of the test that is being run.
        TestPath,
    }

    impl Constant
    {
        /// Maps a constant name to a constant.
        /// Returns `None` if no mapping exists.
        pub fn lookup(name: &str) -> Option<Constant> {
            match name {
                "file" => Some(Constant::TestPath),
                _ => None,
            }
        }
    }

    /// An argument to a tool.
    #[derive(Clone,Debug,PartialEq,Eq)]
    pub enum Argument
    {
        Normal(String),
        Substitute(Constant),
    }

    impl Argument
    {
        /// Parses an argument to a tool.
        ///
        /// If it is prefixed with `@`, then it will be taken
        /// as a constant substitution, otherwise it will
        /// be read verbatim as a tool argument.
        pub fn parse(string: String) -> Result<Self,String> {
            // check if we are parsing a substitution
            if string.chars().next().unwrap() == '@' {
                let name: String = string.chars().skip(1).collect();

                match Constant::lookup(&name) {
                    Some(constant) => Ok(Argument::Substitute(constant)),
                    None => Err(format!("constant does not exist: {}", name)),
                }
            } else { // it is a plain old argument
                Ok(Argument::Normal(string))
            }
        }

        pub fn resolve(&self, test: &Test) -> String {
            match *self {
                Argument::Normal(ref s) => s.clone(),
                Argument::Substitute(constant) => match constant {
                    Constant::TestPath => test.path.clone(),
                },
            }
        }
    }

    /// A tool invocation.
    #[derive(Clone,Debug,PartialEq,Eq)]
    pub struct Invocation
    {
        pub executable: String,
        pub arguments: Vec<Argument>,
    }

    impl Invocation
    {
        /// Parses a tool invocation.
        ///
        /// It is in the format:
        ///
        /// ``` bash
        /// <tool-name> [arg1] [arg2] ...
        /// ```
        pub fn parse<'a,I>(mut words: I) -> Result<Self,String>
            where I: Iterator<Item=&'a str> {
            let executable = match words.next() {
                Some(exec) => exec,
                None => return Err("no executable specified".into()),
            }.into();

            let mut arguments = Vec::new();

            for arg_str in words {
                let arg = try!(Argument::parse(arg_str.into()));
                arguments.push(arg);
            }

            Ok(Invocation {
                executable: executable,
                arguments: arguments,
            })
        }
    }
}

pub mod test
{
    use super::tool;
    use std;

    #[derive(Clone,Debug,PartialEq,Eq)]
    pub enum Directive
    {
        Run(tool::Invocation),
    }

    impl Directive
    {
        pub fn maybe_parse(string: String) -> Option<Result<Self,String>> {
            let directive_str = string.split_whitespace().next().unwrap();
            let inner_words = string.split_whitespace().skip(1);

            match directive_str {
                // FIXME: better message if we have 'RUN :'
                "RUN:" => {
                    let invocation = match tool::Invocation::parse(inner_words) {
                        Ok(i) => i,
                        Err(e) => return Some(Err(e)),
                    };

                    Some(Ok(Directive::Run(invocation)))
                },
                _ => {
                    if directive_str.ends_with(':') {
                        Some(Err(format!("directive '{}' not known", directive_str)))
                    } else {
                        None
                    }
                },
            }
        }
    }

    #[derive(Clone,Debug,PartialEq,Eq)]
    pub struct Test
    {
        pub path: String,
        pub directives: Vec<Directive>,
    }

    impl Test
    {
        pub fn is_empty(&self) -> bool {
            self.directives.is_empty()
        }
    }

    pub enum TestResultKind
    {
        Pass,
        Fail(String, String),
        Skip,
    }

    pub struct TestResult
    {
        pub path: String,
        pub kind: TestResultKind,
    }

    #[derive(Clone,Debug,PartialEq,Eq)]
    pub struct Context
    {
        pub exec_search_dirs: Vec<String>,
        pub tests: Vec<Test>,
    }

    impl Context
    {
        pub fn new() -> Self {
            Context {
                exec_search_dirs: Vec::new(),
                tests: Vec::new(),
            }
        }

        pub fn test(mut self, test: Test) -> Self {
            self.tests.push(test);
            self
        }

        pub fn add_search_dir(&mut self, dir: String) {
            self.exec_search_dirs.push(dir);
        }

        pub fn find_in_search_dir(&self, path: &str)
            -> Option<String> {
            for dir in self.exec_search_dirs.iter() {
                for entry in std::fs::read_dir(dir).unwrap() {
                    let entry = entry.unwrap();
                    let cur_path = entry.path();

                    if std::fs::metadata(&cur_path).unwrap().is_file() {
                        if cur_path.file_name().unwrap() == path {
                            return Some(cur_path.to_str().unwrap().to_owned());
                        }
                    }

                }
            }
            None
        }

        pub fn executable_path(&self, path: &str) -> String {
            match self.find_in_search_dir(path) {
                Some(p) => p,
                None => path.to_owned(),
            }
        }
    }
}

use test::{Test,Directive,TestResult,TestResultKind,Context};

fn main() {
    let mut files: Vec<String> = Vec::new();

    {
        let mut ap = ArgumentParser::new();
        ap.set_description("Runs tests");

        ap.refer(&mut files)
            .add_argument("files", argparse::List,
                          r#"Files to test"#);
        ap.parse_args_or_exit();
    }

    let paths: Vec<&str> = files.iter()
                                 .map(|s| s.borrow())
                                 .collect();

    if paths.is_empty() {
        util::abort("no filenames given")
    }

    let test_paths = find_tests(&paths);

    let mut context = test_paths.into_iter().fold(Context::new(), |c,file| {
        let test = read_test(&file).unwrap();
        c.test(test)
    });

    match util::tool_dir() {
        Some(dir) => context.add_search_dir(dir),
        None => print::warning("could not find tool directory"),
    }

    let results = run_tests(&context);

    for result in results.iter() {
        print_result(result)
    }
}

fn print_result(result: &TestResult) {
    match result.kind {
        TestResultKind::Pass => {
            print::success(format!("PASS :: {}", result.path));
        },
        TestResultKind::Skip => {
            print::line();
            print::warning(format!(
                "SKIP :: {} (test does not contain any directives)",
                     result.path));
            print::line();
        },
        TestResultKind::Fail(ref msg, ref desc) => {
            print::line();

            print::failure(format!("FAIL :: {}", result.path));
            print::text(msg.clone());

            // Only print stderr if there was output
            if !desc.is_empty() {
                print::line();
                print::text("stderr:");
                print::line();
                print::text(desc.clone());
            }

            print::line();
        },
    }
}

/// Recursively finds tests for the given paths.
fn find_tests(paths: &[&str]) -> Vec<String> {
    paths.iter().flat_map(|path| {
                    find_tests_in_path(path).into_iter()
                })
                .collect()
}

fn find_tests_in_path(path: &str) -> Vec<String> {
    let metadata = match std::fs::metadata(path) {
        Ok(meta) => meta,
        Err(e) => util::abort(format!("failed to open '{}': {}",
                                      path, e)),
    };

    if metadata.is_dir() {
        find_tests_in_dir(path)
    } else {
        vec![path.to_owned()]
    }
}

fn find_tests_in_dir(path: &str) -> Vec<String> {
    find_files_in_dir(path).into_iter()
                           .filter(|f| f.ends_with(".ir"))
                           .collect()
}

fn find_files_in_dir(path: &str) -> Vec<String> {
    let mut dir_tests = Vec::new();

    for entry in WalkDir::new(path) {
        let entry = entry.unwrap();

        // don't go into an infinite loop
        if entry.path().to_str().unwrap() == path {
            continue;
        }

        if entry.metadata().unwrap().is_file() {
            dir_tests.push(entry.path().to_str().unwrap().to_owned());
        }
    }

    dir_tests
}

fn read_test(path: &str) -> Result<Test,String> {
    // TODO: redundant indirection
    util::parse_test(path)
}

fn run_tests(context: &Context) -> Vec<TestResult> {
    context.tests.iter().map(|test| run_test(test, context)).collect()
}

fn run_test(test: &Test, context: &Context) -> TestResult {
    if test.is_empty() {
        println!("SKIP :: {} (it includes no test directives", test.path);
        return TestResult {
            path: test.path.clone(),
            kind: TestResultKind::Skip,
        }
    }

    for directive in test.directives.iter() {
        let kind = run_directive(directive, test, context);

        match kind {
            TestResultKind::Pass => continue,
            TestResultKind::Skip => continue,
            TestResultKind::Fail(msg, desc) => {
                return TestResult {
                    path: test.path.clone(),
                    kind: TestResultKind::Fail(msg, desc),
                }
            },
        }
    }

    TestResult {
        path: test.path.clone(),
        kind: TestResultKind::Pass,
    }
}

fn run_directive(directive: &Directive, test: &Test, context: &Context)
    -> TestResultKind {
    match *directive {
        Directive::Run(ref invocation) => {
            let exe_path = context.executable_path(&invocation.executable);
            let mut cmd = Command::new(&exe_path);

            for arg in invocation.arguments.iter() {
                let arg_str = arg.resolve(test);
                cmd.arg(arg_str);
            }

            let output = match cmd.output() {
                Ok(o) => o,
                Err(e) => match e.kind() {
                    std::io::ErrorKind::NotFound => {
                        return TestResultKind::Fail(
                            format!("executable not found: {}",
                                    exe_path), "".to_owned());
                    },
                    _ => {
                        return TestResultKind::Fail(
                            format!("could not execute: '{}', {}",
                                    exe_path, e), "".to_owned());
                    },
                },
            };

            if output.status.success() {
                TestResultKind::Pass
            } else {
                let stderr = String::from_utf8(output.stderr).unwrap();

                TestResultKind::Fail(format!(
                    "{} exited with code {}", exe_path,
                    output.status.code().unwrap()),
                    stderr
                    )
            }
        },
    }
}

mod util
{
    use super::test::{Test,Directive};

    use std::error::Error;
    use std::io::Read;
    use compiler::ir;
    use std;

    pub fn tool_dir() -> Option<String> {
        let current_exec = match std::env::current_exe() {
            Ok(e) => e,
            Err(e) => abort(
                format!("failed to get current executable path: {}", e)),
        };

        current_exec.parent().map(|p| p.to_str().unwrap().to_owned())
    }

    pub fn parse_test(file_name: &str) -> Result<Test,String> {
        use compiler::ir::read::Token;

        let chars = open_file(file_name).chars().map(|c| c.unwrap());

        let tokenizer = ir::read::Tokenizer::new(chars).preserve_comments();
        let tokens = tokenizer.map(|result| result.unwrap());

        let mut directives = Vec::new();

        for token in tokens {
            match token {
                Token::Comment { ref text, .. } => {
                    match maybe_parse_directive(text) {
                        Some(Ok(directive)) => directives.push(directive),
                        Some(Err(e)) => {
                            return Err(format!(
                                "could not parse directive: {}", e)
                            );
                        },
                        None => continue,
                    }
                },
                _ => continue,
            };
        }

        Ok(Test {
            path: file_name.to_owned(),
            directives: directives,
        })
    }

    pub fn maybe_parse_directive(comment_text: &str)
        -> Option<Result<Directive,String>> {
        Directive::maybe_parse(comment_text.trim().to_owned())
    }

    fn open_file(path: &str) -> std::fs::File {
        match std::fs::File::open(path) {
            Ok(f) => f,
            Err(e) => abort(format!("could not open {}: {}",
                                    path, e.description())),
        }
    }
    pub fn abort<S>(msg: S) -> !
        where S: Into<String> {
        super::print::failure(format!("error: {}", msg.into()));

        std::process::exit(1);
    }
}

pub mod print
{
    use std;
    use term;

    pub fn line() {
        with("\n",
             term::stdout().unwrap(),
             term::color::WHITE);
    }

    pub fn text<S>(msg: S)
        where S: Into<String> {
        with(format!("{}\n", msg.into()),
             term::stdout().unwrap(),
             term::color::WHITE);
    }

    pub fn success<S>(msg: S)
        where S: Into<String> {
        with(format!("{}\n", msg.into()),
             term::stdout().unwrap(),
             term::color::GREEN);
    }

    pub fn warning<S>(msg: S)
        where S: Into<String> {
        with(format!("{}\n", msg.into()),
             term::stdout().unwrap(),
             term::color::YELLOW);
    }

    pub fn failure<S>(msg: S)
        where S: Into<String> {
        with(format!("{}\n", msg.into()),
             term::stderr().unwrap(),
             term::color::RED);
    }

    pub fn with<S,W>(msg: S,
                           mut term: Box<term::Terminal<Output=W>>,
                           color: term::color::Color)
        where S: Into<String>, W: std::io::Write {

        term.fg(color).unwrap();
        write!(term, "{}", msg.into()).unwrap();
    }
}
<commit_msg>[test] Add a 'no tests' diagnostic message<commit_after>#![feature(io)]

extern crate compiler;
extern crate argparse;
extern crate walkdir;
extern crate term;

use argparse::ArgumentParser;
use walkdir::WalkDir;
use std::process::Command;
use std::borrow::Borrow;

mod tool
{
    use super::test::Test;

    /// A constant.
    #[derive(Copy,Clone,Debug,PartialEq,Eq)]
    pub enum Constant
    {
        /// The path of the test that is being run.
        TestPath,
    }

    impl Constant
    {
        /// Maps a constant name to a constant.
        /// Returns `None` if no mapping exists.
        pub fn lookup(name: &str) -> Option<Constant> {
            match name {
                "file" => Some(Constant::TestPath),
                _ => None,
            }
        }
    }

    /// An argument to a tool.
    #[derive(Clone,Debug,PartialEq,Eq)]
    pub enum Argument
    {
        Normal(String),
        Substitute(Constant),
    }

    impl Argument
    {
        /// Parses an argument to a tool.
        ///
        /// If it is prefixed with `@`, then it will be taken
        /// as a constant substitution, otherwise it will
        /// be read verbatim as a tool argument.
        pub fn parse(string: String) -> Result<Self,String> {
            // check if we are parsing a substitution
            if string.chars().next().unwrap() == '@' {
                let name: String = string.chars().skip(1).collect();

                match Constant::lookup(&name) {
                    Some(constant) => Ok(Argument::Substitute(constant)),
                    None => Err(format!("constant does not exist: {}", name)),
                }
            } else { // it is a plain old argument
                Ok(Argument::Normal(string))
            }
        }

        pub fn resolve(&self, test: &Test) -> String {
            match *self {
                Argument::Normal(ref s) => s.clone(),
                Argument::Substitute(constant) => match constant {
                    Constant::TestPath => test.path.clone(),
                },
            }
        }
    }

    /// A tool invocation.
    #[derive(Clone,Debug,PartialEq,Eq)]
    pub struct Invocation
    {
        pub executable: String,
        pub arguments: Vec<Argument>,
    }

    impl Invocation
    {
        /// Parses a tool invocation.
        ///
        /// It is in the format:
        ///
        /// ``` bash
        /// <tool-name> [arg1] [arg2] ...
        /// ```
        pub fn parse<'a,I>(mut words: I) -> Result<Self,String>
            where I: Iterator<Item=&'a str> {
            let executable = match words.next() {
                Some(exec) => exec,
                None => return Err("no executable specified".into()),
            }.into();

            let mut arguments = Vec::new();

            for arg_str in words {
                let arg = try!(Argument::parse(arg_str.into()));
                arguments.push(arg);
            }

            Ok(Invocation {
                executable: executable,
                arguments: arguments,
            })
        }
    }
}

pub mod test
{
    use super::tool;
    use std;

    #[derive(Clone,Debug,PartialEq,Eq)]
    pub enum Directive
    {
        Run(tool::Invocation),
    }

    impl Directive
    {
        pub fn maybe_parse(string: String) -> Option<Result<Self,String>> {
            let directive_str = string.split_whitespace().next().unwrap();
            let inner_words = string.split_whitespace().skip(1);

            match directive_str {
                // FIXME: better message if we have 'RUN :'
                "RUN:" => {
                    let invocation = match tool::Invocation::parse(inner_words) {
                        Ok(i) => i,
                        Err(e) => return Some(Err(e)),
                    };

                    Some(Ok(Directive::Run(invocation)))
                },
                _ => {
                    if directive_str.ends_with(':') {
                        Some(Err(format!("directive '{}' not known", directive_str)))
                    } else {
                        None
                    }
                },
            }
        }
    }

    #[derive(Clone,Debug,PartialEq,Eq)]
    pub struct Test
    {
        pub path: String,
        pub directives: Vec<Directive>,
    }

    impl Test
    {
        pub fn is_empty(&self) -> bool {
            self.directives.is_empty()
        }
    }

    pub enum TestResultKind
    {
        Pass,
        Fail(String, String),
        Skip,
    }

    pub struct TestResult
    {
        pub path: String,
        pub kind: TestResultKind,
    }

    #[derive(Clone,Debug,PartialEq,Eq)]
    pub struct Context
    {
        pub exec_search_dirs: Vec<String>,
        pub tests: Vec<Test>,
    }

    impl Context
    {
        pub fn new() -> Self {
            Context {
                exec_search_dirs: Vec::new(),
                tests: Vec::new(),
            }
        }

        pub fn test(mut self, test: Test) -> Self {
            self.tests.push(test);
            self
        }

        pub fn add_search_dir(&mut self, dir: String) {
            self.exec_search_dirs.push(dir);
        }

        pub fn find_in_search_dir(&self, path: &str)
            -> Option<String> {
            for dir in self.exec_search_dirs.iter() {
                for entry in std::fs::read_dir(dir).unwrap() {
                    let entry = entry.unwrap();
                    let cur_path = entry.path();

                    if std::fs::metadata(&cur_path).unwrap().is_file() {
                        if cur_path.file_name().unwrap() == path {
                            return Some(cur_path.to_str().unwrap().to_owned());
                        }
                    }

                }
            }
            None
        }

        pub fn executable_path(&self, path: &str) -> String {
            match self.find_in_search_dir(path) {
                Some(p) => p,
                None => path.to_owned(),
            }
        }
    }
}

use test::{Test,Directive,TestResult,TestResultKind,Context};

fn main() {
    let mut files: Vec<String> = Vec::new();

    {
        let mut ap = ArgumentParser::new();
        ap.set_description("Runs tests");

        ap.refer(&mut files)
            .add_argument("files", argparse::List,
                          r#"Files to test"#);
        ap.parse_args_or_exit();
    }

    let paths: Vec<&str> = files.iter()
                                 .map(|s| s.borrow())
                                 .collect();

    if paths.is_empty() {
        util::abort("no filenames given")
    }

    let test_paths = find_tests(&paths);

    if test_paths.is_empty() {
        print::warning("could not find any tests");
        return;
    }

    let mut context = test_paths.into_iter().fold(Context::new(), |c,file| {
        let test = read_test(&file).unwrap();
        c.test(test)
    });

    match util::tool_dir() {
        Some(dir) => context.add_search_dir(dir),
        None => print::warning("could not find tool directory"),
    }

    let results = run_tests(&context);

    for result in results.iter() {
        print_result(result)
    }
}

fn print_result(result: &TestResult) {
    match result.kind {
        TestResultKind::Pass => {
            print::success(format!("PASS :: {}", result.path));
        },
        TestResultKind::Skip => {
            print::line();
            print::warning(format!(
                "SKIP :: {} (test does not contain any directives)",
                     result.path));
            print::line();
        },
        TestResultKind::Fail(ref msg, ref desc) => {
            print::line();

            print::failure(format!("FAIL :: {}", result.path));
            print::text(msg.clone());

            // Only print stderr if there was output
            if !desc.is_empty() {
                print::line();
                print::text("stderr:");
                print::line();
                print::text(desc.clone());
            }

            print::line();
        },
    }
}

/// Recursively finds tests for the given paths.
fn find_tests(paths: &[&str]) -> Vec<String> {
    paths.iter().flat_map(|path| {
                    find_tests_in_path(path).into_iter()
                })
                .collect()
}

fn find_tests_in_path(path: &str) -> Vec<String> {
    let metadata = match std::fs::metadata(path) {
        Ok(meta) => meta,
        Err(e) => util::abort(format!("failed to open '{}': {}",
                                      path, e)),
    };

    if metadata.is_dir() {
        find_tests_in_dir(path)
    } else {
        vec![path.to_owned()]
    }
}

fn find_tests_in_dir(path: &str) -> Vec<String> {
    find_files_in_dir(path).into_iter()
                           .filter(|f| f.ends_with(".ir"))
                           .collect()
}

fn find_files_in_dir(path: &str) -> Vec<String> {
    let mut dir_tests = Vec::new();

    for entry in WalkDir::new(path) {
        let entry = entry.unwrap();

        // don't go into an infinite loop
        if entry.path().to_str().unwrap() == path {
            continue;
        }

        if entry.metadata().unwrap().is_file() {
            dir_tests.push(entry.path().to_str().unwrap().to_owned());
        }
    }

    dir_tests
}

fn read_test(path: &str) -> Result<Test,String> {
    // TODO: redundant indirection
    util::parse_test(path)
}

fn run_tests(context: &Context) -> Vec<TestResult> {
    context.tests.iter().map(|test| run_test(test, context)).collect()
}

fn run_test(test: &Test, context: &Context) -> TestResult {
    if test.is_empty() {
        println!("SKIP :: {} (it includes no test directives", test.path);
        return TestResult {
            path: test.path.clone(),
            kind: TestResultKind::Skip,
        }
    }

    for directive in test.directives.iter() {
        let kind = run_directive(directive, test, context);

        match kind {
            TestResultKind::Pass => continue,
            TestResultKind::Skip => continue,
            TestResultKind::Fail(msg, desc) => {
                return TestResult {
                    path: test.path.clone(),
                    kind: TestResultKind::Fail(msg, desc),
                }
            },
        }
    }

    TestResult {
        path: test.path.clone(),
        kind: TestResultKind::Pass,
    }
}

fn run_directive(directive: &Directive, test: &Test, context: &Context)
    -> TestResultKind {
    match *directive {
        Directive::Run(ref invocation) => {
            let exe_path = context.executable_path(&invocation.executable);
            let mut cmd = Command::new(&exe_path);

            for arg in invocation.arguments.iter() {
                let arg_str = arg.resolve(test);
                cmd.arg(arg_str);
            }

            let output = match cmd.output() {
                Ok(o) => o,
                Err(e) => match e.kind() {
                    std::io::ErrorKind::NotFound => {
                        return TestResultKind::Fail(
                            format!("executable not found: {}",
                                    exe_path), "".to_owned());
                    },
                    _ => {
                        return TestResultKind::Fail(
                            format!("could not execute: '{}', {}",
                                    exe_path, e), "".to_owned());
                    },
                },
            };

            if output.status.success() {
                TestResultKind::Pass
            } else {
                let stderr = String::from_utf8(output.stderr).unwrap();

                TestResultKind::Fail(format!(
                    "{} exited with code {}", exe_path,
                    output.status.code().unwrap()),
                    stderr
                    )
            }
        },
    }
}

mod util
{
    use super::test::{Test,Directive};

    use std::error::Error;
    use std::io::Read;
    use compiler::ir;
    use std;

    pub fn tool_dir() -> Option<String> {
        let current_exec = match std::env::current_exe() {
            Ok(e) => e,
            Err(e) => abort(
                format!("failed to get current executable path: {}", e)),
        };

        current_exec.parent().map(|p| p.to_str().unwrap().to_owned())
    }

    pub fn parse_test(file_name: &str) -> Result<Test,String> {
        use compiler::ir::read::Token;

        let chars = open_file(file_name).chars().map(|c| c.unwrap());

        let tokenizer = ir::read::Tokenizer::new(chars).preserve_comments();
        let tokens = tokenizer.map(|result| result.unwrap());

        let mut directives = Vec::new();

        for token in tokens {
            match token {
                Token::Comment { ref text, .. } => {
                    match maybe_parse_directive(text) {
                        Some(Ok(directive)) => directives.push(directive),
                        Some(Err(e)) => {
                            return Err(format!(
                                "could not parse directive: {}", e)
                            );
                        },
                        None => continue,
                    }
                },
                _ => continue,
            };
        }

        Ok(Test {
            path: file_name.to_owned(),
            directives: directives,
        })
    }

    pub fn maybe_parse_directive(comment_text: &str)
        -> Option<Result<Directive,String>> {
        Directive::maybe_parse(comment_text.trim().to_owned())
    }

    fn open_file(path: &str) -> std::fs::File {
        match std::fs::File::open(path) {
            Ok(f) => f,
            Err(e) => abort(format!("could not open {}: {}",
                                    path, e.description())),
        }
    }
    pub fn abort<S>(msg: S) -> !
        where S: Into<String> {
        super::print::failure(format!("error: {}", msg.into()));

        std::process::exit(1);
    }
}

pub mod print
{
    use std;
    use term;

    pub fn line() {
        with("\n",
             term::stdout().unwrap(),
             term::color::WHITE);
    }

    pub fn text<S>(msg: S)
        where S: Into<String> {
        with(format!("{}\n", msg.into()),
             term::stdout().unwrap(),
             term::color::WHITE);
    }

    pub fn success<S>(msg: S)
        where S: Into<String> {
        with(format!("{}\n", msg.into()),
             term::stdout().unwrap(),
             term::color::GREEN);
    }

    pub fn warning<S>(msg: S)
        where S: Into<String> {
        with(format!("{}\n", msg.into()),
             term::stdout().unwrap(),
             term::color::YELLOW);
    }

    pub fn failure<S>(msg: S)
        where S: Into<String> {
        with(format!("{}\n", msg.into()),
             term::stderr().unwrap(),
             term::color::RED);
    }

    pub fn with<S,W>(msg: S,
                           mut term: Box<term::Terminal<Output=W>>,
                           color: term::color::Color)
        where S: Into<String>, W: std::io::Write {

        term.fg(color).unwrap();
        write!(term, "{}", msg.into()).unwrap();
    }
}
<|endoftext|>


<commit_before>#![allow(clippy::useless_attribute)] //issue #2910

#[macro_use]
extern crate serde_derive;

/// Tests that we do not lint for unused underscores in a `MacroAttribute`
/// expansion
#[deny(clippy::used_underscore_binding)]
#[derive(Deserialize)]
struct MacroAttributesTest {
    _foo: u32,
}

#[test]
fn macro_attributes_test() {
    let _ = MacroAttributesTest { _foo: 0 };
}

fn main() {}
<commit_msg>fix clippy test<commit_after>// edition:2018

use serde::Deserialize;

/// Tests that we do not lint for unused underscores in a `MacroAttribute`
/// expansion
#[deny(clippy::used_underscore_binding)]
#[derive(Deserialize)]
struct MacroAttributesTest {
    _foo: u32,
}

#[test]
fn macro_attributes_test() {
    let _ = MacroAttributesTest { _foo: 0 };
}

fn main() {}
<|endoftext|>


<commit_before>//! Pointers and their events

use types::input_device::InputDevice;

use wlroots_sys::{wlr_button_state, wlr_event_pointer_axis, wlr_event_pointer_button,
                  wlr_event_pointer_motion, wlr_event_pointer_motion_absolute};

pub struct AxisEvent {
    event: *mut wlr_event_pointer_axis
}

pub struct ButtonEvent {
    event: *mut wlr_event_pointer_button
}

pub struct MotionEvent {
    event: *mut wlr_event_pointer_motion
}

pub struct AbsoluteMotionEvent {
    event: *mut wlr_event_pointer_motion_absolute
}

impl ButtonEvent {
    pub unsafe fn from_ptr(event: *mut wlr_event_pointer_button) -> Self {
        ButtonEvent { event }
    }

    pub fn state(&self) -> wlr_button_state {
        unsafe { (*self.event).state }
    }

    pub fn button(&self) -> u32 {
        unsafe { (*self.event).button }
    }
}

impl AxisEvent {
    pub unsafe fn from_ptr(event: *mut wlr_event_pointer_axis) -> Self {
        AxisEvent { event }
    }

    pub fn delta(&self) -> f64 {
        unsafe { (*self.event).delta }
    }
}

impl MotionEvent {
    pub unsafe fn from_ptr(event: *mut wlr_event_pointer_motion) -> Self {
        MotionEvent { event }
    }

    pub fn device(&self) -> InputDevice {
        unsafe { InputDevice::from_ptr((*self.event).device) }
    }

    pub fn delta(&self) -> (f64, f64) {
        unsafe { ((*self.event).delta_x, (*self.event).delta_y) }
    }
}

impl AbsoluteMotionEvent {
    pub unsafe fn from_ptr(event: *mut wlr_event_pointer_motion_absolute) -> Self {
        AbsoluteMotionEvent { event }
    }

    pub fn device(&self) -> InputDevice {
        unsafe { InputDevice::from_ptr((*self.event).device) }
    }
}
<commit_msg>Plug safety hole in pointer events w/ InputDevice<commit_after>//! Pointers and their events

use types::input_device::InputDevice;

use wlroots_sys::{wlr_button_state, wlr_event_pointer_axis, wlr_event_pointer_button,
                  wlr_event_pointer_motion, wlr_event_pointer_motion_absolute};

// TODO FIXME Document this shit man

#[derive(Debug)]
pub struct AxisEvent {
    event: *mut wlr_event_pointer_axis,
    device: InputDevice
}

#[derive(Debug)]
pub struct ButtonEvent {
    event: *mut wlr_event_pointer_button,
    device: InputDevice
}

#[derive(Debug)]
pub struct MotionEvent {
    event: *mut wlr_event_pointer_motion,
    device: InputDevice
}

#[derive(Debug)]
pub struct AbsoluteMotionEvent {
    event: *mut wlr_event_pointer_motion_absolute,
    device: InputDevice
}

impl ButtonEvent {
    pub unsafe fn from_ptr(event: *mut wlr_event_pointer_button) -> Self {
        ButtonEvent { device: InputDevice::from_ptr((*event).device), event }
    }

    pub fn device(&self) -> &InputDevice {
        &self.device
    }

    pub fn state(&self) -> wlr_button_state {
        unsafe { (*self.event).state }
    }

    pub fn button(&self) -> u32 {
        unsafe { (*self.event).button }
    }
}

impl AxisEvent {
    pub unsafe fn from_ptr(event: *mut wlr_event_pointer_axis) -> Self {
        AxisEvent { device: InputDevice::from_ptr((*event).device), event }
    }

    pub fn device(&self) -> &InputDevice {
        &self.device
    }

    pub fn delta(&self) -> f64 {
        unsafe { (*self.event).delta }
    }
}

impl MotionEvent {
    pub unsafe fn from_ptr(event: *mut wlr_event_pointer_motion) -> Self {
        MotionEvent { device: InputDevice::from_ptr((*event).device), event }
    }

    pub fn device(&self) -> &InputDevice {
        &self.device
    }

    pub fn delta(&self) -> (f64, f64) {
        unsafe { ((*self.event).delta_x, (*self.event).delta_y) }
    }
}

impl AbsoluteMotionEvent {
    pub unsafe fn from_ptr(event: *mut wlr_event_pointer_motion_absolute) -> Self {
        AbsoluteMotionEvent { device: InputDevice::from_ptr((*event).device), event }
    }

    pub fn device(&self) -> &InputDevice {
        &self.device
    }
}
<|endoftext|>


<commit_before>// Implements http://rosettacode.org/wiki/99_Bottles_of_Beer
#![cfg(not_tested)]
use std::iter::range_step_inclusive;

fn sing_bottles_line(num_bottles: int, on_the_wall: bool) {
	// the print! macro uses a built in internationalization formatting language
	// check out the docs for std::fmt
	print!("{0, plural, =0{No bottles} =1{One bottle} other{# bottles}} of beer", num_bottles as uint);

	if on_the_wall {
		print!(" on the wall!");
	}

	print!("\n");
}

fn main() {
	for num_bottles in range_step_inclusive(99, 1, -1) {
		sing_bottles_line(num_bottles, true);
		sing_bottles_line(num_bottles, false);
		println!("Take one down, pass it around...");
		sing_bottles_line(num_bottles - 1, true);
		println!("-----------------------------------");
	}
}
<commit_msg>99 bottles of beer, added test<commit_after>// Implements http://rosettacode.org/wiki/99_Bottles_of_Beer
use std::string::String;

#[cfg(not(test))]
fn main() {
	for num_bottles in std::iter::range_step_inclusive(99, 1, -1) {
        let num_bottles=num_bottles as uint;

		println!("{}",bottles_line(num_bottles as uint, true));
		println!("{}",bottles_line(num_bottles as uint, false));
		println!("Take one down, pass it around...");
		println!("{}",bottles_line(num_bottles - 1, true).as_slice());
		println!("-----------------------------------");
	}
}

fn bottles_line(num_bottles: uint, on_the_wall: bool) -> String {
	// the format! macro uses a built in internationalization formatting language
	// check out the docs for std::fmt
	let mut ln=format!("{0, plural, =0{No bottles} =1{One bottle} other{# bottles}} of beer",
                                                                                num_bottles);

	if on_the_wall {
		ln.push_str(" on the wall!");
	}

	ln.push_str("\n");
    ln
}

#[test]
fn gen_bottle_line() {
    let ln=bottles_line(42, false);
    let ln2=bottles_line(42, true);

    assert_eq!(ln.as_slice(),"42 bottles of beer\n");
    assert_eq!(ln2.as_slice(),"42 bottles of beer on the wall!\n");
}
<|endoftext|>