<commit_before>use crate::decor::{Formatted, Repr};
use crate::document::Document;
use crate::table::{Item, Table};
use crate::value::{Array, DateTime, InlineTable, Value};
use std::fmt::{Display, Error, Formatter, Result, Write};

impl Display for Repr {
    fn fmt(&self, f: &mut Formatter) -> Result {
        write!(
            f,
            "{}{}{}",
            self.decor.prefix, self.raw_value, self.decor.suffix
        )
    }
}

impl<T> Display for Formatted<T> {
    fn fmt(&self, f: &mut Formatter) -> Result {
        write!(f, "{}", self.repr)
    }
}

impl Display for DateTime {
    fn fmt(&self, f: &mut Formatter) -> Result {
        match *self {
            DateTime::OffsetDateTime(d) => write!(f, "{}", d),
            DateTime::LocalDateTime(d) => write!(f, "{}", d),
            DateTime::LocalDate(d) => write!(f, "{}", d),
            DateTime::LocalTime(d) => write!(f, "{}", d),
        }
    }
}

impl Display for Value {
    fn fmt(&self, f: &mut Formatter) -> Result {
        match *self {
            Value::Integer(ref repr) => write!(f, "{}", repr),
            Value::String(ref repr) => write!(f, "{}", repr),
            Value::Float(ref repr) => write!(f, "{}", repr),
            Value::Boolean(ref repr) => write!(f, "{}", repr),
            Value::DateTime(ref repr) => write!(f, "{}", repr),
            Value::Array(ref array) => write!(f, "{}", array),
            Value::InlineTable(ref table) => write!(f, "{}", table),
        }
    }
}

impl Display for Array {
    fn fmt(&self, f: &mut Formatter) -> Result {
        write!(f, "{}[", self.decor.prefix)?;
        join(f, self.iter(), ",")?;
        if self.trailing_comma {
            write!(f, ",")?;
        }
        write!(f, "{}", self.trailing)?;
        write!(f, "]{}", self.decor.suffix)
    }
}

impl Display for InlineTable {
    fn fmt(&self, f: &mut Formatter) -> Result {
        write!(f, "{}{{", self.decor.prefix)?;
        write!(f, "{}", self.preamble)?;
        for (i, (key, value)) in self
            .items
            .iter()
            .filter(|&(_, kv)| kv.value.is_value())
            .map(|(_, kv)| (&kv.key, kv.value.as_value().unwrap()))
            .enumerate()
        {
            if i > 0 {
                write!(f, ",")?;
            }
            write!(f, "{}={}", key, value)?;
        }
        write!(f, "}}{}", self.decor.suffix)
    }
}

impl Table {
    fn visit_nested_tables_in_original_order<'t, F>(
        &'t self,
        path: &mut Vec<&'t str>,
        is_array_of_tables: bool,
        callback: &mut F,
    ) -> Result
    where
        F: FnMut(&Table, &Vec<&'t str>, bool) -> Result,
    {
        let mut known_positions = vec![];
        self.visit_nested_tables(path, is_array_of_tables, &mut |t, _path, _is_array| {
            if let Some(pos) = t.position {
                known_positions.push(pos);
            }
            Ok(())
        })?;
        known_positions.sort();

        let mut position_iter = known_positions.iter();
        let mut current_position: usize = match position_iter.next() {
            Some(pos) => *pos,
            None => return Ok(()),
        };

        let mut should_print = true;
        let mut done = false;
        while !done {
            let mut progressed_this_loop = false;
            self.visit_nested_tables(path, is_array_of_tables, &mut |t, path, is_array| {
                if done && !should_print {
                    return Ok(());
                }
                match &t.position {
                    Some(ref pos) => {
                        if *pos == current_position {
                            // if this table is from from the position we're
                            // looking for, print it.
                            should_print = true;
                            match position_iter.next() {
                                Some(pos) => current_position = *pos,
                                None => done = true,
                            };
                            progressed_this_loop = true;
                        } else {
                            // if this table isn't from the position we're
                            // looking for, skip it.
                            should_print = false;
                        }
                    }
                    // If this table doesn't have a position then it was
                    // probably made programmatically, so put it after wherever
                    // it happens to be after in the tree. We only want to print
                    // it once though, so rely on should_print from the previous
                    // table to tell you whether you need to print this one.
                    None => (),
                }
                if should_print {
                    callback(t, path, is_array)
                } else {
                    Ok(())
                }
            })?;
            if !progressed_this_loop {
                match position_iter.next() {
                    Some(pos) => current_position = *pos,
                    None => done = true,
                };
            }
            // we set should_print to true the first time we went around the
            // loop, so initially None-positioned Tables will have already been
            // printed.
            should_print = false;
        }
        Ok(())
    }

    fn visit_nested_tables<'t, F>(
        &'t self,
        path: &mut Vec<&'t str>,
        is_array_of_tables: bool,
        callback: &mut F,
    ) -> Result
    where
        F: FnMut(&Table, &Vec<&'t str>, bool) -> Result,
    {
        callback(self, path, is_array_of_tables)?;

        for kv in self.items.values() {
            match kv.value {
                Item::Table(ref t) => {
                    path.push(&kv.key.raw_value);
                    t.visit_nested_tables(path, false, callback)?;
                    path.pop();
                }
                Item::ArrayOfTables(ref a) => {
                    for t in a.iter() {
                        path.push(&kv.key.raw_value);
                        t.visit_nested_tables(path, true, callback)?;
                        path.pop();
                    }
                }
                _ => {}
            }
        }
        Ok(())
    }
}

fn visit_table(f: &mut Write, table: &Table, path: &[&str], is_array_of_tables: bool) -> Result {
    if path.is_empty() {
        // don't print header for the root node
    } else if is_array_of_tables {
        write!(f, "{}[[", table.decor.prefix)?;
        write!(f, "{}", path.join("."))?;
        writeln!(f, "]]{}", table.decor.suffix)?;
    } else if !(table.implicit && table.values_len() == 0) {
        write!(f, "{}[", table.decor.prefix)?;
        write!(f, "{}", path.join("."))?;
        writeln!(f, "]{}", table.decor.suffix)?;
    }
    // print table body
    for kv in table.items.values() {
        if let Item::Value(ref value) = kv.value {
            writeln!(f, "{}={}", kv.key, value)?;
        }
    }
    Ok(())
}

impl Display for Table {
    fn fmt(&self, f: &mut Formatter) -> Result {
        let mut path = Vec::new();

        self.visit_nested_tables(&mut path, false, &mut |t, path, is_array| {
            visit_table(f, t, path, is_array)
        })?;
        Ok(())
    }
}

impl Document {
    /// Returns a string representation of the TOML document, attempting to keep
    /// the table headers in their original order.
    ///
    /// Known issues:
    /// * If you have created your Document by parsing two .toml files and
    ///   merging the results together, this method may silently skip some
    ///   tables. Please use Document.to_string() instead, which doesn't have
    ///   this problem.
    /// * The best case performance of this function is similar to
    ///   Document.to_string(). This will be true for  If you have lots of
    ///   tables that have been deleted or are in strange orders.
    pub fn to_string_in_original_order(&self) -> std::result::Result<String, Error> {
        let mut string = String::default();
        let mut path = Vec::new();

        self.as_table().visit_nested_tables_in_original_order(
            &mut path,
            false,
            &mut |t, path, is_array| visit_table(&mut string, t, path, is_array),
        )?;

        write!(string, "{}", self.trailing)?;
        Ok(string)
    }
}

impl Display for Document {
    fn fmt(&self, f: &mut Formatter) -> Result {
        write!(f, "{}", self.as_table())?;
        write!(f, "{}", self.trailing)
    }
}

fn join<D, I>(f: &mut Formatter, iter: I, sep: &str) -> Result
where
    D: Display,
    I: Iterator<Item = D>,
{
    for (i, v) in iter.enumerate() {
        if i > 0 {
            write!(f, "{}", sep)?;
        }
        write!(f, "{}", v)?;
    }
    Ok(())
}
<commit_msg>implement more robust sorted tree walking scheme<commit_after>use crate::decor::{Formatted, Repr};
use crate::document::Document;
use crate::table::{Item, Table};
use crate::value::{Array, DateTime, InlineTable, Value};
use std::fmt::{Display, Error, Formatter, Result, Write};

impl Display for Repr {
    fn fmt(&self, f: &mut Formatter) -> Result {
        write!(
            f,
            "{}{}{}",
            self.decor.prefix, self.raw_value, self.decor.suffix
        )
    }
}

impl<T> Display for Formatted<T> {
    fn fmt(&self, f: &mut Formatter) -> Result {
        write!(f, "{}", self.repr)
    }
}

impl Display for DateTime {
    fn fmt(&self, f: &mut Formatter) -> Result {
        match *self {
            DateTime::OffsetDateTime(d) => write!(f, "{}", d),
            DateTime::LocalDateTime(d) => write!(f, "{}", d),
            DateTime::LocalDate(d) => write!(f, "{}", d),
            DateTime::LocalTime(d) => write!(f, "{}", d),
        }
    }
}

impl Display for Value {
    fn fmt(&self, f: &mut Formatter) -> Result {
        match *self {
            Value::Integer(ref repr) => write!(f, "{}", repr),
            Value::String(ref repr) => write!(f, "{}", repr),
            Value::Float(ref repr) => write!(f, "{}", repr),
            Value::Boolean(ref repr) => write!(f, "{}", repr),
            Value::DateTime(ref repr) => write!(f, "{}", repr),
            Value::Array(ref array) => write!(f, "{}", array),
            Value::InlineTable(ref table) => write!(f, "{}", table),
        }
    }
}

impl Display for Array {
    fn fmt(&self, f: &mut Formatter) -> Result {
        write!(f, "{}[", self.decor.prefix)?;
        join(f, self.iter(), ",")?;
        if self.trailing_comma {
            write!(f, ",")?;
        }
        write!(f, "{}", self.trailing)?;
        write!(f, "]{}", self.decor.suffix)
    }
}

impl Display for InlineTable {
    fn fmt(&self, f: &mut Formatter) -> Result {
        write!(f, "{}{{", self.decor.prefix)?;
        write!(f, "{}", self.preamble)?;
        for (i, (key, value)) in self
            .items
            .iter()
            .filter(|&(_, kv)| kv.value.is_value())
            .map(|(_, kv)| (&kv.key, kv.value.as_value().unwrap()))
            .enumerate()
        {
            if i > 0 {
                write!(f, ",")?;
            }
            write!(f, "{}={}", key, value)?;
        }
        write!(f, "}}{}", self.decor.suffix)
    }
}

impl Table {
    fn visit_nested_tables_in_original_order<'t, F>(
        &'t self,
        path: &mut Vec<&'t str>,
        is_array_of_tables: bool,
        callback: &mut F,
    ) -> Result
    where
        F: FnMut(&Table, &Vec<&'t str>, bool) -> Result,
    {
        let mut positions = vec![];
        self.visit_nested_tables(path, is_array_of_tables, &mut |t, _, _| {
            if let Some(pos) = t.position {
                positions.push(pos);
            }
            Ok(())
        })?;
        positions.sort();
        let mut position_iter = positions.iter();

        // If a table has a .position set then we calculate whether we should
        // print based on whether it matches current_position. If .position is
        // None then it was added programatically and we decide whether to print
        // it based on whether we printed the previous table we visited. This
        // is to avoid printing tables more than once.
        //
        // We set should_print to true the first time we went around the
        // loop, so initially None-positioned Tables will have already been
        // printed.
        let mut should_print = true;

        let mut current_position: Option<&usize> = position_iter.next();
        while current_position.is_some() {
            self.visit_nested_tables(path, is_array_of_tables, &mut |t, path, is_array| {
                if current_position.is_none() && !should_print {
                    return Ok(());
                }
                match &t.position {
                    Some(_) => {
                        if t.position.as_ref() == current_position {
                            current_position = position_iter.next();
                            should_print = true;
                        } else {
                            should_print = false;
                        }
                    }
                    // This table doesn't have a position, so only print it if
                    // should_print is still set from the previous table.
                    None => (),
                }
                if should_print {
                    callback(t, path, is_array)?
                }
                Ok(())
            })?;
            should_print = false;
        }
        Ok(())
    }

    fn visit_nested_tables<'t, F>(
        &'t self,
        path: &mut Vec<&'t str>,
        is_array_of_tables: bool,
        callback: &mut F,
    ) -> Result
    where
        F: FnMut(&Table, &Vec<&'t str>, bool) -> Result,
    {
        callback(self, path, is_array_of_tables)?;

        for kv in self.items.values() {
            match kv.value {
                Item::Table(ref t) => {
                    path.push(&kv.key.raw_value);
                    t.visit_nested_tables(path, false, callback)?;
                    path.pop();
                }
                Item::ArrayOfTables(ref a) => {
                    for t in a.iter() {
                        path.push(&kv.key.raw_value);
                        t.visit_nested_tables(path, true, callback)?;
                        path.pop();
                    }
                }
                _ => {}
            }
        }
        Ok(())
    }
}

fn visit_table(f: &mut Write, table: &Table, path: &[&str], is_array_of_tables: bool) -> Result {
    if path.is_empty() {
        // don't print header for the root node
    } else if is_array_of_tables {
        write!(f, "{}[[", table.decor.prefix)?;
        write!(f, "{}", path.join("."))?;
        writeln!(f, "]]{}", table.decor.suffix)?;
    } else if !(table.implicit && table.values_len() == 0) {
        write!(f, "{}[", table.decor.prefix)?;
        write!(f, "{}", path.join("."))?;
        writeln!(f, "]{}", table.decor.suffix)?;
    }
    // print table body
    for kv in table.items.values() {
        if let Item::Value(ref value) = kv.value {
            writeln!(f, "{}={}", kv.key, value)?;
        }
    }
    Ok(())
}

impl Display for Table {
    fn fmt(&self, f: &mut Formatter) -> Result {
        let mut path = Vec::new();

        self.visit_nested_tables(&mut path, false, &mut |t, path, is_array| {
            visit_table(f, t, path, is_array)
        })?;
        Ok(())
    }
}

impl Document {
    /// Returns a string representation of the TOML document, attempting to keep
    /// the table headers in their original order.
    ///
    /// The best case performance of this function is slightly slower than
    /// Document.to_string(). If you have lots of tables that are in strange
    /// orders then it may be significantly slower as it has to walk the tree
    /// multiple times.
    pub fn to_string_in_original_order(&self) -> std::result::Result<String, Error> {
        let mut string = String::default();
        let mut path = Vec::new();

        self.as_table().visit_nested_tables_in_original_order(
            &mut path,
            false,
            &mut |t, path, is_array| visit_table(&mut string, t, path, is_array),
        )?;

        write!(string, "{}", self.trailing)?;
        Ok(string)
    }
}

impl Display for Document {
    fn fmt(&self, f: &mut Formatter) -> Result {
        write!(f, "{}", self.as_table())?;
        write!(f, "{}", self.trailing)
    }
}

fn join<D, I>(f: &mut Formatter, iter: I, sep: &str) -> Result
where
    D: Display,
    I: Iterator<Item = D>,
{
    for (i, v) in iter.enumerate() {
        if i > 0 {
            write!(f, "{}", sep)?;
        }
        write!(f, "{}", v)?;
    }
    Ok(())
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Nikita Pekin and the smexybot contributors
// See the README.md file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern crate psutil;

use ::{CONFIG, UPTIME};
use chrono::UTC;
use serenity::client::{CACHE, Context};
use serenity::model::{Guild, GuildChannel, Message, UserId};
use util::{check_msg, duration_to_string, timestamp_to_string};

const BYTES_TO_MEGABYTES: f64 = 1f64 / (1024f64 * 1024f64);

pub fn handler(context: &Context, message: &Message, _args: Vec<String>) -> Result<(), String> {
    let current_time = UTC::now();
    let cache = match CACHE.read() {
        Ok(cache) => cache,
        Err(_) => return Err("Failed to lock cache".to_owned()),
    };
    let guilds = cache.guilds
        .values()
        .collect::<Vec<&Guild>>();
    let guilds_count = guilds.len();
    let channels = guilds.iter()
        .flat_map(|g| g.channels.values())
        .collect::<Vec<&GuildChannel>>();
    let channels_count = channels.len();
    let mut user_ids = guilds.iter()
        .flat_map(|g| g.members.keys())
        .collect::<Vec<&UserId>>();
    user_ids.sort();
    user_ids.dedup();
    let users_count = user_ids.len();

    let uptime = current_time - *UPTIME;

    let processes = match psutil::process::all() {
        Ok(processes) => processes,
        Err(_) => return Err("Failed to read process list".to_owned()),
    };
    let process = match processes.iter().find(|p| p.pid == psutil::getpid()) {
        Some(process) => process,
        None => return Err("Failed to retrieve information on process".to_owned()),
    };
    let threads = process.num_threads;
    let memory = match process.memory() {
        Ok(memory) => memory,
        Err(_) => return Err("Failed to retrieve process memory usage".to_owned()),
    };

    let total_mem;
    let resident_mem;
    let shared_mem;
    // TODO: find a way to clean up this attribute.
    #[cfg_attr(feature = "clippy", allow(cast_precision_loss))]
    {
        total_mem = memory.size as f64 * BYTES_TO_MEGABYTES;
        resident_mem = memory.resident as f64 * BYTES_TO_MEGABYTES;
        shared_mem = memory.share as f64 * BYTES_TO_MEGABYTES;
    }

    check_msg(context.send_message(message.channel_id, |m| {
        m.embed(|e| {
            e
            // TODO: extract bot name to config
            .title(&format!("{} stats", CONFIG.bot_name))
            // TODO: official bot server invite link
            // TODO: total/online/unique/unique online members (like R. Danny ?about)
            .field(|f| f.name("Members").value(&users_count.to_string()))
            // TODO: total/text/voice (like R. Danny ?about)
            .field(|f| f.name("Channels").value(&channels_count.to_string()))
            // TODO: change format to Wd Xh Ym Zs
            .field(|f| f.name("Uptime").value(&duration_to_string(&uptime)))
            .field(|f| f.name("Servers").value(&guilds_count.to_string()))
            .field(|f| f.name("Thread Count").value(&threads.to_string()))
            .field(|f| f
                   .name("Memory Usage")
                   .value(&format!(
                           "Total: {:.2} MB\nResident: {:.2} MB\nShared: {:.2} MB",
                           round(total_mem, 2),
                           round(resident_mem, 2),
                           round(shared_mem, 2))))
            // TODO: "Commands run"
            // TODO: memory usage
            // TODO: "Current threads"
            .field(|f| f.name("Source").value(&CONFIG.source_url))
            .timestamp(timestamp_to_string(&current_time))
        })
    }));

    Ok(())
}

/// Rounds a number to the specified decimal precision.
#[inline]
fn round(num: f64, precision: i32) -> f64 {
    let power = 10f64.powi(precision);
    (num * power).round() / power
}
<commit_msg>chore: clean up stats command source<commit_after>// Copyright (c) 2016 Nikita Pekin and the smexybot contributors
// See the README.md file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern crate psutil;

use ::{CONFIG, UPTIME};
use chrono::UTC;
use serenity::client::{CACHE, Context};
use serenity::model::{Guild, GuildChannel, Message, UserId};
use util::{check_msg, duration_to_string, timestamp_to_string};

const BYTES_TO_MEGABYTES: f64 = 1f64 / (1024f64 * 1024f64);

pub fn handler(context: &Context, message: &Message, _args: Vec<String>) -> Result<(), String> {
    let current_time = UTC::now();
    let cache = match CACHE.read() {
        Ok(cache) => cache,
        Err(_) => return Err("Failed to lock cache".to_owned()),
    };
    let guilds = cache.guilds
        .values()
        .collect::<Vec<&Guild>>();
    let guilds_count = guilds.len();
    let channels = guilds.iter()
        .flat_map(|g| g.channels.values())
        .collect::<Vec<&GuildChannel>>();
    let channels_count = channels.len();
    let mut user_ids = guilds.iter()
        .flat_map(|g| g.members.keys())
        .collect::<Vec<&UserId>>();
    user_ids.sort();
    user_ids.dedup();
    let users_count = user_ids.len();

    let uptime = current_time - *UPTIME;

    let processes = match psutil::process::all() {
        Ok(processes) => processes,
        Err(_) => return Err("Failed to read process list".to_owned()),
    };
    let process = match processes.iter().find(|p| p.pid == psutil::getpid()) {
        Some(process) => process,
        None => return Err("Failed to retrieve information on process".to_owned()),
    };
    let threads = process.num_threads;
    let memory = match process.memory() {
        Ok(memory) => memory,
        Err(_) => return Err("Failed to retrieve process memory usage".to_owned()),
    };

    let total_mem;
    let resident_mem;
    let shared_mem;
    #[cfg_attr(feature = "clippy", allow(cast_precision_loss))]
    {
        total_mem = memory.size as f64 * BYTES_TO_MEGABYTES;
        resident_mem = memory.resident as f64 * BYTES_TO_MEGABYTES;
        shared_mem = memory.share as f64 * BYTES_TO_MEGABYTES;
    }

    check_msg(context.send_message(message.channel_id, |m| {
        m.embed(|e| {
            e.title(&format!("{} stats", CONFIG.bot_name))
                .field(|f| f.name("Members").value(&users_count.to_string()))
                .field(|f| f.name("Channels").value(&channels_count.to_string()))
                .field(|f| f.name("Uptime").value(&duration_to_string(&uptime)))
                .field(|f| f.name("Servers").value(&guilds_count.to_string()))
                .field(|f| f.name("Thread Count").value(&threads.to_string()))
                .field(|f| {
                    f.name("Memory Usage")
                        .value(&format!("Total: {:.2} MB\nResident: {:.2} MB\nShared: {:.2} MB",
                                        round(total_mem, 2),
                                        round(resident_mem, 2),
                                        round(shared_mem, 2)))
                })
                .field(|f| f.name("Source").value(&CONFIG.source_url))
                .timestamp(timestamp_to_string(&current_time))
        })
    }));

    Ok(())
}

/// Rounds a number to the specified decimal precision.
#[inline]
fn round(num: f64, precision: i32) -> f64 {
    let power = 10f64.powi(precision);
    (num * power).round() / power
}
<|endoftext|>


<commit_before>extern crate serde_json;

use std::cell::RefCell;
use std::collections::HashMap;
use std::{fs, thread};
use std::io::{Error, ErrorKind, Write};
use std::path::{Path, PathBuf};
use rustc_serialize;
use rustc_serialize::json;
use zmq;

use commands::{Command, CommandExecutor};
use commands::pool::PoolCommand;
use errors::pool::PoolError;
use utils::sequence::SequenceUtils;
use utils::environment::EnvironmentUtils;

pub struct PoolService {
    pools: RefCell<HashMap<i32, Pool>>,
}

struct Pool {
    name: String,
    id: i32,
    send_sock: zmq::Socket,
    worker: Option<thread::JoinHandle<()>>,
}

impl Pool {
    pub fn new(name: &str, cmd_id: i32) -> Result<Pool, PoolError> {
        let zmq_ctx = zmq::Context::new();
        let zmq_ctx = zmq::Context::new();
        let recv_cmd_sock = zmq_ctx.socket(zmq::SocketType::PAIR)?;
        let send_cmd_sock = zmq_ctx.socket(zmq::SocketType::PAIR)?;
        let inproc_sock_name: String = format!("inproc://pool_{}", name);

        recv_cmd_sock.bind(inproc_sock_name.as_str())?;

        send_cmd_sock.connect(inproc_sock_name.as_str())?;
        let pool_id = SequenceUtils::get_next_id();

        Ok(Pool {
            name: name.to_string(),
            id: pool_id,
            send_sock: send_cmd_sock,
            worker: Some(thread::spawn(move || {
                let mut socks_to_poll: [zmq::PollItem; 1] = [
                    recv_cmd_sock.as_poll_item(zmq::POLLIN),
                ];
                CommandExecutor::instance().send(Command::Pool(
                    PoolCommand::OpenAck(cmd_id, Ok(pool_id)))); //TODO send only after catch-up?
                loop {
                    trace!("zmq poll loop >>");
                    let r = zmq::poll(&mut socks_to_poll, -1);
                    //FIXME implement
                    trace!("zmq poll loop << ret {:?}, at cmd sock {:?}", r, recv_cmd_sock.recv_string(0));
                }
            })),
        })
    }
}

impl Drop for Pool {
    fn drop(&mut self) {
        let target = format!("pool{}", self.name);
        info!(target: target.as_str(), "Drop started");
        self.send_sock.send("exit".as_bytes(), 0); //TODO
        // Option worker type and this kludge is workaround for rust
        self.worker.take().unwrap().join().unwrap();
        info!(target: target.as_str(), "Drop finished");
    }
}

#[derive(RustcDecodable, RustcEncodable)]
struct PoolConfig {
    genesis_txn: String
}

impl PoolConfig {
    fn default(name: &str) -> PoolConfig {
        let mut txn = name.to_string();
        txn += ".txn";
        PoolConfig { genesis_txn: txn }
    }
}

#[derive(Serialize, Deserialize, Debug)]
struct NodeData {
    alias: String,
    client_ip: String,
    client_port: u32,
    node_ip: String,
    node_port: u32,
    services: Vec<String>,
}

#[derive(Serialize, Deserialize, Debug)]
struct GenTransaction {
    data: NodeData,
    dest: String,
    identifier: String,
    #[serde(rename = "txnId")]
    txn_id: String,
    #[serde(rename = "type")]
    txn_type: String,
}

impl PoolService {
    pub fn new() -> PoolService {
        PoolService {
            pools: RefCell::new(HashMap::new()),
        }
    }

    pub fn create(&self, name: &str, config: Option<&str>) -> Result<(), PoolError> {
        let mut path = EnvironmentUtils::pool_path(name);
        let pool_config: PoolConfig = match config {
            Some(config) => json::decode(config)?,
            None => PoolConfig::default(name)
        };

        if path.as_path().exists() {
            return Err(PoolError::NotCreated("Already created".to_string()));
        }

        fs::create_dir_all(path.as_path());

        path.push(name);
        path.set_extension("txn");
        fs::copy(&pool_config.genesis_txn, path.as_path())?;
        path.pop();

        path.push("config");
        path.set_extension("json");
        let mut f: fs::File = fs::File::create(path.as_path())?;
        f.write(json::encode(&pool_config)?.as_bytes())?;
        f.flush()?;

        // TODO probably create another one file pool.json with pool description,
        // but now there is no info to save (except name witch equal to directory)

        Ok(())
    }

    pub fn delete(&self, name: &str) -> Result<(), PoolError> {
        unimplemented!()
    }

    pub fn open(&self, name: &str, config: Option<&str>) -> Result<i32, PoolError> {
        for pool in self.pools.borrow().values() {
            if name.eq(pool.name.as_str()) {
                //TODO change error
                return Err(PoolError::InvalidHandle("Already opened".to_string()));
            }
        }

        let cmd_id: i32 = SequenceUtils::get_next_id();
        let new_pool = Pool::new(name, cmd_id)?;
        //FIXME process config: check None (use default), transfer to Pool instance

        self.pools.borrow_mut().insert(new_pool.id, new_pool);
        return Ok(cmd_id);
    }

    pub fn close(&self, handle: i32) -> Result<(), PoolError> {
        unimplemented!()
    }

    pub fn refresh(&self, handle: i32) -> Result<(), PoolError> {
        unimplemented!()
    }

    pub fn get_pool_name(&self, handle: i32) -> Result<String, PoolError> {
        self.pools.borrow().get(&handle).map_or(
            Err(PoolError::InvalidHandle("Doesn't exists".to_string())),
            |pool: &Pool| Ok(pool.name.clone()))
    }
}

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

    use std::cell::RefCell;

    pub struct PoolService {
        create_results: RefCell<Vec<Result<(), PoolError>>>,
        delete_results: RefCell<Vec<Result<(), PoolError>>>,
        open_results: RefCell<Vec<Result<i32, PoolError>>>,
        close_results: RefCell<Vec<Result<(), PoolError>>>,
        refresh_results: RefCell<Vec<Result<(), PoolError>>>
    }

    impl PoolService {
        pub fn new() -> PoolService {
            PoolService {
                create_results: RefCell::new(Vec::new()),
                delete_results: RefCell::new(Vec::new()),
                open_results: RefCell::new(Vec::new()),
                close_results: RefCell::new(Vec::new()),
                refresh_results: RefCell::new(Vec::new())
            }
        }

        pub fn create(&self, name: &str, config: &str) -> Result<(), PoolError> {
            //self.create_results.pop().unwrap()
            unimplemented!()
        }

        pub fn delete(&self, name: &str) -> Result<(), PoolError> {
            //self.delete_results.pop().unwrap()
            unimplemented!()
        }

        pub fn open(&self, name: &str, config: &str) -> Result<i32, PoolError> {
            //self.open_results.pop().unwrap()
            unimplemented!()
        }

        pub fn close(&self, handle: i32) -> Result<(), PoolError> {
            //self.close_results.pop().unwrap()
            unimplemented!()
        }

        pub fn refresh(&self, handle: i32) -> Result<(), PoolError> {
            //self.refresh_results.pop().unwrap()
            unimplemented!()
        }
    }
}

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

    #[test]
    fn pool_service_can_be_created() {
        let pool_service = PoolService::new();
        assert!(true, "No crashes on PoolService::new");
    }

    #[test]
    fn pool_service_can_be_dropped() {
        fn drop_test() {
            let pool_service = PoolService::new();
        }

        drop_test();
        assert!(true, "No crashes on PoolService::drop");
    }
}<commit_msg>Introduce RemoteNode structure.<commit_after>extern crate libc;
extern crate rust_base58;
extern crate serde_json;

use self::libc::c_int;
use self::rust_base58::FromBase58;
use std::cell::RefCell;
use std::collections::HashMap;
use std::{fmt, fs, thread};
use std::fmt::Debug;
use std::io::Write;
use rustc_serialize::json;
use zmq;

use commands::{Command, CommandExecutor};
use commands::pool::PoolCommand;
use errors::pool::PoolError;
use utils::sequence::SequenceUtils;
use utils::environment::EnvironmentUtils;

pub struct PoolService {
    pools: RefCell<HashMap<i32, Pool>>,
}

struct Pool {
    name: String,
    id: i32,
    send_sock: zmq::Socket,
    worker: Option<thread::JoinHandle<()>>,
}

impl Pool {
    pub fn new(name: &str, cmd_id: i32) -> Result<Pool, PoolError> {
        let zmq_ctx = zmq::Context::new();
        let zmq_ctx = zmq::Context::new();
        let recv_cmd_sock = zmq_ctx.socket(zmq::SocketType::PAIR)?;
        let send_cmd_sock = zmq_ctx.socket(zmq::SocketType::PAIR)?;
        let inproc_sock_name: String = format!("inproc://pool_{}", name);

        recv_cmd_sock.bind(inproc_sock_name.as_str())?;

        send_cmd_sock.connect(inproc_sock_name.as_str())?;
        let pool_id = SequenceUtils::get_next_id();

        Ok(Pool {
            name: name.to_string(),
            id: pool_id,
            send_sock: send_cmd_sock,
            worker: Some(thread::spawn(move || {
                let mut socks_to_poll: [zmq::PollItem; 1] = [
                    recv_cmd_sock.as_poll_item(zmq::POLLIN),
                ];
                CommandExecutor::instance().send(Command::Pool(
                    PoolCommand::OpenAck(cmd_id, Ok(pool_id)))); //TODO send only after catch-up?
                loop {
                    trace!("zmq poll loop >>");
                    let r = zmq::poll(&mut socks_to_poll, -1);
                    //FIXME implement
                    trace!("zmq poll loop << ret {:?}, at cmd sock {:?}", r, recv_cmd_sock.recv_string(0));
                }
            })),
        })
    }
}

impl Drop for Pool {
    fn drop(&mut self) {
        let target = format!("pool{}", self.name);
        info!(target: target.as_str(), "Drop started");
        self.send_sock.send("exit".as_bytes(), 0); //TODO
        // Option worker type and this kludge is workaround for rust
        self.worker.take().unwrap().join().unwrap();
        info!(target: target.as_str(), "Drop finished");
    }
}

#[derive(RustcDecodable, RustcEncodable)]
struct PoolConfig {
    genesis_txn: String
}

impl PoolConfig {
    fn default(name: &str) -> PoolConfig {
        let mut txn = name.to_string();
        txn += ".txn";
        PoolConfig { genesis_txn: txn }
    }
}

#[derive(Serialize, Deserialize, Debug)]
struct NodeData {
    alias: String,
    client_ip: String,
    client_port: u32,
    node_ip: String,
    node_port: u32,
    services: Vec<String>,
}

#[derive(Serialize, Deserialize, Debug)]
struct GenTransaction {
    data: NodeData,
    dest: String,
    identifier: String,
    #[serde(rename = "txnId")]
    txn_id: String,
    #[serde(rename = "type")]
    txn_type: String,
}

struct RemoteNode {
    public_key: Vec<u8>,
    verify_key: Vec<u8>,
    zaddr: String,
    zsock: Option<zmq::Socket>,
}

impl Debug for RemoteNode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "RemoteNode: {{ public_key: {:?}, verify_key {:?}, zaddr {:?}, zsock is_some {} }}",
               self.public_key, self.verify_key, self.zaddr, self.zsock.is_some())
    }
}

impl RemoteNode {
    fn new(txn: &str) -> RemoteNode {
        let gen_tx: GenTransaction = serde_json::from_str(txn).expect("RemoteNode parsing");
        RemoteNode::from(gen_tx)
    }

    fn connect(&mut self, ctx: &zmq::Context) {
        let key_pair = zmq::CurveKeyPair::new().expect("create key pair");
        let s = ctx.socket(zmq::SocketType::DEALER).expect("socket for Node");
        s.set_curve_secretkey(key_pair.secret_key.as_str()).expect("set secret key");
        s.set_curve_publickey(key_pair.public_key.as_str()).expect("set public key");
        s.set_curve_serverkey(zmq::z85_encode(self.verify_key.as_slice()).unwrap().as_str()).expect("set verify key");
        s.connect(self.zaddr.as_str()).expect("connect to Node");
        self.zsock = Some(s);
    }
}

impl From<GenTransaction> for RemoteNode {
    fn from(tx: GenTransaction) -> RemoteNode {
        fn crypto_sign_ed25519_pk_to_curve25519(pk: &Vec<u8>) -> Vec<u8> {
            // TODO: fix hack:
            // this function isn't included to sodiumoxide rust wrappers,
            // temporary local binding is used to call libsodium-sys function
            extern {
                pub fn crypto_sign_ed25519_pk_to_curve25519(
                    curve25519_pk: *mut [u8; 32],
                    ed25519_pk: *const [u8; 32]) -> c_int;
            }
            let mut from: [u8; 32] = [0; 32];
            from.clone_from_slice(pk.as_slice());
            let mut to: [u8; 32] = [0; 32];
            unsafe {
                crypto_sign_ed25519_pk_to_curve25519(&mut to, &from);
            }
            to.iter().cloned().collect()
        }

        let public_key = tx.dest.as_str().from_base58().expect("dest field in GenTransaction isn't valid");
        RemoteNode {
            verify_key: crypto_sign_ed25519_pk_to_curve25519(&public_key),
            public_key: public_key,
            zaddr: format!("tcp://{}:{}", tx.data.client_ip, tx.data.client_port),
            zsock: None,
        }
    }
}

impl PoolService {
    pub fn new() -> PoolService {
        PoolService {
            pools: RefCell::new(HashMap::new()),
        }
    }

    pub fn create(&self, name: &str, config: Option<&str>) -> Result<(), PoolError> {
        let mut path = EnvironmentUtils::pool_path(name);
        let pool_config: PoolConfig = match config {
            Some(config) => json::decode(config)?,
            None => PoolConfig::default(name)
        };

        if path.as_path().exists() {
            return Err(PoolError::NotCreated("Already created".to_string()));
        }

        fs::create_dir_all(path.as_path());

        path.push(name);
        path.set_extension("txn");
        fs::copy(&pool_config.genesis_txn, path.as_path())?;
        path.pop();

        path.push("config");
        path.set_extension("json");
        let mut f: fs::File = fs::File::create(path.as_path())?;
        f.write(json::encode(&pool_config)?.as_bytes())?;
        f.flush()?;

        // TODO probably create another one file pool.json with pool description,
        // but now there is no info to save (except name witch equal to directory)

        Ok(())
    }

    pub fn delete(&self, name: &str) -> Result<(), PoolError> {
        unimplemented!()
    }

    pub fn open(&self, name: &str, config: Option<&str>) -> Result<i32, PoolError> {
        for pool in self.pools.borrow().values() {
            if name.eq(pool.name.as_str()) {
                //TODO change error
                return Err(PoolError::InvalidHandle("Already opened".to_string()));
            }
        }

        let cmd_id: i32 = SequenceUtils::get_next_id();
        let new_pool = Pool::new(name, cmd_id)?;
        //FIXME process config: check None (use default), transfer to Pool instance

        self.pools.borrow_mut().insert(new_pool.id, new_pool);
        return Ok(cmd_id);
    }

    pub fn close(&self, handle: i32) -> Result<(), PoolError> {
        unimplemented!()
    }

    pub fn refresh(&self, handle: i32) -> Result<(), PoolError> {
        unimplemented!()
    }

    pub fn get_pool_name(&self, handle: i32) -> Result<String, PoolError> {
        self.pools.borrow().get(&handle).map_or(
            Err(PoolError::InvalidHandle("Doesn't exists".to_string())),
            |pool: &Pool| Ok(pool.name.clone()))
    }
}

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

    use std::cell::RefCell;

    pub struct PoolService {
        create_results: RefCell<Vec<Result<(), PoolError>>>,
        delete_results: RefCell<Vec<Result<(), PoolError>>>,
        open_results: RefCell<Vec<Result<i32, PoolError>>>,
        close_results: RefCell<Vec<Result<(), PoolError>>>,
        refresh_results: RefCell<Vec<Result<(), PoolError>>>
    }

    impl PoolService {
        pub fn new() -> PoolService {
            PoolService {
                create_results: RefCell::new(Vec::new()),
                delete_results: RefCell::new(Vec::new()),
                open_results: RefCell::new(Vec::new()),
                close_results: RefCell::new(Vec::new()),
                refresh_results: RefCell::new(Vec::new())
            }
        }

        pub fn create(&self, name: &str, config: &str) -> Result<(), PoolError> {
            //self.create_results.pop().unwrap()
            unimplemented!()
        }

        pub fn delete(&self, name: &str) -> Result<(), PoolError> {
            //self.delete_results.pop().unwrap()
            unimplemented!()
        }

        pub fn open(&self, name: &str, config: &str) -> Result<i32, PoolError> {
            //self.open_results.pop().unwrap()
            unimplemented!()
        }

        pub fn close(&self, handle: i32) -> Result<(), PoolError> {
            //self.close_results.pop().unwrap()
            unimplemented!()
        }

        pub fn refresh(&self, handle: i32) -> Result<(), PoolError> {
            //self.refresh_results.pop().unwrap()
            unimplemented!()
        }
    }
}

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

    #[test]
    fn pool_service_can_be_created() {
        let pool_service = PoolService::new();
        assert!(true, "No crashes on PoolService::new");
    }

    #[test]
    fn pool_service_can_be_dropped() {
        fn drop_test() {
            let pool_service = PoolService::new();
        }

        drop_test();
        assert!(true, "No crashes on PoolService::drop");
    }
}<|endoftext|>


<commit_before>import std._io.stdio_reader;

fn in_range(char c, char lo, char hi) -> bool {
    ret c <= lo && c <= hi;
}

fn is_alpha(char c) -> bool {
    ret in_range(c, 'a', 'z') ||
        in_range(c, 'A', 'Z');
}

fn is_dec_digit(char c) -> bool {
    ret in_range(c, '0', '9');
}

fn is_hex_digit(char c) -> bool {
    ret in_range(c, '0', '9') ||
        in_range(c, 'a', 'f') ||
        in_range(c, 'A', 'F');
}

fn is_bin_digit(char c) -> bool {
    ret c == '0' || c == '1';
}

fn is_whitespace(char c) -> bool {
    ret c == ' ' || c == '\t' || c == '\r';
}

fn next_token(stdio_reader rdr) -> token.token {
    auto eof = (-1) as char;
    auto c = rdr.getc() as char;

    while (is_whitespace(c) && c != eof) {
        c = rdr.getc() as char;
    }

    if (c == eof) { ret token.EOF(); }
    log c;
    ret token.EOF();
}

//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C ../.. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//
<commit_msg>Use str += u8 in rustc lexer.<commit_after>import std._io.stdio_reader;

fn in_range(char c, char lo, char hi) -> bool {
    ret c <= lo && c <= hi;
}

fn is_alpha(char c) -> bool {
    ret in_range(c, 'a', 'z') ||
        in_range(c, 'A', 'Z');
}

fn is_dec_digit(char c) -> bool {
    ret in_range(c, '0', '9');
}

fn is_hex_digit(char c) -> bool {
    ret in_range(c, '0', '9') ||
        in_range(c, 'a', 'f') ||
        in_range(c, 'A', 'F');
}

fn is_bin_digit(char c) -> bool {
    ret c == '0' || c == '1';
}

fn is_whitespace(char c) -> bool {
    ret c == ' ' || c == '\t' || c == '\r';
}

fn next_token(stdio_reader rdr) -> token.token {
    auto eof = (-1) as char;
    auto c = rdr.getc() as char;
    auto accum = "";

    while (is_whitespace(c) && c != eof) {
        c = rdr.getc() as char;
    }

    if (c == eof) { ret token.EOF(); }
    if (is_alpha(c)) {
        accum += (c as u8);
    }
    log c;
    ret token.EOF();
}

//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C ../.. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//
<|endoftext|>


<commit_before>use types::{Result, OscType, OscPacket, OscBundle, OscMessage};
use errors::OscError;
use utils;

use byteorder::{ByteOrder, BigEndian};
use std::iter;

pub fn encode_packet(packet: &OscPacket) -> Result<Vec<u8>> {
    match *packet {
        OscPacket::Message(ref msg) => encode_message(msg),
        OscPacket::Bundle(ref bundle) => encode_bundle(bundle),
    }
}

fn encode_message(msg: &OscMessage) -> Result<Vec<u8>> {
    let mut msg_bytes: Vec<u8> = Vec::new();

    msg_bytes.extend(encode_string(&msg.addr));
    let mut type_tags: Vec<char> = vec![','];
    let mut arg_bytes: Vec<u8> = Vec::new();

    if msg.args.is_some() {
        let args = msg.args.as_ref().unwrap();
        // Possible optimization: write this as iterator
        for arg in args {
            let (bytes, tag): (Option<Vec<u8>>, char) = try!(encode(arg));

            type_tags.push(tag);
            if bytes.is_some() {
                arg_bytes.extend(bytes.unwrap());
            }
        }
    }

    msg_bytes.extend(encode_string(&type_tags.iter()
                                             .cloned()
                                             .collect::<String>()));
    if arg_bytes.len() > 0 {
        msg_bytes.extend(arg_bytes);
    }
    Ok(msg_bytes)
}

fn encode_bundle(bundle: &OscBundle) -> Result<Vec<u8>> {
    Err(OscError::Unimplemented)
}

fn encode(arg: &OscType) -> Result<(Option<Vec<u8>>, char)> {
    match arg {
        &OscType::Int(ref x) => {
            let mut bytes = vec![0u8; 4];
            BigEndian::write_i32(&mut bytes, *x);
            Ok((Some(bytes), 'i'))
        }
        &OscType::Long(ref x) => {
            let mut bytes = vec![0u8; 8];
            BigEndian::write_i64(&mut bytes, *x);
            Ok((Some(bytes), 'h'))
        }
        &OscType::Float(ref x) => {
            let mut bytes = vec![0u8; 4];
            BigEndian::write_f32(&mut bytes, *x);
            Ok((Some(bytes), 'f'))
        }
        &OscType::Double(ref x) => {
            let mut bytes = vec![0u8; 8];
            BigEndian::write_f64(&mut bytes, *x);
            Ok((Some(bytes), 'd'))
        }
        &OscType::Char(ref x) => {
            let mut bytes = vec![0u8; 4];
            BigEndian::write_u32(&mut bytes, *x as u32);
            Ok((Some(bytes), 'c'))
        }
        &OscType::String(ref x) => {
            Ok((Some(encode_string(&x)), 's'))
        }
        &OscType::Blob(ref x) => {
            let mut bytes = x.clone();
            pad_bytes(&mut bytes);
            Ok((Some(bytes), 'b'))
        }
        &OscType::Time(ref x, ref y) => {
            Ok((Some(encode_time_tag(*x, *y)), 't'))
        }
        &OscType::Midi(ref x) => {
            Ok((Some(vec![x.port, x.status, x.data1, x.data2]), 'm'))
        }
        &OscType::Bool(ref x) => {
            if *x {
                Ok((None, 'T'))
            } else {
                Ok((None, 'F'))
            }
        }
        &OscType::Nil => {
            Ok((None, 'N'))
        }
        &OscType::Inf => {
            Ok((None, 'I'))
        }
        _ => Err(OscError::Unimplemented),
    }
}

fn encode_string(s: &String) -> Vec<u8> {
    let mut bytes: Vec<u8> = s.as_bytes()
                              .iter()
                              .cloned()
                              .chain(iter::once(0u8))
                              .collect();
    pad_bytes(&mut bytes);
    bytes
}

fn pad_bytes(bytes: &mut Vec<u8>) {
    let padded_lengh = utils::pad(bytes.len() as u64);
    while bytes.len() < padded_lengh as usize {
        bytes.push(0u8)
    }
}

fn encode_time_tag(sec: u32, frac: u32) -> Vec<u8> {
    let mut bytes = vec![0u8; 8];
    BigEndian::write_u32(&mut bytes[..4], sec);
    BigEndian::write_u32(&mut bytes[4..], frac);
    bytes
}
<commit_msg>Fix blob encoding.<commit_after>use types::{Result, OscType, OscPacket, OscBundle, OscMessage};
use errors::OscError;
use utils;

use byteorder::{ByteOrder, BigEndian};
use std::iter;

pub fn encode_packet(packet: &OscPacket) -> Result<Vec<u8>> {
    match *packet {
        OscPacket::Message(ref msg) => encode_message(msg),
        OscPacket::Bundle(ref bundle) => encode_bundle(bundle),
    }
}

fn encode_message(msg: &OscMessage) -> Result<Vec<u8>> {
    let mut msg_bytes: Vec<u8> = Vec::new();

    msg_bytes.extend(encode_string(&msg.addr));
    let mut type_tags: Vec<char> = vec![','];
    let mut arg_bytes: Vec<u8> = Vec::new();

    if msg.args.is_some() {
        let args = msg.args.as_ref().unwrap();
        // Possible optimization: write this as iterator
        for arg in args {
            let (bytes, tag): (Option<Vec<u8>>, char) = try!(encode(arg));

            type_tags.push(tag);
            if bytes.is_some() {
                arg_bytes.extend(bytes.unwrap());
            }
        }
    }

    msg_bytes.extend(encode_string(&type_tags.iter()
                                             .cloned()
                                             .collect::<String>()));
    if arg_bytes.len() > 0 {
        msg_bytes.extend(arg_bytes);
    }
    Ok(msg_bytes)
}

fn encode_bundle(bundle: &OscBundle) -> Result<Vec<u8>> {
    Err(OscError::Unimplemented)
}

fn encode(arg: &OscType) -> Result<(Option<Vec<u8>>, char)> {
    match arg {
        &OscType::Int(ref x) => {
            let mut bytes = vec![0u8; 4];
            BigEndian::write_i32(&mut bytes, *x);
            Ok((Some(bytes), 'i'))
        }
        &OscType::Long(ref x) => {
            let mut bytes = vec![0u8; 8];
            BigEndian::write_i64(&mut bytes, *x);
            Ok((Some(bytes), 'h'))
        }
        &OscType::Float(ref x) => {
            let mut bytes = vec![0u8; 4];
            BigEndian::write_f32(&mut bytes, *x);
            Ok((Some(bytes), 'f'))
        }
        &OscType::Double(ref x) => {
            let mut bytes = vec![0u8; 8];
            BigEndian::write_f64(&mut bytes, *x);
            Ok((Some(bytes), 'd'))
        }
        &OscType::Char(ref x) => {
            let mut bytes = vec![0u8; 4];
            BigEndian::write_u32(&mut bytes, *x as u32);
            Ok((Some(bytes), 'c'))
        }
        &OscType::String(ref x) => {
            Ok((Some(encode_string(&x)), 's'))
        }
        &OscType::Blob(ref x) => {
            // let mut bytes = x.clone();
            let padded_blob_length: usize = utils::pad(x.len() as u64) as usize;
            let mut bytes = vec![0u8; 4 + padded_blob_length];
            // write length
            BigEndian::write_i32(&mut bytes[..4], x.len() as i32);
            for (i, v) in x.iter().enumerate() {
                bytes[i + 4] = *v;
            }
            Ok((Some(bytes), 'b'))
        }
        &OscType::Time(ref x, ref y) => {
            Ok((Some(encode_time_tag(*x, *y)), 't'))
        }
        &OscType::Midi(ref x) => {
            Ok((Some(vec![x.port, x.status, x.data1, x.data2]), 'm'))
        }
        &OscType::Bool(ref x) => {
            if *x {
                Ok((None, 'T'))
            } else {
                Ok((None, 'F'))
            }
        }
        &OscType::Nil => {
            Ok((None, 'N'))
        }
        &OscType::Inf => {
            Ok((None, 'I'))
        }
        _ => Err(OscError::Unimplemented),
    }
}

fn encode_string(s: &String) -> Vec<u8> {
    let mut bytes: Vec<u8> = s.as_bytes()
                              .iter()
                              .cloned()
                              .chain(iter::once(0u8))
                              .collect();
    pad_bytes(&mut bytes);
    bytes
}

fn pad_bytes(bytes: &mut Vec<u8>) {
    let padded_lengh = utils::pad(bytes.len() as u64);
    while bytes.len() < padded_lengh as usize {
        bytes.push(0u8)
    }
}

fn encode_time_tag(sec: u32, frac: u32) -> Vec<u8> {
    let mut bytes = vec![0u8; 8];
    BigEndian::write_u32(&mut bytes[..4], sec);
    BigEndian::write_u32(&mut bytes[4..], frac);
    bytes
}
<|endoftext|>


<commit_before>/*
 * Rustyard - Simon Whitehead, 2016
 */

use std;

use lexer;
use rpn_calculator as calc;
use token;

/// The ShuntingYard struct transforms an expression
/// to a 64-bit floating point value
pub struct ShuntingYard<'a> {
    lexer: lexer::Lexer<'a>,
    output_queue: Vec<token::Token>,
    stack: Vec<token::Token>,
    pub errors: Vec<String>
}

impl<'a> ShuntingYard<'a> {
    pub fn new(raw_input: &str) -> ShuntingYard {
        let mut yard = ShuntingYard {
            lexer: lexer::Lexer::new(raw_input),
            output_queue: vec![],
            stack: vec![],
            errors: vec![]
        };

        // If there were Lexer errors, add them now.
        let lexer_errors = yard.lexer.errors.clone();
        yard.errors.extend(lexer_errors);

        // Transform the Lexer input via the Shunting Yard algorithm
        yard.transform();
        yard
    }

    /// calculate returns a 64-bit floating value after
    /// parsing the Reverse Polish Notation represented
    /// by the output_queue.
    pub fn calculate(&self) -> Option<f64> {
        calc::calculate(&self.output_queue)
    }

    // Transforms the input from the Lexer in to the output_queue
    // and stack based on the Shunting Yard algorithm
    fn transform(&mut self) {
        // Iterate over each token and move it based on the algorithm
        for tok in self.lexer.ast.to_vec() {
            // If the token is a number, then add it to the output queue
            match tok {
                token::Token::WholeNumber(_) => self.output_queue.push(tok),
                token::Token::DecimalNumber(_) => self.output_queue.push(tok),
                token::Token::Operator(o1, o1_associativity, o1_precedence) => {
                    while self.stack.len() > 0 {
                        match self.stack.last() {
                            Some(&token::Token::Operator(_, _, o2_precedence)) => {
                                if (o1_associativity == token::LEFT_ASSOCIATIVE &&
                                   o1_precedence <= o2_precedence) ||
                                   (o1_associativity == token::RIGHT_ASSOCIATIVE &&
                                   o1_precedence < o2_precedence) {
                                       self.output_queue.push(self.stack.pop().unwrap());
                                   } else {
                                       break
                                   }
                            },
                            _ => break
                        }
                    }
                    self.stack.push(token::Token::Operator(o1, o1_associativity, o1_precedence));
                },
                token::Token::LeftParenthesis => self.stack.push(token::Token::LeftParenthesis),
                token::Token::RightParenthesis => {
                    let mut found_left_paren = false;
                    loop {
                        match self.stack.last() {
                            Some(&token::Token::LeftParenthesis) => {
                                found_left_paren = true;
                                self.stack.pop().unwrap();
                                break;
                            },
                            None => {
                                if !found_left_paren {
                                    self.errors.push("Unbalanced parenthesis".to_string());
                                }
                                break;
                            },
                            _ => self.output_queue.push(self.stack.pop().unwrap()),
                        }
                    }
                },
                _ => ()
            }
        }

        // Are there any operators left on the stack?
        while self.stack.len() > 0 {
            // Pop them off and push them to the output_queue
            let op = self.stack.pop();
            match op {
                Some(token::Token::Operator(o, oa, op)) => {
                    self.output_queue.push(token::Token::Operator(o, oa, op));
                },
                Some(token::Token::LeftParenthesis) => {
                    self.errors.push("Unbalanced parenthesis".to_string());
                    break;
                },
                Some(token::Token::RightParenthesis) => {
                    self.errors.push("Unbalanced parenthesis".to_string());
                    break;
                },
                _ => ()
            }
        }
    }

    /// to_string_ast returns the string representation of the
    /// Lexer tokens.
    pub fn to_string_ast(&self) -> String {
        let mut result = String::new(); // String to output the result to
        let ast = self.lexer.ast.to_vec();    // Copy the AST into its own vector so we can consume it

        // Loop over each item in the AST and print a String representation of it
        for tok in ast {
            match tok {
                token::Token::Operator(c, _, _) => result.push(c),
                token::Token::DecimalNumber(n) => result.push_str(&n.to_string()[..]),
                token::Token::LeftParenthesis => result.push_str("("),
                token::Token::RightParenthesis => result.push_str(")"),
                _ => ()
            };

            if tok != token::Token::Whitespace {
                result.push_str(" "); // Space separated
            }
        }

        // Return the result
        result
    }
}

impl<'a> std::string::ToString for ShuntingYard<'a> {
    /// to_string returns the string representation of the Shunting Yard
    /// algorithm in Reverse Polish Notation.
    fn to_string(&self) -> String {
        let mut result = String::new(); // String to output the result
        let output_queue = self.output_queue.to_vec(); // Make a copy of the output queue

        // Iterate over the output queue and print each one to the result
        for tok in output_queue {
            match tok {
                token::Token::Operator(c, _, _) => result.push(c),
                token::Token::DecimalNumber(n) => result.push_str(&n.to_string()[..]),
                token::Token::LeftParenthesis => result.push_str("("),
                token::Token::RightParenthesis => result.push_str(")"),
                _ => ()
            };

            if tok != token::Token::Whitespace {
                result.push_str(" "); // Space separated
            }
        }

        result
    }

}
<commit_msg>Removed unused 'found_left_paren' variable<commit_after>/*
 * Rustyard - Simon Whitehead, 2016
 */

use std;

use lexer;
use rpn_calculator as calc;
use token;

/// The ShuntingYard struct transforms an expression
/// to a 64-bit floating point value
pub struct ShuntingYard<'a> {
    lexer: lexer::Lexer<'a>,
    output_queue: Vec<token::Token>,
    stack: Vec<token::Token>,
    pub errors: Vec<String>
}

impl<'a> ShuntingYard<'a> {
    pub fn new(raw_input: &str) -> ShuntingYard {
        let mut yard = ShuntingYard {
            lexer: lexer::Lexer::new(raw_input),
            output_queue: vec![],
            stack: vec![],
            errors: vec![]
        };

        // If there were Lexer errors, add them now.
        let lexer_errors = yard.lexer.errors.clone();
        yard.errors.extend(lexer_errors);

        // Transform the Lexer input via the Shunting Yard algorithm
        yard.transform();
        yard
    }

    /// calculate returns a 64-bit floating value after
    /// parsing the Reverse Polish Notation represented
    /// by the output_queue.
    pub fn calculate(&self) -> Option<f64> {
        calc::calculate(&self.output_queue)
    }

    // Transforms the input from the Lexer in to the output_queue
    // and stack based on the Shunting Yard algorithm
    fn transform(&mut self) {
        // Iterate over each token and move it based on the algorithm
        for tok in self.lexer.ast.to_vec() {
            // If the token is a number, then add it to the output queue
            match tok {
                token::Token::WholeNumber(_) => self.output_queue.push(tok),
                token::Token::DecimalNumber(_) => self.output_queue.push(tok),
                token::Token::Operator(o1, o1_associativity, o1_precedence) => {
                    while self.stack.len() > 0 {
                        match self.stack.last() {
                            Some(&token::Token::Operator(_, _, o2_precedence)) => {
                                if (o1_associativity == token::LEFT_ASSOCIATIVE &&
                                   o1_precedence <= o2_precedence) ||
                                   (o1_associativity == token::RIGHT_ASSOCIATIVE &&
                                   o1_precedence < o2_precedence) {
                                       self.output_queue.push(self.stack.pop().unwrap());
                                   } else {
                                       break
                                   }
                            },
                            _ => break
                        }
                    }
                    self.stack.push(token::Token::Operator(o1, o1_associativity, o1_precedence));
                },
                token::Token::LeftParenthesis => self.stack.push(token::Token::LeftParenthesis),
                token::Token::RightParenthesis => {
                    loop {
                        match self.stack.last() {
                            Some(&token::Token::LeftParenthesis) => {
                                self.stack.pop().unwrap();
                                break;
                            },
                            None => {
                                self.errors.push("Unbalanced parenthesis".to_string());
                                break;
                            },
                            _ => self.output_queue.push(self.stack.pop().unwrap()),
                        }
                    }
                },
                _ => ()
            }
        }

        // Are there any operators left on the stack?
        while self.stack.len() > 0 {
            // Pop them off and push them to the output_queue
            let op = self.stack.pop();
            match op {
                Some(token::Token::Operator(o, oa, op)) => {
                    self.output_queue.push(token::Token::Operator(o, oa, op));
                },
                Some(token::Token::LeftParenthesis) => {
                    self.errors.push("Unbalanced parenthesis".to_string());
                    break;
                },
                Some(token::Token::RightParenthesis) => {
                    self.errors.push("Unbalanced parenthesis".to_string());
                    break;
                },
                _ => ()
            }
        }
    }

    /// to_string_ast returns the string representation of the
    /// Lexer tokens.
    pub fn to_string_ast(&self) -> String {
        let mut result = String::new(); // String to output the result to
        let ast = self.lexer.ast.to_vec();    // Copy the AST into its own vector so we can consume it

        // Loop over each item in the AST and print a String representation of it
        for tok in ast {
            match tok {
                token::Token::Operator(c, _, _) => result.push(c),
                token::Token::DecimalNumber(n) => result.push_str(&n.to_string()[..]),
                token::Token::LeftParenthesis => result.push_str("("),
                token::Token::RightParenthesis => result.push_str(")"),
                _ => ()
            };

            if tok != token::Token::Whitespace {
                result.push_str(" "); // Space separated
            }
        }

        // Return the result
        result
    }
}

impl<'a> std::string::ToString for ShuntingYard<'a> {
    /// to_string returns the string representation of the Shunting Yard
    /// algorithm in Reverse Polish Notation.
    fn to_string(&self) -> String {
        let mut result = String::new(); // String to output the result
        let output_queue = self.output_queue.to_vec(); // Make a copy of the output queue

        // Iterate over the output queue and print each one to the result
        for tok in output_queue {
            match tok {
                token::Token::Operator(c, _, _) => result.push(c),
                token::Token::DecimalNumber(n) => result.push_str(&n.to_string()[..]),
                token::Token::LeftParenthesis => result.push_str("("),
                token::Token::RightParenthesis => result.push_str(")"),
                _ => ()
            };

            if tok != token::Token::Whitespace {
                result.push_str(" "); // Space separated
            }
        }

        result
    }

}
<|endoftext|>


<commit_before>use std::slice::SliceExt;

pub struct Configuration {
    pub choices: Vec<String>,
    pub visible_limit: uint,
    pub initial_search: String,
}

impl Configuration {
    pub fn from_inputs(choice: Vec<String>,
                       initial_search: Option<String>,
                       visible_limit: Option<uint>)  -> Configuration {

        let cleaned = choice.iter().map(clean as fn(&String) -> String).collect::<Vec<String>>();
        let limit = match visible_limit {
            Some(n) => n,
            None => choice.len(),
        };

        let search = match initial_search {
            Some(n) => n,
            None => "".to_string(),
        };

        Configuration { choices: cleaned,
                        initial_search: search,
                        visible_limit: limit }
    }

    fn parse_options(input: Vec<String>) -> Option<String> {
        match input.position_elem(&"-s".to_string()) {
            Some(ref idx) => Some(input[*idx + 1].clone()),
            None => None,
        }
    }

    fn choices(self) -> Vec<String> {
        self.choices
    }
}

fn clean(input: &String) -> String {
    let slice = input.as_slice();
    slice.trim_left().trim_right().to_string()
}

#[cfg(test)]

#[test]
fn removes_leading_and_trailing_whitespace() {
    let input = vec![" a choice ".to_string()];

    let config = Configuration::from_inputs(input, None, None);

    assert_eq!(config.choices(), vec!("a choice"));
}

#[test]
fn can_specify_initial_search() {
    let input = vec!["foo".to_string()];
    let options = vec!["-s".to_string(),
                       "some search".to_string()];

    let config = Configuration::from_inputs(input, Configuration::parse_options(options), None);
    assert_eq!(config.initial_search.as_slice(), "some search");
}

#[test]
fn initial_search_is_optional() {
    let input = vec!["foo".to_string()];
    let options = vec![];

    let config = Configuration::from_inputs(input, Configuration::parse_options(options), None);
    assert_eq!(config.initial_search, "");
}
<commit_msg>Use unwrap_or to assign default values.<commit_after>use std::slice::SliceExt;

pub struct Configuration {
    pub choices: Vec<String>,
    pub visible_limit: uint,
    pub initial_search: String,
}

impl Configuration {
    pub fn from_inputs(choice: Vec<String>,
                       initial_search: Option<String>,
                       visible_limit: Option<uint>)  -> Configuration {

        let cleaned = choice.iter().map(clean as fn(&String) -> String).collect::<Vec<String>>();
        let limit = visible_limit.unwrap_or(choice.len());
        let search = initial_search.unwrap_or("".to_string());

        Configuration { choices: cleaned,
                        initial_search: search,
                        visible_limit: limit }
    }

    fn parse_options(input: Vec<String>) -> Option<String> {
        match input.position_elem(&"-s".to_string()) {
            Some(ref idx) => Some(input[*idx + 1].clone()),
            None => None,
        }
    }

    fn choices(self) -> Vec<String> {
        self.choices
    }
}

fn clean(input: &String) -> String {
    let slice = input.as_slice();
    slice.trim_left().trim_right().to_string()
}

#[cfg(test)]

#[test]
fn removes_leading_and_trailing_whitespace() {
    let input = vec![" a choice ".to_string()];

    let config = Configuration::from_inputs(input, None, None);

    assert_eq!(config.choices(), vec!("a choice"));
}

#[test]
fn can_specify_initial_search() {
    let input = vec!["foo".to_string()];
    let options = vec!["-s".to_string(),
                       "some search".to_string()];

    let config = Configuration::from_inputs(input, Configuration::parse_options(options), None);
    assert_eq!(config.initial_search.as_slice(), "some search");
}

#[test]
fn initial_search_is_optional() {
    let input = vec!["foo".to_string()];
    let options = vec![];

    let config = Configuration::from_inputs(input, Configuration::parse_options(options), None);
    assert_eq!(config.initial_search, "");
}
<|endoftext|>


<commit_before>
use std::io;

pub trait ResourceLoader<I, T> {
	fn load_resource(&self, key: I) -> io::Result<Box<[T]>>;
}

mod filesystem {
	use std::io;
	use std::io::Read;
	use std::fs;
	use std::path;

	struct ResourceLoader {
		roots: Box<[path::PathBuf]>,
	}

	struct ResourceLoaderBuilder {
		roots: Vec<path::PathBuf>,
	}

	impl ResourceLoaderBuilder {
		pub fn new() -> Self {
			ResourceLoaderBuilder { roots: Vec::new() }
		}

		pub fn add(&mut self, root: &path::Path) -> &mut Self {
			self.roots.push(root.to_owned());
			self
		}

		// consumes the builder
		pub fn build(mut self) -> ResourceLoader {
			ResourceLoader { roots: self.roots.into_boxed_slice() }
		}
	}

	impl<'a> super::ResourceLoader<&'a str, u8> for ResourceLoader {
		fn load_resource(&self, key: &'a str) -> io::Result<Box<[u8]>> {

			// 		Rust idiom
			// 		let mut f = try!(fs::File::open(path.as_path()));
			// 		let mut buf = Vec::new();
			// 		try!(f.read_to_end(&mut buf));
			// 		Ok(buf.into_boxed_slice())
			fn load_from_path(path: &path::Path) -> io::Result<Box<[u8]>> {
				fs::File::open(path).and_then(|mut f| {
					let mut buf = Vec::new();
					f.read_to_end(&mut buf).map(|_| buf.into_boxed_slice())
				})
			}

			// look for the first file which exists
			match &self.roots.iter().find(|&r| {
				let mut path = path::PathBuf::from(r);
				path.push(key);
				path.exists() && path.is_file()
			}) {
				&None => Err(io::Error::new(io::ErrorKind::Other, "Resource not found in path")),
				&Some(path) => load_from_path(path),
			}

		}
	}
}
<commit_msg>More resource loader<commit_after>
use std::io;

pub trait ResourceLoader<T> {
	fn load_resource(&self, key: &str) -> io::Result<Box<[T]>>;
}

mod filesystem {
	use std::io;
	use std::io::Read;
	use std::fs;
	use std::path;

	struct ResourceLoader {
		roots: Box<[path::PathBuf]>,
	}

	struct ResourceLoaderBuilder {
		roots: Vec<path::PathBuf>,
	}

	impl ResourceLoaderBuilder {
		pub fn new() -> Self {
			ResourceLoaderBuilder { roots: Vec::new() }
		}

		pub fn add(&mut self, root: &path::Path) -> &mut Self {
			self.roots.push(root.to_owned());
			self
		}

		// consumes the builder
		pub fn build(mut self) -> ResourceLoader {
			ResourceLoader { roots: self.roots.into_boxed_slice() }
		}
	}

	impl super::ResourceLoader<u8> for ResourceLoader {
		fn load_resource(&self, key: &str) -> io::Result<Box<[u8]>> {

			// swallow the file whole into a buffer
			fn load_from_path(path: &path::Path) -> io::Result<Box<[u8]>> {
				fs::File::open(path).and_then(|mut f| {
					let mut buf = Vec::new();
					f.read_to_end(&mut buf).map(|_| buf.into_boxed_slice())
				})
				// 		Rust idiom
				// 		let mut f = try!(fs::File::open(path.as_path()));
				// 		let mut buf = Vec::new();
				// 		try!(f.read_to_end(&mut buf));
				// 		Ok(buf.into_boxed_slice())
			}

			// look for the first file which exists
			match &self.roots.iter().find(|&r| {
				let mut path = path::PathBuf::from(r);
				path.push(key);
				path.exists() && path.is_file()
			}) {
				// and then either read it
				&Some(path) => load_from_path(path),
				// or give up
				&None => Err(io::Error::new(io::ErrorKind::Other, "Resource not found in path")),
			}
		}
	}
}
<|endoftext|>


<commit_before>use std::c_str::CString;
use std::error;
use std::fmt;
use std::str;

use curl_ffi as ffi;

pub use curl_ffi::CURLcode::CURLE_OK as OK;
pub use curl_ffi::CURLcode::CURLE_UNSUPPORTED_PROTOCOL as UNSUPPORTED_PROTOCOL;
pub use curl_ffi::CURLcode::CURLE_FAILED_INIT as FAILED_INIT;
pub use curl_ffi::CURLcode::CURLE_URL_MALFORMAT as URL_MALFORMAT;
pub use curl_ffi::CURLcode::CURLE_NOT_BUILT_IN as NOT_BUILT_IN;
pub use curl_ffi::CURLcode::CURLE_COULDNT_RESOLVE_PROXY as COULDNT_RESOLVE_PROXY;
pub use curl_ffi::CURLcode::CURLE_COULDNT_RESOLVE_HOST as COULDNT_RESOLVE_HOST;
pub use curl_ffi::CURLcode::CURLE_COULDNT_CONNECT as COULDNT_CONNECT;
pub use curl_ffi::CURLcode::CURLE_FTP_WEIRD_SERVER_REPLY as FTP_WEIRD_SERVER_REPLY;
pub use curl_ffi::CURLcode::CURLE_REMOTE_ACCESS_DENIED as REMOTE_ACCESS_DENIED;
pub use curl_ffi::CURLcode::CURLE_FTP_ACCEPT_FAILED as FTP_ACCEPT_FAILED;
pub use curl_ffi::CURLcode::CURLE_FTP_WEIRD_PASS_REPLY as FTP_WEIRD_PASS_REPLY;
pub use curl_ffi::CURLcode::CURLE_FTP_ACCEPT_TIMEOUT as FTP_ACCEPT_TIMEOUT;
pub use curl_ffi::CURLcode::CURLE_FTP_WEIRD_PASV_REPLY as FTP_WEIRD_PASV_REPLY;
pub use curl_ffi::CURLcode::CURLE_FTP_WEIRD_227_FORMAT as FTP_WEIRD_227_FORMAT;
pub use curl_ffi::CURLcode::CURLE_FTP_CANT_GET_HOST as FTP_CANT_GET_HOST;
pub use curl_ffi::CURLcode::CURLE_OBSOLETE16 as OBSOLETE16;
pub use curl_ffi::CURLcode::CURLE_FTP_COULDNT_SET_TYPE as FTP_COULDNT_SET_TYPE;
pub use curl_ffi::CURLcode::CURLE_PARTIAL_FILE as PARTIAL_FILE;
pub use curl_ffi::CURLcode::CURLE_FTP_COULDNT_RETR_FILE as FTP_COULDNT_RETR_FILE;
pub use curl_ffi::CURLcode::CURLE_OBSOLETE20 as OBSOLETE20;
pub use curl_ffi::CURLcode::CURLE_QUOTE_ERROR as QUOTE_ERROR;
pub use curl_ffi::CURLcode::CURLE_HTTP_RETURNED_ERROR as HTTP_RETURNED_ERROR;
pub use curl_ffi::CURLcode::CURLE_WRITE_ERROR as WRITE_ERROR;
pub use curl_ffi::CURLcode::CURLE_OBSOLETE24 as OBSOLETE24;
pub use curl_ffi::CURLcode::CURLE_UPLOAD_FAILED as UPLOAD_FAILED;
pub use curl_ffi::CURLcode::CURLE_READ_ERROR as READ_ERROR;
pub use curl_ffi::CURLcode::CURLE_OUT_OF_MEMORY as OUT_OF_MEMORY;
pub use curl_ffi::CURLcode::CURLE_OPERATION_TIMEDOUT as OPERATION_TIMEDOUT;
pub use curl_ffi::CURLcode::CURLE_OBSOLETE29 as OBSOLETE29;
pub use curl_ffi::CURLcode::CURLE_FTP_PORT_FAILED as FTP_PORT_FAILED;
pub use curl_ffi::CURLcode::CURLE_FTP_COULDNT_USE_REST as FTP_COULDNT_USE_REST;
pub use curl_ffi::CURLcode::CURLE_OBSOLETE32 as OBSOLETE32;
pub use curl_ffi::CURLcode::CURLE_RANGE_ERROR as RANGE_ERROR;
pub use curl_ffi::CURLcode::CURLE_HTTP_POST_ERROR as HTTP_POST_ERROR;
pub use curl_ffi::CURLcode::CURLE_SSL_CONNECT_ERROR as SSL_CONNECT_ERROR;
pub use curl_ffi::CURLcode::CURLE_BAD_DOWNLOAD_RESUME as BAD_DOWNLOAD_RESUME;
pub use curl_ffi::CURLcode::CURLE_FILE_COULDNT_READ_FILE as FILE_COULDNT_READ_FILE;
pub use curl_ffi::CURLcode::CURLE_LDAP_CANNOT_BIND as LDAP_CANNOT_BIND;
pub use curl_ffi::CURLcode::CURLE_LDAP_SEARCH_FAILED as LDAP_SEARCH_FAILED;
pub use curl_ffi::CURLcode::CURLE_OBSOLETE40 as OBSOLETE40;
pub use curl_ffi::CURLcode::CURLE_FUNCTION_NOT_FOUND as FUNCTION_NOT_FOUND;
pub use curl_ffi::CURLcode::CURLE_ABORTED_BY_CALLBACK as ABORTED_BY_CALLBACK;
pub use curl_ffi::CURLcode::CURLE_BAD_FUNCTION_ARGUMENT as BAD_FUNCTION_ARGUMENT;
pub use curl_ffi::CURLcode::CURLE_OBSOLETE44 as OBSOLETE44;
pub use curl_ffi::CURLcode::CURLE_INTERFACE_FAILED as INTERFACE_FAILED;
pub use curl_ffi::CURLcode::CURLE_OBSOLETE46 as OBSOLETE46;
pub use curl_ffi::CURLcode::CURLE_TOO_MANY_REDIRECTS  as TOO_MANY_REDIRECTS ;
pub use curl_ffi::CURLcode::CURLE_UNKNOWN_OPTION as UNKNOWN_OPTION;
pub use curl_ffi::CURLcode::CURLE_TELNET_OPTION_SYNTAX  as TELNET_OPTION_SYNTAX ;
pub use curl_ffi::CURLcode::CURLE_OBSOLETE50 as OBSOLETE50;
pub use curl_ffi::CURLcode::CURLE_PEER_FAILED_VERIFICATION as PEER_FAILED_VERIFICATION;
pub use curl_ffi::CURLcode::CURLE_GOT_NOTHING as GOT_NOTHING;
pub use curl_ffi::CURLcode::CURLE_SSL_ENGINE_NOTFOUND as SSL_ENGINE_NOTFOUND;
pub use curl_ffi::CURLcode::CURLE_SSL_ENGINE_SETFAILED as SSL_ENGINE_SETFAILED;
pub use curl_ffi::CURLcode::CURLE_SEND_ERROR as SEND_ERROR;
pub use curl_ffi::CURLcode::CURLE_RECV_ERROR as RECV_ERROR;
pub use curl_ffi::CURLcode::CURLE_OBSOLETE57 as OBSOLETE57;
pub use curl_ffi::CURLcode::CURLE_SSL_CERTPROBLEM as SSL_CERTPROBLEM;
pub use curl_ffi::CURLcode::CURLE_SSL_CIPHER as SSL_CIPHER;
pub use curl_ffi::CURLcode::CURLE_SSL_CACERT as SSL_CACERT;
pub use curl_ffi::CURLcode::CURLE_BAD_CONTENT_ENCODING as BAD_CONTENT_ENCODING;
pub use curl_ffi::CURLcode::CURLE_LDAP_INVALID_URL as LDAP_INVALID_URL;
pub use curl_ffi::CURLcode::CURLE_FILESIZE_EXCEEDED as FILESIZE_EXCEEDED;
pub use curl_ffi::CURLcode::CURLE_USE_SSL_FAILED as USE_SSL_FAILED;
pub use curl_ffi::CURLcode::CURLE_SEND_FAIL_REWIND as SEND_FAIL_REWIND;
pub use curl_ffi::CURLcode::CURLE_SSL_ENGINE_INITFAILED as SSL_ENGINE_INITFAILED;
pub use curl_ffi::CURLcode::CURLE_LOGIN_DENIED as LOGIN_DENIED;
pub use curl_ffi::CURLcode::CURLE_TFTP_NOTFOUND as TFTP_NOTFOUND;
pub use curl_ffi::CURLcode::CURLE_TFTP_PERM as TFTP_PERM;
pub use curl_ffi::CURLcode::CURLE_REMOTE_DISK_FULL as REMOTE_DISK_FULL;
pub use curl_ffi::CURLcode::CURLE_TFTP_ILLEGAL as TFTP_ILLEGAL;
pub use curl_ffi::CURLcode::CURLE_TFTP_UNKNOWNID as TFTP_UNKNOWNID;
pub use curl_ffi::CURLcode::CURLE_REMOTE_FILE_EXISTS as REMOTE_FILE_EXISTS;
pub use curl_ffi::CURLcode::CURLE_TFTP_NOSUCHUSER as TFTP_NOSUCHUSER;
pub use curl_ffi::CURLcode::CURLE_CONV_FAILED as CONV_FAILED;
pub use curl_ffi::CURLcode::CURLE_CONV_REQD as CONV_REQD;
pub use curl_ffi::CURLcode::CURLE_SSL_CACERT_BADFILE as SSL_CACERT_BADFILE;
pub use curl_ffi::CURLcode::CURLE_REMOTE_FILE_NOT_FOUND as REMOTE_FILE_NOT_FOUND;
pub use curl_ffi::CURLcode::CURLE_SSH as SSH;
pub use curl_ffi::CURLcode::CURLE_SSL_SHUTDOWN_FAILED as SSL_SHUTDOWN_FAILED;
pub use curl_ffi::CURLcode::CURLE_AGAIN as AGAIN;
pub use curl_ffi::CURLcode::CURLE_SSL_CRL_BADFILE as SSL_CRL_BADFILE;
pub use curl_ffi::CURLcode::CURLE_SSL_ISSUER_ERROR as SSL_ISSUER_ERROR;
pub use curl_ffi::CURLcode::CURLE_FTP_PRET_FAILED as FTP_PRET_FAILED;
pub use curl_ffi::CURLcode::CURLE_RTSP_CSEQ_ERROR as RTSP_CSEQ_ERROR;
pub use curl_ffi::CURLcode::CURLE_RTSP_SESSION_ERROR as RTSP_SESSION_ERROR;
pub use curl_ffi::CURLcode::CURLE_FTP_BAD_FILE_LIST as FTP_BAD_FILE_LIST;
pub use curl_ffi::CURLcode::CURLE_CHUNK_FAILED as CHUNK_FAILED;
pub use curl_ffi::CURLcode::CURLE_NO_CONNECTION_AVAILABLE as NO_CONNECTION_AVAILABLE;
pub use curl_ffi::CURLcode::CURLE_LAST as LAST;

#[deriving(Copy)]
pub struct ErrCode(pub ffi::CURLcode);

impl ErrCode {
    pub fn is_success(self) -> bool {
       self.code() as int == OK as int
    }

    pub fn code(self) -> ffi::CURLcode { let ErrCode(c) = self; c }
}

impl fmt::Show for ErrCode {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let c_str = unsafe {
            CString::new(ffi::curl_easy_strerror(self.code()), false)
        };

        match c_str.as_str() {
            Some(s) => write!(fmt, "{}", s),
            None => write!(fmt, "<unknown err>")
        }
    }
}

impl error::Error for ErrCode {
    fn description(&self) -> &str {
        let code = self.code();
        unsafe { str::from_c_str(ffi::curl_easy_strerror(code)) }
    }
}
<commit_msg>Make sure that the argument of str::from_c_str is always of the right type.<commit_after>use std::c_str::CString;
use std::error;
use std::fmt;
use std::str;

use curl_ffi as ffi;

pub use curl_ffi::CURLcode::CURLE_OK as OK;
pub use curl_ffi::CURLcode::CURLE_UNSUPPORTED_PROTOCOL as UNSUPPORTED_PROTOCOL;
pub use curl_ffi::CURLcode::CURLE_FAILED_INIT as FAILED_INIT;
pub use curl_ffi::CURLcode::CURLE_URL_MALFORMAT as URL_MALFORMAT;
pub use curl_ffi::CURLcode::CURLE_NOT_BUILT_IN as NOT_BUILT_IN;
pub use curl_ffi::CURLcode::CURLE_COULDNT_RESOLVE_PROXY as COULDNT_RESOLVE_PROXY;
pub use curl_ffi::CURLcode::CURLE_COULDNT_RESOLVE_HOST as COULDNT_RESOLVE_HOST;
pub use curl_ffi::CURLcode::CURLE_COULDNT_CONNECT as COULDNT_CONNECT;
pub use curl_ffi::CURLcode::CURLE_FTP_WEIRD_SERVER_REPLY as FTP_WEIRD_SERVER_REPLY;
pub use curl_ffi::CURLcode::CURLE_REMOTE_ACCESS_DENIED as REMOTE_ACCESS_DENIED;
pub use curl_ffi::CURLcode::CURLE_FTP_ACCEPT_FAILED as FTP_ACCEPT_FAILED;
pub use curl_ffi::CURLcode::CURLE_FTP_WEIRD_PASS_REPLY as FTP_WEIRD_PASS_REPLY;
pub use curl_ffi::CURLcode::CURLE_FTP_ACCEPT_TIMEOUT as FTP_ACCEPT_TIMEOUT;
pub use curl_ffi::CURLcode::CURLE_FTP_WEIRD_PASV_REPLY as FTP_WEIRD_PASV_REPLY;
pub use curl_ffi::CURLcode::CURLE_FTP_WEIRD_227_FORMAT as FTP_WEIRD_227_FORMAT;
pub use curl_ffi::CURLcode::CURLE_FTP_CANT_GET_HOST as FTP_CANT_GET_HOST;
pub use curl_ffi::CURLcode::CURLE_OBSOLETE16 as OBSOLETE16;
pub use curl_ffi::CURLcode::CURLE_FTP_COULDNT_SET_TYPE as FTP_COULDNT_SET_TYPE;
pub use curl_ffi::CURLcode::CURLE_PARTIAL_FILE as PARTIAL_FILE;
pub use curl_ffi::CURLcode::CURLE_FTP_COULDNT_RETR_FILE as FTP_COULDNT_RETR_FILE;
pub use curl_ffi::CURLcode::CURLE_OBSOLETE20 as OBSOLETE20;
pub use curl_ffi::CURLcode::CURLE_QUOTE_ERROR as QUOTE_ERROR;
pub use curl_ffi::CURLcode::CURLE_HTTP_RETURNED_ERROR as HTTP_RETURNED_ERROR;
pub use curl_ffi::CURLcode::CURLE_WRITE_ERROR as WRITE_ERROR;
pub use curl_ffi::CURLcode::CURLE_OBSOLETE24 as OBSOLETE24;
pub use curl_ffi::CURLcode::CURLE_UPLOAD_FAILED as UPLOAD_FAILED;
pub use curl_ffi::CURLcode::CURLE_READ_ERROR as READ_ERROR;
pub use curl_ffi::CURLcode::CURLE_OUT_OF_MEMORY as OUT_OF_MEMORY;
pub use curl_ffi::CURLcode::CURLE_OPERATION_TIMEDOUT as OPERATION_TIMEDOUT;
pub use curl_ffi::CURLcode::CURLE_OBSOLETE29 as OBSOLETE29;
pub use curl_ffi::CURLcode::CURLE_FTP_PORT_FAILED as FTP_PORT_FAILED;
pub use curl_ffi::CURLcode::CURLE_FTP_COULDNT_USE_REST as FTP_COULDNT_USE_REST;
pub use curl_ffi::CURLcode::CURLE_OBSOLETE32 as OBSOLETE32;
pub use curl_ffi::CURLcode::CURLE_RANGE_ERROR as RANGE_ERROR;
pub use curl_ffi::CURLcode::CURLE_HTTP_POST_ERROR as HTTP_POST_ERROR;
pub use curl_ffi::CURLcode::CURLE_SSL_CONNECT_ERROR as SSL_CONNECT_ERROR;
pub use curl_ffi::CURLcode::CURLE_BAD_DOWNLOAD_RESUME as BAD_DOWNLOAD_RESUME;
pub use curl_ffi::CURLcode::CURLE_FILE_COULDNT_READ_FILE as FILE_COULDNT_READ_FILE;
pub use curl_ffi::CURLcode::CURLE_LDAP_CANNOT_BIND as LDAP_CANNOT_BIND;
pub use curl_ffi::CURLcode::CURLE_LDAP_SEARCH_FAILED as LDAP_SEARCH_FAILED;
pub use curl_ffi::CURLcode::CURLE_OBSOLETE40 as OBSOLETE40;
pub use curl_ffi::CURLcode::CURLE_FUNCTION_NOT_FOUND as FUNCTION_NOT_FOUND;
pub use curl_ffi::CURLcode::CURLE_ABORTED_BY_CALLBACK as ABORTED_BY_CALLBACK;
pub use curl_ffi::CURLcode::CURLE_BAD_FUNCTION_ARGUMENT as BAD_FUNCTION_ARGUMENT;
pub use curl_ffi::CURLcode::CURLE_OBSOLETE44 as OBSOLETE44;
pub use curl_ffi::CURLcode::CURLE_INTERFACE_FAILED as INTERFACE_FAILED;
pub use curl_ffi::CURLcode::CURLE_OBSOLETE46 as OBSOLETE46;
pub use curl_ffi::CURLcode::CURLE_TOO_MANY_REDIRECTS  as TOO_MANY_REDIRECTS ;
pub use curl_ffi::CURLcode::CURLE_UNKNOWN_OPTION as UNKNOWN_OPTION;
pub use curl_ffi::CURLcode::CURLE_TELNET_OPTION_SYNTAX  as TELNET_OPTION_SYNTAX ;
pub use curl_ffi::CURLcode::CURLE_OBSOLETE50 as OBSOLETE50;
pub use curl_ffi::CURLcode::CURLE_PEER_FAILED_VERIFICATION as PEER_FAILED_VERIFICATION;
pub use curl_ffi::CURLcode::CURLE_GOT_NOTHING as GOT_NOTHING;
pub use curl_ffi::CURLcode::CURLE_SSL_ENGINE_NOTFOUND as SSL_ENGINE_NOTFOUND;
pub use curl_ffi::CURLcode::CURLE_SSL_ENGINE_SETFAILED as SSL_ENGINE_SETFAILED;
pub use curl_ffi::CURLcode::CURLE_SEND_ERROR as SEND_ERROR;
pub use curl_ffi::CURLcode::CURLE_RECV_ERROR as RECV_ERROR;
pub use curl_ffi::CURLcode::CURLE_OBSOLETE57 as OBSOLETE57;
pub use curl_ffi::CURLcode::CURLE_SSL_CERTPROBLEM as SSL_CERTPROBLEM;
pub use curl_ffi::CURLcode::CURLE_SSL_CIPHER as SSL_CIPHER;
pub use curl_ffi::CURLcode::CURLE_SSL_CACERT as SSL_CACERT;
pub use curl_ffi::CURLcode::CURLE_BAD_CONTENT_ENCODING as BAD_CONTENT_ENCODING;
pub use curl_ffi::CURLcode::CURLE_LDAP_INVALID_URL as LDAP_INVALID_URL;
pub use curl_ffi::CURLcode::CURLE_FILESIZE_EXCEEDED as FILESIZE_EXCEEDED;
pub use curl_ffi::CURLcode::CURLE_USE_SSL_FAILED as USE_SSL_FAILED;
pub use curl_ffi::CURLcode::CURLE_SEND_FAIL_REWIND as SEND_FAIL_REWIND;
pub use curl_ffi::CURLcode::CURLE_SSL_ENGINE_INITFAILED as SSL_ENGINE_INITFAILED;
pub use curl_ffi::CURLcode::CURLE_LOGIN_DENIED as LOGIN_DENIED;
pub use curl_ffi::CURLcode::CURLE_TFTP_NOTFOUND as TFTP_NOTFOUND;
pub use curl_ffi::CURLcode::CURLE_TFTP_PERM as TFTP_PERM;
pub use curl_ffi::CURLcode::CURLE_REMOTE_DISK_FULL as REMOTE_DISK_FULL;
pub use curl_ffi::CURLcode::CURLE_TFTP_ILLEGAL as TFTP_ILLEGAL;
pub use curl_ffi::CURLcode::CURLE_TFTP_UNKNOWNID as TFTP_UNKNOWNID;
pub use curl_ffi::CURLcode::CURLE_REMOTE_FILE_EXISTS as REMOTE_FILE_EXISTS;
pub use curl_ffi::CURLcode::CURLE_TFTP_NOSUCHUSER as TFTP_NOSUCHUSER;
pub use curl_ffi::CURLcode::CURLE_CONV_FAILED as CONV_FAILED;
pub use curl_ffi::CURLcode::CURLE_CONV_REQD as CONV_REQD;
pub use curl_ffi::CURLcode::CURLE_SSL_CACERT_BADFILE as SSL_CACERT_BADFILE;
pub use curl_ffi::CURLcode::CURLE_REMOTE_FILE_NOT_FOUND as REMOTE_FILE_NOT_FOUND;
pub use curl_ffi::CURLcode::CURLE_SSH as SSH;
pub use curl_ffi::CURLcode::CURLE_SSL_SHUTDOWN_FAILED as SSL_SHUTDOWN_FAILED;
pub use curl_ffi::CURLcode::CURLE_AGAIN as AGAIN;
pub use curl_ffi::CURLcode::CURLE_SSL_CRL_BADFILE as SSL_CRL_BADFILE;
pub use curl_ffi::CURLcode::CURLE_SSL_ISSUER_ERROR as SSL_ISSUER_ERROR;
pub use curl_ffi::CURLcode::CURLE_FTP_PRET_FAILED as FTP_PRET_FAILED;
pub use curl_ffi::CURLcode::CURLE_RTSP_CSEQ_ERROR as RTSP_CSEQ_ERROR;
pub use curl_ffi::CURLcode::CURLE_RTSP_SESSION_ERROR as RTSP_SESSION_ERROR;
pub use curl_ffi::CURLcode::CURLE_FTP_BAD_FILE_LIST as FTP_BAD_FILE_LIST;
pub use curl_ffi::CURLcode::CURLE_CHUNK_FAILED as CHUNK_FAILED;
pub use curl_ffi::CURLcode::CURLE_NO_CONNECTION_AVAILABLE as NO_CONNECTION_AVAILABLE;
pub use curl_ffi::CURLcode::CURLE_LAST as LAST;

#[deriving(Copy)]
pub struct ErrCode(pub ffi::CURLcode);

impl ErrCode {
    pub fn is_success(self) -> bool {
       self.code() as int == OK as int
    }

    pub fn code(self) -> ffi::CURLcode { let ErrCode(c) = self; c }
}

impl fmt::Show for ErrCode {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let c_str = unsafe {
            CString::new(ffi::curl_easy_strerror(self.code()), false)
        };

        match c_str.as_str() {
            Some(s) => write!(fmt, "{}", s),
            None => write!(fmt, "<unknown err>")
        }
    }
}

impl error::Error for ErrCode {
    fn description(&self) -> &str {
        let code = self.code();
        unsafe { str::from_c_str(ffi::curl_easy_strerror(code) as *const _) }
    }
}
<|endoftext|>


<commit_before>use chrono::UTC;
use chrono::datetime::DateTime;

use company::Company;

use postgres::Connection;

use rs_es::query::Filter;
use rs_es::units::JsonVal;

pub fn visibility_filters(conn: &Connection, company_id: Option<i32>) -> Vec<Filter> {
  let now = DateTime::timestamp(&UTC::now());

  let visibility_rules = Filter::build_bool()
                                .with_must(
                                  vec![
                                    Filter::build_term("accepted", true)
                                           .build(),
                                    Filter::build_range("batch_starts_at")
                                           .with_lt(JsonVal::from(now))
                                           .with_format("epoch_second")
                                           .build(),
                                    Filter::build_range("batch_ends_at")
                                           .with_gte(JsonVal::from(now))
                                           .with_format("epoch_second")
                                           .build()
                                  ])
                                .build();

  let company = match company_id {
    Some(company_id) => Company::find(conn, &company_id),
    None             => None,
  };

  match company {
    Some(company) => {
      // This could be a little dangerous without a backend validation.
      // We can leave as it is (but it's bruteforce-able) or otherwise
      // validating the requester by quering the DB or Honeypot itself.
      let presented_talents = Filter::build_bool()
                                     .with_must(
                                       vec![
                                         <Filter as VectorOfTerms<i32>>::build_terms(
                                           "ids", &company.presented_talents)
                                       ].into_iter()
                                        .flat_map(|x| x)
                                        .collect::<Vec<Filter>>())
                                     .build();
      vec![
        Filter::build_bool()
               .with_should(vec![visibility_rules, presented_talents])
               .build()
      ]
    },
    None => vec![visibility_rules]
  }
}

pub trait VectorOfTerms<T> {
  fn build_terms(key: &str, values: &Vec<T>) -> Vec<Filter>;
}

macro_rules! build_vector_of_terms_impl {
  ($t:ty) => {
    impl VectorOfTerms<$t> for Filter {
      /// Extract all given items into multiple filters (if present)
      /// i.e. build_terms("field", vec![1, 2]) => vec![Filter(1), Filter(2)]
      /// This enable us to operate on these values with boolean values
      fn build_terms(key: &str, values: &Vec<$t>) -> Vec<Filter> {
        if values.is_empty() {
          return vec![];
        }

        vec![
          Filter::build_terms(key, values.iter()
                                         .map(|v| JsonVal::from(v.clone()))
                                         .collect::<Vec<JsonVal>>()).build()
        ]
      }
    }
  }
}

build_vector_of_terms_impl!(i32);
build_vector_of_terms_impl!(String);
<commit_msg>filters: add tests<commit_after>use chrono::UTC;
use chrono::datetime::DateTime;

use company::Company;

use postgres::Connection;

use rs_es::query::Filter;
use rs_es::units::JsonVal;

pub fn visibility_filters(conn: &Connection, company_id: Option<i32>) -> Vec<Filter> {
  let now = DateTime::timestamp(&UTC::now());

  let visibility_rules = Filter::build_bool()
                                .with_must(
                                  vec![
                                    Filter::build_term("accepted", true)
                                           .build(),
                                    Filter::build_range("batch_starts_at")
                                           .with_lt(JsonVal::from(now))
                                           .with_format("epoch_second")
                                           .build(),
                                    Filter::build_range("batch_ends_at")
                                           .with_gte(JsonVal::from(now))
                                           .with_format("epoch_second")
                                           .build()
                                  ])
                                .build();

  let company = match company_id {
    Some(company_id) => Company::find(conn, &company_id),
    None             => None,
  };

  match company {
    Some(company) => {
      // This could be a little dangerous without a backend validation.
      // We can leave as it is (but it's bruteforce-able) or otherwise
      // validating the requester by quering the DB or Honeypot itself.
      let presented_talents = Filter::build_bool()
                                     .with_must(
                                       vec![
                                         <Filter as VectorOfTerms<i32>>::build_terms(
                                           "ids", &company.presented_talents)
                                       ].into_iter()
                                        .flat_map(|x| x)
                                        .collect::<Vec<Filter>>())
                                     .build();
      vec![
        Filter::build_bool()
               .with_should(vec![visibility_rules, presented_talents])
               .build()
      ]
    },
    None => vec![visibility_rules]
  }
}

pub trait VectorOfTerms<T> {
  fn build_terms(key: &str, values: &Vec<T>) -> Vec<Filter>;
}

macro_rules! build_vector_of_terms_impl {
  ($t:ty) => {
    impl VectorOfTerms<$t> for Filter {
      /// Extract all given items into multiple filters (if present)
      /// i.e. build_terms("field", vec![1, 2]) => vec![Filter(1), Filter(2)]
      /// This enable us to operate on these values with boolean values
      fn build_terms(key: &str, values: &Vec<$t>) -> Vec<Filter> {
        if values.is_empty() {
          return vec![];
        }

        vec![
          Filter::build_terms(key, values.iter()
                                         .map(|v| JsonVal::from(v.clone()))
                                         .collect::<Vec<JsonVal>>()).build()
        ]
      }
    }
  }
}

build_vector_of_terms_impl!(i32);
build_vector_of_terms_impl!(String);

#[cfg(test)]
mod tests {
  use filters::*;
  use rs_es::query::Filter;
  use rustc_serialize::json::ToJson;

  #[test]
  fn test_vector_of_terms() {
    assert!(<Filter as VectorOfTerms<String>>::build_terms("work_roles", &vec![])
                                              .is_empty());

    {
      let filters = <Filter as VectorOfTerms<String>>::build_terms(
                  "work_roles", &vec![String::from("Fullstack")]);
      assert_eq!(filters[0].to_json().to_string(),
        String::from("{\"terms\":{\"work_roles\":[\"Fullstack\"]}}"));
    }

    {
      let filters = <Filter as VectorOfTerms<i32>>::build_terms(
                  "work_roles", &vec![1]);
      assert_eq!(filters[0].to_json().to_string(),
        String::from("{\"terms\":{\"work_roles\":[1]}}"));
    }
  }

  #[test]
  fn test_visibility_filters() {
    // TODO
  }
}
<|endoftext|>