<commit_before>pub use self::parse_mode::ParseMode;
pub use self::chat_action::ChatAction;

mod parse_mode;
mod chat_action;
mod file;

use reqwest::Client;
use serde::de::DeserializeOwned;
use serde_json;
use serde_json::Value;

use bot::chat_action::get_chat_action;
use bot::parse_mode::get_parse_mode;
use error::{Result, check_for_error};
use error::Error::JsonNotFound;
use marker::ReplyMarkup;
use objects::{Update, Message, Contact, InlineKeyboardMarkup, User, UserProfilePhotos, File};

/// A `Bot` which will do all the API calls.
///
/// The `Bot` will be given access to in a `Command` with which you can do all
/// the API interactions in your `Command`s.
#[derive(Debug)]
pub struct Bot {
    pub id: i64,
    pub first_name: String,
    pub last_name: Option<String>,
    pub username: String,
    pub bot_url: String,
    client: Client,
}

impl Bot {
    /// Constructs a new `Bot`.
    pub fn new(bot_url: String) -> Result<Self> {
        debug!("Going to construct a new Bot...");
        let client = Client::new()?;
        let me = Bot::get_me(&client, &bot_url)?;
        let id = me.id;
        let first_name = me.first_name;
        let last_name = me.last_name;
        let username = me.username.expect("Cannot find username of the bot");

        Ok(Bot {
            id: id,
            first_name: first_name,
            last_name: last_name,
            username: username,
            client: client,
            bot_url: bot_url,
        })
    }

    /// API call which gets the information about your bot.
    pub fn get_me(client: &Client, bot_url: &str) -> Result<User> {
        debug!("Calling get_me...");
        let path = ["getMe"];
        let url = ::construct_api_url(bot_url, &path);
        let mut data = client.get(&url)?.send()?;
        let rjson: Value = check_for_error(data.json()?)?;
        let user_json = rjson.get("result").ok_or(JsonNotFound)?;
        let user: User = serde_json::from_value(user_json.clone())?;
        Ok(user)
    }

    /// API call which will get called to get the updates for your bot.
    pub fn get_updates(
        &self,
        offset: i32,
        limit: Option<i32>,
        timeout: Option<i32>,
        network_delay: Option<f32>,
    ) -> Result<Option<Vec<Update>>> {
        debug!("Calling get_updates...");
        let limit = limit.unwrap_or(100);
        let timeout = timeout.unwrap_or(0);
        let network_delay = network_delay.unwrap_or(0.0);
        let path = ["getUpdates"];
        let path_url = ::construct_api_url(&self.bot_url, &path);
        let url = format!(
            "{}?offset={}&limit={}&timeout={}&network_delay={}",
            path_url,
            offset,
            limit,
            timeout,
            network_delay
        );
        let mut data = self.client.get(&url)?.send()?;
        let rjson: Value = check_for_error(data.json()?)?;
        let updates_json = rjson.get("result");

        if let Some(result) = updates_json {
            let updates: Vec<Update> = serde_json::from_value(result.clone())?;
            Ok(Some(updates))
        } else {
            Ok(None)
        }
    }

    /// API call which will send a message to a chat which your bot participates in.
    pub fn send_message<M: ReplyMarkup>(
        &self,
        chat_id: &i64,
        text: &str,
        parse_mode: Option<&ParseMode>,
        disable_web_page_preview: Option<&bool>,
        disable_notification: Option<&bool>,
        reply_to_message_id: Option<&i64>,
        reply_markup: Option<M>,
    ) -> Result<Message> {
        debug!("Calling send_message...");
        let chat_id: &str = &chat_id.to_string();
        let parse_mode = &get_parse_mode(parse_mode.unwrap_or(&ParseMode::Text));
        let disable_web_page_preview: &str =
            &disable_web_page_preview.unwrap_or(&false).to_string();
        let disable_notification: &str = &disable_notification.unwrap_or(&false).to_string();
        let reply_to_message_id: &str = &reply_to_message_id.map(|i| i.to_string()).unwrap_or(
            "None"
                .to_string(),
        );
        let reply_markup = &Box::new(reply_markup)
            .map(|r| serde_json::to_string(&r).unwrap_or("".to_string()))
            .unwrap_or("".to_string());

        let path = ["sendMessage"];
        let params = [
            ("chat_id", chat_id),
            ("text", text),
            ("parse_mode", parse_mode),
            ("disable_web_page_preview", disable_web_page_preview),
            ("disable_notification", disable_notification),
            ("reply_to_message_id", reply_to_message_id),
            ("reply_markup", reply_markup),
        ];
        self.call(&path, &params)
    }

    /// API call which will reply to a message directed to your bot.
    pub fn reply_to_message(&self, update: &Update, text: &str) -> Result<Message> {
        debug!("Calling reply_to_message...");
        let message = update.clone().message.unwrap();
        let message_id = message.message_id;
        let chat_id = message.chat.id;
        self.send_message(
            &chat_id,
            text,
            None,
            None,
            None,
            Some(&message_id),
            ::NO_MARKUP,
        )
    }

    /// API call which will forward a message.
    pub fn forward_message(
        &self,
        update: &Update,
        chat_id: &i64,
        disable_notification: Option<&bool>,
    ) -> Result<Message> {
        debug!("Calling forward_message...");
        let message = update.clone().message.unwrap();
        let chat_id: &str = &chat_id.to_string();
        let from_chat_id: &str = &message.chat.id.to_string();
        let message_id: &str = &message.message_id.to_string();
        let disable_notification: &str = &disable_notification.unwrap_or(&false).to_string();
        let path = ["forwardMessage"];
        let params = [
            ("chat_id", chat_id),
            ("from_chat_id", from_chat_id),
            ("disable_notification", disable_notification),
            ("message_id", message_id),
        ];
        self.call(&path, &params)
    }

    /// API call which will show the given chat action to the users.
    pub fn send_chat_action(&self, chat_id: &i64, action: &ChatAction) -> Result<bool> {
        debug!("Calling send_chat_action...");
        let chat_id: &str = &chat_id.to_string();
        let action = &get_chat_action(action);
        let path = ["sendChatAction"];
        let params = [("chat_id", chat_id), ("action", action)];
        self.call(&path, &params)
    }

    /// API call which will send the given contact.
    pub fn send_contact(
        &self,
        chat_id: &i64,
        contact: &Contact,
        disable_notification: Option<&bool>,
        reply_to_message_id: Option<&i64>,
        reply_markup: Option<&InlineKeyboardMarkup>,
    ) -> Result<Message> {
        debug!("Calling send_contact...");
        let chat_id: &str = &chat_id.to_string();
        let phone_number = &contact.phone_number;
        let first_name = &contact.first_name;
        let last_name = &contact.clone().last_name.unwrap();
        let disable_notification: &str = &disable_notification.unwrap_or(&false).to_string();
        let reply_to_message_id: &str = &reply_to_message_id.map(|i| i.to_string()).unwrap_or(
            "None"
                .to_string(),
        );
        let reply_markup = &reply_markup
            .and_then(|r| serde_json::to_string(r).ok())
            .unwrap_or("".to_string());
        let path = ["sendContact"];
        let params = [
            ("chat_id", chat_id),
            ("phone_number", phone_number),
            ("first_name", first_name),
            ("last_name", last_name),
            ("disable_notification", disable_notification),
            ("reply_to_message_id", reply_to_message_id),
            ("reply_markup", reply_markup),
        ];
        self.call(&path, &params)
    }

    /// API call which will get a list of profile pictures for a user.
    pub fn get_user_profile_photos(
        &self,
        user_id: &i64,
        offset: Option<&i64>,
        limit: Option<&i64>,
    ) -> Result<UserProfilePhotos> {
        debug!("Calling get_user_profile_photos...");
        let user_id: &str = &user_id.to_string();
        let offset: &str = &offset.map(|i| i.to_string()).unwrap_or("None".to_string());
        let limit: &str = &limit.map(|i| i.to_string()).unwrap_or("None".to_string());
        let path = ["getUserProfilePhotos"];
        let params = [("user_id", user_id), ("offset", offset), ("limit", limit)];
        self.call(&path, &params)
    }

    /// API call which will get basic info about a file and prepare it for donwloading.
    pub fn get_file(&self, file_id: &str) -> Result<File> {
        debug!("Calling get_file...");
        let path = ["getFile"];
        let params = [("file_id", file_id)];
        self.call(&path, &params)
    }

    /// API call which will kick a user from a group, supergroup or a channel. The bot must be
    /// an administrator in the chat for this call to succeed.
    pub fn kick_chat_member(
        &self,
        chat_id: &i64,
        user_id: &i64,
        until_date: Option<i64>,
    ) -> Result<bool> {
        debug!("Calling kick_chat_member...");
        let chat_id: &str = &chat_id.to_string();
        let user_id: &str = &user_id.to_string();
        let until_date: &str = &until_date.map(|i| i.to_string()).unwrap_or(
            "None".to_string(),
        );
        let path = ["kickChatMember"];
        let params = [
            ("chat_id", chat_id),
            ("user_id", user_id),
            ("until_date", until_date),
        ];
        self.call(&path, &params)
    }

    /// The actual networking done for sending messages.
    fn call<T: DeserializeOwned>(&self, path: &[&str], params: &[(&str, &str)]) -> Result<T> {
        debug!("Making API call...");
        let url = ::construct_api_url(&self.bot_url, path);
        let mut data = self.client.post(&url)?.form(&params)?.send()?;
        let rjson: Value = check_for_error(data.json()?)?;
        let object_json = rjson.get("result").ok_or(JsonNotFound)?;
        let object = serde_json::from_value::<T>(object_json.clone())?;
        Ok(object)
    }
}
<commit_msg>Adding unban_chat_member method<commit_after>pub use self::parse_mode::ParseMode;
pub use self::chat_action::ChatAction;

mod parse_mode;
mod chat_action;
mod file;

use reqwest::Client;
use serde::de::DeserializeOwned;
use serde_json;
use serde_json::Value;

use bot::chat_action::get_chat_action;
use bot::parse_mode::get_parse_mode;
use error::{Result, check_for_error};
use error::Error::JsonNotFound;
use marker::ReplyMarkup;
use objects::{Update, Message, Contact, InlineKeyboardMarkup, User, UserProfilePhotos, File};

/// A `Bot` which will do all the API calls.
///
/// The `Bot` will be given access to in a `Command` with which you can do all
/// the API interactions in your `Command`s.
#[derive(Debug)]
pub struct Bot {
    pub id: i64,
    pub first_name: String,
    pub last_name: Option<String>,
    pub username: String,
    pub bot_url: String,
    client: Client,
}

impl Bot {
    /// Constructs a new `Bot`.
    pub fn new(bot_url: String) -> Result<Self> {
        debug!("Going to construct a new Bot...");
        let client = Client::new()?;
        let me = Bot::get_me(&client, &bot_url)?;
        let id = me.id;
        let first_name = me.first_name;
        let last_name = me.last_name;
        let username = me.username.expect("Cannot find username of the bot");

        Ok(Bot {
            id: id,
            first_name: first_name,
            last_name: last_name,
            username: username,
            client: client,
            bot_url: bot_url,
        })
    }

    /// API call which gets the information about your bot.
    pub fn get_me(client: &Client, bot_url: &str) -> Result<User> {
        debug!("Calling get_me...");
        let path = ["getMe"];
        let url = ::construct_api_url(bot_url, &path);
        let mut data = client.get(&url)?.send()?;
        let rjson: Value = check_for_error(data.json()?)?;
        let user_json = rjson.get("result").ok_or(JsonNotFound)?;
        let user: User = serde_json::from_value(user_json.clone())?;
        Ok(user)
    }

    /// API call which will get called to get the updates for your bot.
    pub fn get_updates(
        &self,
        offset: i32,
        limit: Option<i32>,
        timeout: Option<i32>,
        network_delay: Option<f32>,
    ) -> Result<Option<Vec<Update>>> {
        debug!("Calling get_updates...");
        let limit = limit.unwrap_or(100);
        let timeout = timeout.unwrap_or(0);
        let network_delay = network_delay.unwrap_or(0.0);
        let path = ["getUpdates"];
        let path_url = ::construct_api_url(&self.bot_url, &path);
        let url = format!(
            "{}?offset={}&limit={}&timeout={}&network_delay={}",
            path_url,
            offset,
            limit,
            timeout,
            network_delay
        );
        let mut data = self.client.get(&url)?.send()?;
        let rjson: Value = check_for_error(data.json()?)?;
        let updates_json = rjson.get("result");

        if let Some(result) = updates_json {
            let updates: Vec<Update> = serde_json::from_value(result.clone())?;
            Ok(Some(updates))
        } else {
            Ok(None)
        }
    }

    /// API call which will send a message to a chat which your bot participates in.
    pub fn send_message<M: ReplyMarkup>(
        &self,
        chat_id: &i64,
        text: &str,
        parse_mode: Option<&ParseMode>,
        disable_web_page_preview: Option<&bool>,
        disable_notification: Option<&bool>,
        reply_to_message_id: Option<&i64>,
        reply_markup: Option<M>,
    ) -> Result<Message> {
        debug!("Calling send_message...");
        let chat_id: &str = &chat_id.to_string();
        let parse_mode = &get_parse_mode(parse_mode.unwrap_or(&ParseMode::Text));
        let disable_web_page_preview: &str =
            &disable_web_page_preview.unwrap_or(&false).to_string();
        let disable_notification: &str = &disable_notification.unwrap_or(&false).to_string();
        let reply_to_message_id: &str = &reply_to_message_id.map(|i| i.to_string()).unwrap_or(
            "None"
                .to_string(),
        );
        let reply_markup = &Box::new(reply_markup)
            .map(|r| serde_json::to_string(&r).unwrap_or("".to_string()))
            .unwrap_or("".to_string());

        let path = ["sendMessage"];
        let params = [
            ("chat_id", chat_id),
            ("text", text),
            ("parse_mode", parse_mode),
            ("disable_web_page_preview", disable_web_page_preview),
            ("disable_notification", disable_notification),
            ("reply_to_message_id", reply_to_message_id),
            ("reply_markup", reply_markup),
        ];
        self.call(&path, &params)
    }

    /// API call which will reply to a message directed to your bot.
    pub fn reply_to_message(&self, update: &Update, text: &str) -> Result<Message> {
        debug!("Calling reply_to_message...");
        let message = update.clone().message.unwrap();
        let message_id = message.message_id;
        let chat_id = message.chat.id;
        self.send_message(
            &chat_id,
            text,
            None,
            None,
            None,
            Some(&message_id),
            ::NO_MARKUP,
        )
    }

    /// API call which will forward a message.
    pub fn forward_message(
        &self,
        update: &Update,
        chat_id: &i64,
        disable_notification: Option<&bool>,
    ) -> Result<Message> {
        debug!("Calling forward_message...");
        let message = update.clone().message.unwrap();
        let chat_id: &str = &chat_id.to_string();
        let from_chat_id: &str = &message.chat.id.to_string();
        let message_id: &str = &message.message_id.to_string();
        let disable_notification: &str = &disable_notification.unwrap_or(&false).to_string();
        let path = ["forwardMessage"];
        let params = [
            ("chat_id", chat_id),
            ("from_chat_id", from_chat_id),
            ("disable_notification", disable_notification),
            ("message_id", message_id),
        ];
        self.call(&path, &params)
    }

    /// API call which will show the given chat action to the users.
    pub fn send_chat_action(&self, chat_id: &i64, action: &ChatAction) -> Result<bool> {
        debug!("Calling send_chat_action...");
        let chat_id: &str = &chat_id.to_string();
        let action = &get_chat_action(action);
        let path = ["sendChatAction"];
        let params = [("chat_id", chat_id), ("action", action)];
        self.call(&path, &params)
    }

    /// API call which will send the given contact.
    pub fn send_contact(
        &self,
        chat_id: &i64,
        contact: &Contact,
        disable_notification: Option<&bool>,
        reply_to_message_id: Option<&i64>,
        reply_markup: Option<&InlineKeyboardMarkup>,
    ) -> Result<Message> {
        debug!("Calling send_contact...");
        let chat_id: &str = &chat_id.to_string();
        let phone_number = &contact.phone_number;
        let first_name = &contact.first_name;
        let last_name = &contact.clone().last_name.unwrap();
        let disable_notification: &str = &disable_notification.unwrap_or(&false).to_string();
        let reply_to_message_id: &str = &reply_to_message_id.map(|i| i.to_string()).unwrap_or(
            "None"
                .to_string(),
        );
        let reply_markup = &reply_markup
            .and_then(|r| serde_json::to_string(r).ok())
            .unwrap_or("".to_string());
        let path = ["sendContact"];
        let params = [
            ("chat_id", chat_id),
            ("phone_number", phone_number),
            ("first_name", first_name),
            ("last_name", last_name),
            ("disable_notification", disable_notification),
            ("reply_to_message_id", reply_to_message_id),
            ("reply_markup", reply_markup),
        ];
        self.call(&path, &params)
    }

    /// API call which will get a list of profile pictures for a user.
    pub fn get_user_profile_photos(
        &self,
        user_id: &i64,
        offset: Option<&i64>,
        limit: Option<&i64>,
    ) -> Result<UserProfilePhotos> {
        debug!("Calling get_user_profile_photos...");
        let user_id: &str = &user_id.to_string();
        let offset: &str = &offset.map(|i| i.to_string()).unwrap_or("None".to_string());
        let limit: &str = &limit.map(|i| i.to_string()).unwrap_or("None".to_string());
        let path = ["getUserProfilePhotos"];
        let params = [("user_id", user_id), ("offset", offset), ("limit", limit)];
        self.call(&path, &params)
    }

    /// API call which will get basic info about a file and prepare it for donwloading.
    pub fn get_file(&self, file_id: &str) -> Result<File> {
        debug!("Calling get_file...");
        let path = ["getFile"];
        let params = [("file_id", file_id)];
        self.call(&path, &params)
    }

    /// API call which will kick a user from a group, supergroup or a channel. The bot must be
    /// an administrator in the chat for this call to succeed.
    pub fn kick_chat_member(
        &self,
        chat_id: &i64,
        user_id: &i64,
        until_date: Option<i64>,
    ) -> Result<bool> {
        debug!("Calling kick_chat_member...");
        let chat_id: &str = &chat_id.to_string();
        let user_id: &str = &user_id.to_string();
        let until_date: &str = &until_date.map(|i| i.to_string()).unwrap_or(
            "None".to_string(),
        );
        let path = ["kickChatMember"];
        let params = [
            ("chat_id", chat_id),
            ("user_id", user_id),
            ("until_date", until_date),
        ];
        self.call(&path, &params)
    }

    /// API call which will unban previously kicked members in a supergroup or channel. The bot
    /// must be administrator for this to work.
    pub fn unban_chat_member(&self, chat_id: &i64, user_id: &i64) -> Result<bool> {
        debug!("Calling unban_chat_member...");
        let chat_id: &str = &chat_id.to_string();
        let user_id: &str = &user_id.to_string();
        let path = ["unbanChatMember"];
        let params = [("chat_id", chat_id), ("user_id", user_id)];
        self.call(&path, &params)
    }

    /// The actual networking done for making API calls.
    fn call<T: DeserializeOwned>(&self, path: &[&str], params: &[(&str, &str)]) -> Result<T> {
        debug!("Making API call...");
        let url = ::construct_api_url(&self.bot_url, path);
        let mut data = self.client.post(&url)?.form(&params)?.send()?;
        let rjson: Value = check_for_error(data.json()?)?;
        let object_json = rjson.get("result").ok_or(JsonNotFound)?;
        let object = serde_json::from_value::<T>(object_json.clone())?;
        Ok(object)
    }
}
<|endoftext|>


<commit_before>use objects::update;

pub trait Command {
    fn execute(&mut self, update::Update);
}
<commit_msg>Letting Command inherit from 'static<commit_after>use objects::update;
use bot;

pub trait Command: 'static {
    fn execute(&mut self, bot::Bot, update::Update);
}
<|endoftext|>


<commit_before>extern crate chrono;

use chrono::prelude::*;
use regex::Regex;

#[derive(Debug)]
pub enum Command {
    BadCommand,
    OneTimeEvent(OneTimeEventImpl),
}

#[derive(Debug)]
pub struct OneTimeEventImpl{
    pub event_time : DateTime<Utc>,
    pub event_text : String,
}

pub fn parse_command(command_line : String) -> Command {
    debug!("parse incoming text: {}", command_line);
    let reg_main    = Regex::new(r"(?P<spec>[\d\w]*)(?P<divider> )(?P<main_text>.*)").unwrap();

    let reg_day     = r"(?P<days>[\d]*)[D|d]";
    let reg_hour    = r"(?P<hours>[\d]*)[H|h]";
    let reg_min     = r"(?P<minuts>[\d]*)[M|m]";
    let reg_sec     = r"(?P<seconds>[\d]*)[S|s]";

    let caps = reg_main.captures(&command_line);
    if caps.is_none() {
        warn!("parse_command: incoming text doesn't match main regex");
        return Command::BadCommand;
    }
    let caps = caps.unwrap();
    let spec = caps.name("spec").unwrap().as_str();
    let text = caps.name("main_text").unwrap().as_str();

    let days    = get_first_regex_group_as_u32(reg_day,  spec);
    let hours   = get_first_regex_group_as_u32(reg_hour, spec);
    let minutes = get_first_regex_group_as_u32(reg_min,  spec);
    let seconds = get_first_regex_group_as_u32(reg_sec,  spec);

    // TODO: should we a better way to do this
    let dt = chrono::Duration::seconds((days as i64) * (60*60*24)
                                    + (hours as i64) * (60*60)
                                    + (minutes as i64) * 60
                                    + (seconds as i64)
                                    );

    let event_time = Utc::now() + dt;

    Command::OneTimeEvent(OneTimeEventImpl
            { event_text : String::from(text)
            , event_time : event_time }
        )
}

fn get_first_regex_group_as_u32(reg : &str, text : &str) -> u32{
    let reg = Regex::new(reg).expect("get_first_regex_group_as_u32: wrong regex string");
    let number = match reg.captures(text){
        None => "0",
        Some(d) => d.get(1)
            .expect("get_first_regex_group_as_u32: expect regex string with at least 1 group")
            .as_str(),
    };
    number.parse().unwrap_or(0)
}
<commit_msg>Check for matching regex [#8]<commit_after>extern crate chrono;

use chrono::prelude::*;
use regex::Regex;

#[derive(Debug)]
pub enum Command {
    BadCommand,
    OneTimeEvent(OneTimeEventImpl),
}

#[derive(Debug)]
pub struct OneTimeEventImpl{
    pub event_time : DateTime<Utc>,
    pub event_text : String,
}

pub fn parse_command(command_line : String) -> Command {
    debug!("parse incoming text: {}", command_line);
    let reg_main    = Regex::new(r"(?P<spec>[\d\w]*)(?P<divider> )(?P<main_text>.*)").unwrap();

    let reg_day     = r"(?P<days>[\d]*)[D|d]";
    let reg_hour    = r"(?P<hours>[\d]*)[H|h]";
    let reg_min     = r"(?P<minuts>[\d]*)[M|m]";
    let reg_sec     = r"(?P<seconds>[\d]*)[S|s]";

    let caps = reg_main.captures(&command_line);
    if caps.is_none() {
        warn!("parse_command: incoming text doesn't match main regex");
        return Command::BadCommand;
    }
    let caps = caps.unwrap();
    let spec = caps.name("spec").unwrap().as_str();
    let text = caps.name("main_text").unwrap().as_str();

    let days    = get_first_regex_group_as_u32(reg_day,  spec);
    let hours   = get_first_regex_group_as_u32(reg_hour, spec);
    let minutes = get_first_regex_group_as_u32(reg_min,  spec);
    let seconds = get_first_regex_group_as_u32(reg_sec,  spec);

    if days == 0 && hours == 0 && minutes == 0 && seconds == 0 {
        warn!("parse_command: incoming text doesn't match main regex");
        return Command::BadCommand;
    }

    // TODO: should we a better way to do this
    let dt = chrono::Duration::seconds((days as i64) * (60*60*24)
                                    + (hours as i64) * (60*60)
                                    + (minutes as i64) * 60
                                    + (seconds as i64)
                                    );

    let event_time = Utc::now() + dt;

    Command::OneTimeEvent(OneTimeEventImpl
            { event_text : String::from(text)
            , event_time : event_time }
        )
}

fn get_first_regex_group_as_u32(reg : &str, text : &str) -> u32{
    let reg = Regex::new(reg).expect("get_first_regex_group_as_u32: wrong regex string");
    let number = match reg.captures(text){
        None => "0",
        Some(d) => d.get(1)
            .expect("get_first_regex_group_as_u32: expect regex string with at least 1 group")
            .as_str(),
    };
    number.parse().unwrap_or(0)
}
<|endoftext|>


<commit_before>use proc_macro2 as pm2;
use syn::parse::{Parse, ParseStream};
use syn::punctuated::Punctuated;
use quote::{ToTokens};
use std::cell::RefCell;

static CONTROL_LIST: &'static [&'static str] = &[
    "Window", "Button", "CheckBox", "ComboBox", "DatePicker", "FancyWindow",
    "ImageFrame", "Label", "ListBox", "Menu", "MenuItem", "MenuSeparator",
    "Notice", "ProgressBar", "RadioButton", "StatusBar", "TabsContainer", "Tab",
    "TextBox", "TextInput", "Timer", "Tooltip", "Trackbar", "TreeView"
];

static TOP_LEVEL: &'static [&'static str] = &[
    "Window", "FancyWindow", "TabsContainer", "Tab"
];

#[allow(unused)]
struct ControlParam {
    ident: syn::Ident,
    sep: Token![:],
    e: syn::Expr,
}

impl Parse for ControlParam {
    fn parse(input: ParseStream) -> syn::Result<Self> {
        Ok(ControlParam {
            ident: input.parse()?,
            sep: input.parse()?,
            e: input.parse()?,
        })
    }
}

struct ControlParameters {
    params: Punctuated<ControlParam, Token![,]>
}

impl Parse for ControlParameters {
    fn parse(input: ParseStream) -> syn::Result<Self> {
        let content;
        parenthesized!(content in input);
        Ok(ControlParameters {
            params: content.parse_terminated(ControlParam::parse)?
        })
    }
}

pub struct ControlGen<'a> {
    ty: syn::Ident,
    member: &'a syn::Ident,
    params: RefCell<ControlParameters>,
}

impl<'a> ToTokens for ControlGen<'a> {

    fn to_tokens(&self, tokens: &mut pm2::TokenStream) {
        let mut control_params = self.params.borrow_mut();
        let member = self.member;
        let ty = &self.ty;

        let flags_name = format!("{}Flags", ty);
        expand_flags(&mut control_params, &flags_name);

        let ids: Vec<&syn::Ident> = control_params.params.iter().map(|p| &p.ident).collect();
        let values: Vec<&syn::Expr> = control_params.params.iter().map(|p| &p.e).collect();

        let control_tk = quote! {
            nwg::#ty::builder()
                #(.#ids(#values))*
                .build(&mut data.#member)?;
        };

        control_tk.to_tokens(tokens);
    }

}

/// Generate the code that inits the control in the `build_ui` function or the `build_partial` function
/// Note that ordering is done in `organize_controls`
pub fn generate_control<'a>(field: &'a syn::Field) -> Option<ControlGen<'a>> {
    let attrs = &field.attrs;
    if attrs.len() == 0 { return None; }

    let member = field.ident.as_ref().expect("Cannot find member name when generating control");

    let attr = match find_control_attr(&attrs) {
        Some(a) => a,
        None => { return None; }
    };

    let ty = extract_control_type(&field.ty);
    if !CONTROL_LIST.iter().any(|name| &ty == name) {
        panic!("Unkown nwg type #{}. If you use renamed control try `control(ty=Button)`.", ty);
    }

    let params = parse_parameters(member, &attr.tokens);

    Some( ControlGen {  ty, member, params: RefCell::new(params)  } )
}

/// Guess the controls parent and reorder the controls creation order to make sure everything works
pub fn organize_controls<'a>(fields: &mut Vec<ControlGen<'a>>) {
    let mut last_top_level: Option<&ControlGen<'a>> = None;

    for control in fields.iter() {
        if TOP_LEVEL.iter().any(|top| &control.ty == top) {
            last_top_level = Some(control);
            continue;
        }

        let try_expand_parent = match last_top_level.clone() {
            Some(top) => auto_parent(control, top),
            None => true
        };

        if try_expand_parent {
            expand_parent(control);
        }
    }

}

fn find_control_attr(attrs: &[syn::Attribute]) -> Option<&syn::Attribute> {
    let mut index = None;
    for (i, attr) in attrs.iter().enumerate() {
        if let Some(ident) = attr.path.get_ident() {
            if ident == "nwg_control" {
                index = Some(i);
                break;
            }
        }
    }

    index.map(|i| &attrs[i])
}

fn extract_control_type(ty: &syn::Type) -> syn::Ident {
    let control_type: String;

    match ty {
        syn::Type::Path(p) => {
            let path_len = p.path.segments.len();
            control_type = p.path.segments[path_len-1].ident.to_string();
        },
        _ => panic!("Ui control fields must be in a path format `nwg::Button` or simple format `Button`.")
    }

    syn::Ident::new(&control_type, pm2::Span::call_site())
}

fn parse_parameters(m: &pm2::Ident, s: &pm2::TokenStream) -> ControlParameters {
    match syn::parse2(s.clone()) {
        Ok(a) => a,
        Err(e) => panic!("Failed to parse field #{}: {}", m, e)
    }
}

/// Expand the control flags from the compressed format. Ex: "WINDOW|VISIBLE"
fn expand_flags(p: &mut ControlParameters, base: &str) {
    let mut flags = p.params.iter_mut().find(|f| &f.ident == "flags");
    if let Some(flags_param) = flags.as_mut() {
        let flags_value = match &flags_param.e {
            syn::Expr::Lit(expr_lit) => match &expr_lit.lit {
                syn::Lit::Str(value) => value,
                other => panic!("Compressed flags must str, got {:?}", other)
            },
            _ => { return; }
        };

        let flags = flags_value.value();
        let splitted: Vec<&str> = flags.split('|').collect();

        let flags_count = splitted.len() - 1;
        let mut final_flags: String = String::with_capacity(100);
        for (i, value) in splitted.into_iter().enumerate() {
            final_flags.push_str("nwg::");
            final_flags.push_str(base);
            final_flags.push_str("::");
            final_flags.push_str(value);

            if i != flags_count {
                final_flags.push('|');
            }
        }

        flags_param.e = syn::parse_str(&final_flags).expect("Failed to parse flags");
    }
}

/// Expand user defined parent field. Ex: "parent: window" becomes "parent: &data.window"
fn expand_parent<'a>(control: &ControlGen<'a>) {
    let mut p = control.params.borrow_mut();
    let mut parent = p.params.iter_mut().find(|f| &f.ident == "parent");

    if let Some(parent_params) = parent.as_mut() {
        let parent_name_path = match &parent_params.e {
            syn::Expr::Path(exp_path) => &exp_path.path.segments,
            _ => { return; }
        };

        let parent_name = match parent_name_path.first().map(|seg| &seg.ident) {
            Some(name) => name,
            None => panic!("Failed to parse parent value for control {}", control.member)
        };

        let final_parent = format!("& data.{}", parent_name);
        parent_params.e = match syn::parse_str(&final_parent) {
            Ok(e) => e,
            Err(e) => panic!("Failed to parse parent value for control {}: {}", control.member, e)
        };
    }
}

/// Add the control parent to the control parameters.
/// Returns `true` if a parent field already exists
/// Returns `false` if the parent field was added
fn auto_parent<'a>(control: &ControlGen<'a>, parent: &ControlGen<'a>) -> bool {
    let mut p = control.params.borrow_mut();
    if p.params.iter().any(|p| &p.ident == "parent") {
        return true;  // User already defined a parent
    }

    let parent_expr = format!("&data.{}", parent.member);
    let parent_param = ControlParam {
        ident: syn::Ident::new("parent", pm2::Span::call_site()),
        sep: syn::token::Colon(pm2::Span::call_site()),
        e: syn::parse_str(&parent_expr).unwrap(),
    };

    p.params.push(parent_param);

    false
}
<commit_msg>expand flags update<commit_after>use proc_macro2 as pm2;
use syn::parse::{Parse, ParseStream};
use syn::punctuated::Punctuated;
use quote::{ToTokens};
use std::cell::RefCell;

static CONTROL_LIST: &'static [&'static str] = &[
    "Window", "Button", "CheckBox", "ComboBox", "DatePicker", "FancyWindow",
    "ImageFrame", "Label", "ListBox", "Menu", "MenuItem", "MenuSeparator",
    "Notice", "ProgressBar", "RadioButton", "StatusBar", "TabsContainer", "Tab",
    "TextBox", "TextInput", "Timer", "Tooltip", "Trackbar", "TreeView"
];

static TOP_LEVEL: &'static [&'static str] = &[
    "Window", "FancyWindow", "TabsContainer", "Tab"
];

#[allow(unused)]
struct ControlParam {
    ident: syn::Ident,
    sep: Token![:],
    e: syn::Expr,
}

impl Parse for ControlParam {
    fn parse(input: ParseStream) -> syn::Result<Self> {
        Ok(ControlParam {
            ident: input.parse()?,
            sep: input.parse()?,
            e: input.parse()?,
        })
    }
}

struct ControlParameters {
    params: Punctuated<ControlParam, Token![,]>
}

impl Parse for ControlParameters {
    fn parse(input: ParseStream) -> syn::Result<Self> {
        let content;
        parenthesized!(content in input);
        Ok(ControlParameters {
            params: content.parse_terminated(ControlParam::parse)?
        })
    }
}

pub struct ControlGen<'a> {
    ty: syn::Ident,
    member: &'a syn::Ident,
    params: RefCell<ControlParameters>,
}

impl<'a> ToTokens for ControlGen<'a> {

    fn to_tokens(&self, tokens: &mut pm2::TokenStream) {
        let control_params = self.params.borrow();
        let member = self.member;
        let ty = &self.ty;

        let ids: Vec<&syn::Ident> = control_params.params.iter().map(|p| &p.ident).collect();
        let values: Vec<&syn::Expr> = control_params.params.iter().map(|p| &p.e).collect();

        let control_tk = quote! {
            nwg::#ty::builder()
                #(.#ids(#values))*
                .build(&mut data.#member)?;
        };

        control_tk.to_tokens(tokens);
    }

}

/// Generate the code that inits the control in the `build_ui` function or the `build_partial` function
/// Note that ordering is done in `organize_controls`
pub fn generate_control<'a>(field: &'a syn::Field) -> Option<ControlGen<'a>> {
    let attrs = &field.attrs;
    if attrs.len() == 0 { return None; }

    let member = field.ident.as_ref().expect("Cannot find member name when generating control");

    let attr = match find_control_attr(&attrs) {
        Some(a) => a,
        None => { return None; }
    };

    let ty = extract_control_type(&field.ty);
    if !CONTROL_LIST.iter().any(|name| &ty == name) {
        panic!("Unkown nwg type #{}. If you use renamed control try `control(ty=Button)`.", ty);
    }

    let params = parse_parameters(member, &attr.tokens);

    Some( ControlGen {  ty, member, params: RefCell::new(params)  } )
}

/// Guess the controls parent and reorder the controls creation order to make sure everything works
pub fn organize_controls<'a>(fields: &mut Vec<ControlGen<'a>>) {
    let mut last_top_level: Option<&ControlGen<'a>> = None;

    for control in fields.iter() {
        let flags_name = format!("{}Flags", control.ty);

        if TOP_LEVEL.iter().any(|top| &control.ty == top) {
            last_top_level = Some(control);
            expand_flags(control, &flags_name);
            continue;
        }

        let try_expand_parent = match last_top_level.clone() {
            Some(top) => auto_parent(control, top),
            None => true
        };

        if try_expand_parent {
            expand_parent(control);
        }

        expand_flags(control, &flags_name);
    }

}

fn find_control_attr(attrs: &[syn::Attribute]) -> Option<&syn::Attribute> {
    let mut index = None;
    for (i, attr) in attrs.iter().enumerate() {
        if let Some(ident) = attr.path.get_ident() {
            if ident == "nwg_control" {
                index = Some(i);
                break;
            }
        }
    }

    index.map(|i| &attrs[i])
}

fn extract_control_type(ty: &syn::Type) -> syn::Ident {
    let control_type: String;

    match ty {
        syn::Type::Path(p) => {
            let path_len = p.path.segments.len();
            control_type = p.path.segments[path_len-1].ident.to_string();
        },
        _ => panic!("Ui control fields must be in a path format `nwg::Button` or simple format `Button`.")
    }

    syn::Ident::new(&control_type, pm2::Span::call_site())
}

fn parse_parameters(m: &pm2::Ident, s: &pm2::TokenStream) -> ControlParameters {
    match syn::parse2(s.clone()) {
        Ok(a) => a,
        Err(e) => panic!("Failed to parse field #{}: {}", m, e)
    }
}

/// Expand the control flags from the compressed format. Ex: "WINDOW|VISIBLE"
fn expand_flags<'a>(control: &ControlGen<'a>, base: &str) {
    let mut p = control.params.borrow_mut();
    let mut flags = p.params.iter_mut().find(|f| &f.ident == "flags");
    if let Some(flags_param) = flags.as_mut() {
        let flags_value = match &flags_param.e {
            syn::Expr::Lit(expr_lit) => match &expr_lit.lit {
                syn::Lit::Str(value) => value,
                other => panic!("Compressed flags must str, got {:?} for control {}", other, control.member)
            },
            _ => { return; }
        };

        let flags = flags_value.value();
        let splitted: Vec<&str> = flags.split('|').collect();

        let flags_count = splitted.len() - 1;
        let mut final_flags: String = String::with_capacity(100);
        for (i, value) in splitted.into_iter().enumerate() {
            final_flags.push_str("nwg::");
            final_flags.push_str(base);
            final_flags.push_str("::");
            final_flags.push_str(value);

            if i != flags_count {
                final_flags.push('|');
            }
        }

        flags_param.e = match syn::parse_str(&final_flags) {
            Ok(e) => e,
            Err(e) => panic!("Failed to parse flags value for control {}: {}", control.member, e)
        };
    }
}

/// Expand user defined parent field. Ex: "parent: window" becomes "parent: &data.window"
fn expand_parent<'a>(control: &ControlGen<'a>) {
    let mut p = control.params.borrow_mut();
    let mut parent = p.params.iter_mut().find(|f| &f.ident == "parent");

    if let Some(parent_params) = parent.as_mut() {
        let parent_name_path = match &parent_params.e {
            syn::Expr::Path(exp_path) => &exp_path.path.segments,
            _ => { return; }
        };

        let parent_name = match parent_name_path.first().map(|seg| &seg.ident) {
            Some(name) => name,
            None => panic!("Failed to parse parent value for control {}", control.member)
        };

        let final_parent = format!("& data.{}", parent_name);
        parent_params.e = match syn::parse_str(&final_parent) {
            Ok(e) => e,
            Err(e) => panic!("Failed to parse parent value for control {}: {}", control.member, e)
        };
    }
}

/// Add the control parent to the control parameters.
/// Returns `true` if a parent field already exists
/// Returns `false` if the parent field was added
fn auto_parent<'a>(control: &ControlGen<'a>, parent: &ControlGen<'a>) -> bool {
    let mut p = control.params.borrow_mut();
    if p.params.iter().any(|p| &p.ident == "parent") {
        return true;  // User already defined a parent
    }

    let parent_expr = format!("&data.{}", parent.member);
    let parent_param = ControlParam {
        ident: syn::Ident::new("parent", pm2::Span::call_site()),
        sep: syn::token::Colon(pm2::Span::call_site()),
        e: syn::parse_str(&parent_expr).unwrap(),
    };

    p.params.push(parent_param);

    false
}
<|endoftext|>


<commit_before>// iterators2.rs
// In this module, you'll learn some of unique advantages that iterators can offer
// Step 1. Complete the `capitalize_first` function to pass the first two cases
// Step 2. Apply the `capitalize_first` function to a vector of strings, ensuring that it
// Step 3. Apply the `capitalize_first` function again to a list, but try and ensure it returns a single string
// As always, there are hints below!

pub fn capitalize_first(input: &str) -> String {
    let mut c = input.chars();
    match c.next() {
        None => String::new(),
        Some(first) => first.collect::<String>() + c.as_str(),
    }
}

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

    // Step 1.
    // Tests that verify your `capitalize_first` function implementation
    #[test]
    fn test_success() {
        assert_eq!(capitalize_first("hello"), "Hello");
    }

    #[test]
    fn test_empty() {
        assert_eq!(capitalize_first(""), "");
    }

    // Step 2.
    #[test]
    fn test_iterate_string_vec() {
        let words = vec!["hello", "world"];
        let capitalized_words: Vec<String> = // TODO
        assert_eq!(capitalized_words, ["Hello", "World"]);
    }

    #[test]
    fn test_iterate_into_string() {
        let words = vec!["hello", " ", "world"];
        let capitalized_words = // TODO
        assert_eq!(capitalized_words, "Hello World");
    }
}

// Step 1
// You need to call something on `first` before it can be collected
// Currently it's type is `char`. Have a look at the methods that are available on that type:
// https://doc.rust-lang.org/std/primitive.char.html

// Step 2
// First you'll need to turn the Vec into an iterator
// Then you'll need to apply your function unto each item in the vector
// P.s. Don't forget to collect() at the end!

// Step 3.
// This is very similar to the previous test. The only real change is that you will need to
// alter the type that collect is coerced into. For a bonus you could try doing this with a
// turbofish
<commit_msg>chore(iterators2): Add exercise instructions<commit_after>// iterators2.rs
// In this module, you'll learn some of unique advantages that iterators can offer
// Step 1. Complete the `capitalize_first` function to pass the first two cases
// Step 2. Apply the `capitalize_first` function to a vector of strings, ensuring that it returns a vector of strings as well
// Step 3. Apply the `capitalize_first` function again to a list, but try and ensure it returns a single string
// As always, there are hints below!

pub fn capitalize_first(input: &str) -> String {
    let mut c = input.chars();
    match c.next() {
        None => String::new(),
        Some(first) => first.collect::<String>() + c.as_str(),
    }
}

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

    // Step 1.
    // Tests that verify your `capitalize_first` function implementation
    #[test]
    fn test_success() {
        assert_eq!(capitalize_first("hello"), "Hello");
    }

    #[test]
    fn test_empty() {
        assert_eq!(capitalize_first(""), "");
    }

    // Step 2.
    #[test]
    fn test_iterate_string_vec() {
        let words = vec!["hello", "world"];
        let capitalized_words: Vec<String> = // TODO
        assert_eq!(capitalized_words, ["Hello", "World"]);
    }

    #[test]
    fn test_iterate_into_string() {
        let words = vec!["hello", " ", "world"];
        let capitalized_words = // TODO
        assert_eq!(capitalized_words, "Hello World");
    }
}

// Step 1
// You need to call something on `first` before it can be collected
// Currently it's type is `char`. Have a look at the methods that are available on that type:
// https://doc.rust-lang.org/std/primitive.char.html

// Step 2
// First you'll need to turn the Vec into an iterator
// Then you'll need to apply your function unto each item in the vector
// P.s. Don't forget to collect() at the end!

// Step 3.
// This is very similar to the previous test. The only real change is that you will need to
// alter the type that collect is coerced into. For a bonus you could try doing this with a
// turbofish
<|endoftext|>


<commit_before>extern crate pkg_config;

fn main() {
    println!("cargo:rerun-if-changed=build.rs");
    pkg_config::probe_library("cfitsio").unwrap();
}
<commit_msg>Handle missing cfitsio on pkg-config path<commit_after>extern crate pkg_config;

use std::io::Write;
use pkg_config::Error;

fn main() {

    let package_name = "cfitsio";
    match pkg_config::probe_library(package_name) {
        Ok(_) => {}
        Err(Error::Failure { output, .. }) => {
            // Handle the case where the user has not installed cfitsio, and thusly it is not on
            // the PKG_CONFIG_PATH
            let stderr = String::from_utf8(output.stderr).unwrap();
            if stderr.contains::<&str>(format!("{} was not found in the pkg-config search path",
                                               package_name)
                .as_ref()) {
                let err_msg = format!("
Cannot find {} on the pkg-config search path.  Consider installing the library for your
system (e.g. through homebrew, apt-get etc.).  Alternatively if it is installed, then add
the directory that contains `cfitsio.pc` on your PKG_CONFIG_PATH, e.g.:

PKG_CONFIG_PATH=<blah> cargo build
",
                                      package_name);
                std::io::stderr().write(err_msg.as_bytes()).unwrap();
                std::process::exit(output.status.code().unwrap());
            }
        }
        Err(e) => panic!("Unhandled error: {:?}", e),
    };
}
<|endoftext|>


<commit_before>
use std::borrow::Cow;
use std::fmt;

use assembler::source_file_location::SourceFileLocation;

#[derive(PartialEq, Debug, Clone)]
pub enum Token<'a> {
  /// A single-line comment. Value includes ';' but not the newline.
  SingleLineComment(&'a str, SourceFileLocation<'a>),
  /// A period.
  DirectiveMarker(SourceFileLocation<'a>),
  /// An identifier (starts with an _ or a letter, is an underscore or alphanumeric).
  Identifier(&'a str, SourceFileLocation<'a>),
  /// A colon.
  LabelMarker(SourceFileLocation<'a>),
  /// A string literal, contained in double-quotes. Quotes are not included in the value and it is unescaped.
  StringLiteral(&'a str, SourceFileLocation<'a>),
  /// A numeric literal value.
  NumericLiteral(usize, SourceFileLocation<'a>),
  /// List separator token ','.
  Comma(SourceFileLocation<'a>),
  /// Newline, a \n character.
  Newline(SourceFileLocation<'a>),
  /// An including the reason that the tokenization failed.
  Error(Cow<'a, str>, SourceFileLocation<'a>)
}

impl<'a> Token<'a> {
  /**
   @return A reference to the source file location corresponding to any variant of Token.
   */
  pub fn location(&self) -> &SourceFileLocation<'a> {
    match *self {
      Token::SingleLineComment(_, ref loc)  => loc,
      Token::DirectiveMarker(ref loc)       => loc,
      Token::Identifier(_, ref loc)         => loc,
      Token::LabelMarker(ref loc)           => loc,
      Token::StringLiteral(_, ref loc)      => loc,
      Token::NumericLiteral(_, ref loc)     => loc,
      Token::Comma(ref loc)                 => loc,
      Token::Newline(ref loc)               => loc,
      Token::Error(_, ref loc)              => loc
    }
  }
}

/**
 Un-parameterized display names for tokens.
 */
pub mod display_names {
  pub const SINGLE_LINE_COMMENT: &'static str = "single-line comment";
  pub const DIRECTIVE_MARKER: &'static str = "directive marker";
  pub const IDENTIFIER: &'static str = "identifier";
  pub const LABEL_MARKER: &'static str = "label marker";
  pub const STRING_LITERAL: &'static str = "string literal";
  pub const NUMERIC_LITERAL: &'static str = "numeric literal";
  pub const COMMA: &'static str = "comma";
  pub const NEWLINE: &'static str = "newline";
}

impl<'a> fmt::Display for Token<'a> {
  /**
   Formats the receiver for display purposes. This includes the associated value if any
   while omitting the source file location component. Names are lower-case.
   @param f Formatter to write into.
   @return A result representing the formatted receiver or a failure to write into the Formatter.
   */
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    match *self {
      Token::SingleLineComment(_, _)        => write!(f, "{}", display_names::SINGLE_LINE_COMMENT),
      Token::DirectiveMarker(_)             => write!(f, "{}", display_names::DIRECTIVE_MARKER),
      Token::LabelMarker(_)                 => write!(f, "{}", display_names::LABEL_MARKER),
      Token::Comma(_)                       => write!(f, "{}", display_names::COMMA),
      Token::Newline(_)                     => write!(f, "{}", display_names::NEWLINE),
      Token::Identifier(ref value, _)       => write!(f, "{} ({})", display_names::IDENTIFIER, value),
      Token::StringLiteral(ref value, _)    => write!(f, "{} (\"{}\")", display_names::STRING_LITERAL, value),
      Token::NumericLiteral(ref value, _)   => write!(f, "{} ({} / ${:X})", display_names::NUMERIC_LITERAL, value, value),
      Token::Error(ref reason, _)           => write!(f, "{}", reason)
    }
  }
}

#[cfg(test)]
mod tests {

  use std::borrow::Cow;

  use super::*;

  use assembler::source_file_location::SourceFileLocation;

  #[test]
  fn test_display_fmt() {
    let location = SourceFileLocation::new("test_file.s", 1, 1, 1);
    assert_eq!(format!("{}", Token::SingleLineComment("; Hello", location.clone())), "single-line comment");
    assert_eq!(format!("{}", Token::DirectiveMarker(location.clone())), "directive marker");
    assert_eq!(format!("{}", Token::Identifier("test_id", location.clone())), "identifier (test_id)");
    assert_eq!(format!("{}", Token::LabelMarker(location.clone())), "label marker");
    assert_eq!(format!("{}", Token::StringLiteral("Hello", location.clone())), "string literal (\"Hello\")");
    assert_eq!(format!("{}", Token::NumericLiteral(12, location.clone())), "numeric literal (12 / $C)");
    assert_eq!(format!("{}", Token::Comma(location.clone())), "comma");
    assert_eq!(format!("{}", Token::Newline(location.clone())), "newline");
    assert_eq!(format!("{}", Token::Error(Cow::Borrowed("error_reason"), location.clone())), "error_reason");
  }

}
<commit_msg>Moved for cleanliness.<commit_after>
use std::borrow::Cow;
use std::fmt;

use assembler::source_file_location::SourceFileLocation;

#[derive(PartialEq, Debug, Clone)]
pub enum Token<'a> {
  /// A single-line comment. Value includes ';' but not the newline.
  SingleLineComment(&'a str, SourceFileLocation<'a>),
  /// A period.
  DirectiveMarker(SourceFileLocation<'a>),
  /// An identifier (starts with an _ or a letter, is an underscore or alphanumeric).
  Identifier(&'a str, SourceFileLocation<'a>),
  /// A colon.
  LabelMarker(SourceFileLocation<'a>),
  /// A string literal, contained in double-quotes. Quotes are not included in the value and it is unescaped.
  StringLiteral(&'a str, SourceFileLocation<'a>),
  /// A numeric literal value.
  NumericLiteral(usize, SourceFileLocation<'a>),
  /// List separator token ','.
  Comma(SourceFileLocation<'a>),
  /// Newline, a \n character.
  Newline(SourceFileLocation<'a>),
  /// An including the reason that the tokenization failed.
  Error(Cow<'a, str>, SourceFileLocation<'a>)
}

impl<'a> Token<'a> {
  /**
   @return A reference to the source file location corresponding to any variant of Token.
   */
  pub fn location(&self) -> &SourceFileLocation<'a> {
    match *self {
      Token::SingleLineComment(_, ref loc)  => loc,
      Token::DirectiveMarker(ref loc)       => loc,
      Token::Identifier(_, ref loc)         => loc,
      Token::LabelMarker(ref loc)           => loc,
      Token::StringLiteral(_, ref loc)      => loc,
      Token::NumericLiteral(_, ref loc)     => loc,
      Token::Comma(ref loc)                 => loc,
      Token::Newline(ref loc)               => loc,
      Token::Error(_, ref loc)              => loc
    }
  }
}

impl<'a> fmt::Display for Token<'a> {
  /**
   Formats the receiver for display purposes. This includes the associated value if any
   while omitting the source file location component. Names are lower-case.
   @param f Formatter to write into.
   @return A result representing the formatted receiver or a failure to write into the Formatter.
   */
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    match *self {
      Token::SingleLineComment(_, _)        => write!(f, "{}", display_names::SINGLE_LINE_COMMENT),
      Token::DirectiveMarker(_)             => write!(f, "{}", display_names::DIRECTIVE_MARKER),
      Token::LabelMarker(_)                 => write!(f, "{}", display_names::LABEL_MARKER),
      Token::Comma(_)                       => write!(f, "{}", display_names::COMMA),
      Token::Newline(_)                     => write!(f, "{}", display_names::NEWLINE),
      Token::Identifier(ref value, _)       => write!(f, "{} ({})", display_names::IDENTIFIER, value),
      Token::StringLiteral(ref value, _)    => write!(f, "{} (\"{}\")", display_names::STRING_LITERAL, value),
      Token::NumericLiteral(ref value, _)   => write!(f, "{} ({} / ${:X})", display_names::NUMERIC_LITERAL, value, value),
      Token::Error(ref reason, _)           => write!(f, "{}", reason)
    }
  }
}

/**
 Un-parameterized display names for tokens.
 */
pub mod display_names {
  pub const SINGLE_LINE_COMMENT: &'static str = "single-line comment";
  pub const DIRECTIVE_MARKER: &'static str    = "directive marker";
  pub const IDENTIFIER: &'static str          = "identifier";
  pub const LABEL_MARKER: &'static str        = "label marker";
  pub const STRING_LITERAL: &'static str      = "string literal";
  pub const NUMERIC_LITERAL: &'static str     = "numeric literal";
  pub const COMMA: &'static str               = "comma";
  pub const NEWLINE: &'static str             = "newline";
}

#[cfg(test)]
mod tests {

  use std::borrow::Cow;

  use super::*;

  use assembler::source_file_location::SourceFileLocation;

  #[test]
  fn test_display_fmt() {
    let location = SourceFileLocation::new("test_file.s", 1, 1, 1);
    assert_eq!(format!("{}", Token::SingleLineComment("; Hello", location.clone())), "single-line comment");
    assert_eq!(format!("{}", Token::DirectiveMarker(location.clone())), "directive marker");
    assert_eq!(format!("{}", Token::Identifier("test_id", location.clone())), "identifier (test_id)");
    assert_eq!(format!("{}", Token::LabelMarker(location.clone())), "label marker");
    assert_eq!(format!("{}", Token::StringLiteral("Hello", location.clone())), "string literal (\"Hello\")");
    assert_eq!(format!("{}", Token::NumericLiteral(12, location.clone())), "numeric literal (12 / $C)");
    assert_eq!(format!("{}", Token::Comma(location.clone())), "comma");
    assert_eq!(format!("{}", Token::Newline(location.clone())), "newline");
    assert_eq!(format!("{}", Token::Error(Cow::Borrowed("error_reason"), location.clone())), "error_reason");
  }

}
<|endoftext|>


<commit_before>//! Simple module to store files in database.
//!
//! cratesfyi is generating more than 5 million files, they are small and mostly html files.
//! They are using so many inodes and it is better to store them in database instead of
//! filesystem. This module is adding files into database and retrieving them.

use std::path::{PathBuf, Path};
use postgres::Connection;
use rustc_serialize::json::{Json, ToJson};
use std::fs;
use std::io::Read;
use error::Result;
use failure::err_msg;
use rusoto_s3::{S3, PutObjectRequest, GetObjectRequest, S3Client};
use rusoto_core::region::Region;
use rusoto_credential::EnvironmentProvider;

fn get_file_list_from_dir<P: AsRef<Path>>(path: P,
                                          files: &mut Vec<PathBuf>)
                                          -> Result<()> {
    let path = path.as_ref();

    for file in try!(path.read_dir()) {
        let file = try!(file);

        if try!(file.file_type()).is_file() {
            files.push(file.path());
        } else if try!(file.file_type()).is_dir() {
            try!(get_file_list_from_dir(file.path(), files));
        }
    }

    Ok(())
}

pub fn get_file_list<P: AsRef<Path>>(path: P) -> Result<Vec<PathBuf>> {
    let path = path.as_ref();
    let mut files = Vec::new();

    if !path.exists() {
        return Err(err_msg("File not found"));
    } else if path.is_file() {
        files.push(PathBuf::from(path.file_name().unwrap()));
    } else if path.is_dir() {
        try!(get_file_list_from_dir(path, &mut files));
        for file_path in &mut files {
            // We want the paths in this list to not be {path}/bar.txt but just bar.txt
            *file_path = PathBuf::from(file_path.strip_prefix(path).unwrap());
        }
    }

    Ok(files)
}

pub struct Blob {
    pub path: String,
    pub mime: String,
    pub date_updated: time::Timespec,
    pub content: Vec<u8>,
}

pub fn get_path(conn: &Connection, path: &str) -> Option<Blob> {
    let rows = conn.query("SELECT path, mime, date_updated, content
                           FROM files
                           WHERE path = $1", &[&path]).unwrap();

    if rows.len() == 0 {
        None
    } else {
        let row = rows.get(0);
        let mut content = row.get(3);
        if content == b"in-s3" {
            let client = s3_client();
            content = client.and_then(|c| c.get_object(GetObjectRequest {
                bucket: "rust-docs-rs".into(),
                key: path.into(),
                ..Default::default()
            }).sync().ok()).and_then(|r| r.body).map(|b| {
                let mut b = b.into_blocking_read();
                let mut content = Vec::new();
                b.read_to_end(&mut content).unwrap();
                content
            }).unwrap();
        };

        Some(Blob {
            path: row.get(0),
            mime: row.get(1),
            date_updated: row.get(2),
            content,
        })
    }
}

fn s3_client() -> Option<S3Client> {
    // If AWS keys aren't configured, then presume we should use the DB exclusively
    // for file storage.
    if std::env::var_os("AWS_ACCESS_KEY_ID").is_none() {
        return None;
    }
    Some(S3Client::new_with(
        rusoto_core::request::HttpClient::new().unwrap(),
        EnvironmentProvider::default(),
        std::env::var("S3_ENDPOINT").ok().map(|e| Region::Custom {
            name: "us-west-1".to_owned(),
            endpoint: e,
        }).unwrap_or(Region::UsWest1),
    ))
}

/// Adds files into database and returns list of files with their mime type in Json
pub fn add_path_into_database<P: AsRef<Path>>(conn: &Connection,
                                              prefix: &str,
                                              path: P)
                                              -> Result<Json> {
    use magic::{Cookie, flags};
    let cookie = try!(Cookie::open(flags::MIME_TYPE));
    try!(cookie.load::<&str>(&[]));

    let trans = try!(conn.transaction());
    let client = s3_client();
    let mut file_list_with_mimes: Vec<(String, PathBuf)> = Vec::new();

    for file_path in try!(get_file_list(&path)) {
        let (path, content, mime) = {
            let path = Path::new(path.as_ref()).join(&file_path);
            // Some files have insufficient permissions (like .lock file created by cargo in
            // documentation directory). We are skipping this files.
            let mut file = match fs::File::open(path) {
                Ok(f) => f,
                Err(_) => continue,
            };
            let mut content: Vec<u8> = Vec::new();
            try!(file.read_to_end(&mut content));
            let bucket_path = Path::new(prefix).join(&file_path)
                .into_os_string().into_string().unwrap();

            let mime = {
                let mime = try!(cookie.buffer(&content));
                // css's are causing some problem in browsers
                // magic will return text/plain for css file types
                // convert them to text/css
                // do the same for javascript files
                if mime == "text/plain" {
                    let e = file_path.extension().unwrap_or_default();
                    if e == "css" {
                        "text/css".to_owned()
                    } else if e == "js" {
                        "application/javascript".to_owned()
                    } else {
                        mime.to_owned()
                    }
                } else {
                    mime.to_owned()
                }
            };

            let content: Option<Vec<u8>> = if let Some(client) = &client {
                let s3_res = client.put_object(PutObjectRequest {
                    acl: Some("public-read".into()),
                    bucket: "rust-docs-rs".into(),
                    key: bucket_path.clone(),
                    body: Some(content.clone().into()),
                    content_type: Some(mime.clone()),
                    ..Default::default()
                }).sync();
                match s3_res {
                    // we've successfully uploaded the content, so steal it;
                    // we don't want to put it in the DB
                    Ok(_) => None,
                    // Since s3 was configured, we want to panic on failure to upload.
                    Err(e) => {
                        panic!("failed to upload to {}: {:?}", bucket_path, e)
                    },
                }
            } else {
                Some(content.clone().into())
            };

            file_list_with_mimes.push((mime.clone(), file_path.clone()));

            (
                bucket_path,
                content,
                mime,
            )
        };

        // check if file already exists in database
        let rows = try!(conn.query("SELECT COUNT(*) FROM files WHERE path = $1", &[&path]));

        let content = content.unwrap_or_else(|| "in-s3".to_owned().into());

        if rows.get(0).get::<usize, i64>(0) == 0 {
            try!(trans.query("INSERT INTO files (path, mime, content) VALUES ($1, $2, $3)",
                             &[&path, &mime, &content]));
        } else {
            try!(trans.query("UPDATE files SET mime = $2, content = $3, date_updated = NOW() \
                              WHERE path = $1",
                             &[&path, &mime, &content]));
        }
    }

    try!(trans.commit());

    file_list_to_json(file_list_with_mimes)
}

fn file_list_to_json(file_list: Vec<(String, PathBuf)>) -> Result<Json> {

    let mut file_list_json: Vec<Json> = Vec::new();

    for file in file_list {
        let mut v: Vec<String> = Vec::new();
        v.push(file.0.clone());
        v.push(file.1.into_os_string().into_string().unwrap());
        file_list_json.push(v.to_json());
    }

    Ok(file_list_json.to_json())
}

#[cfg(test)]
mod test {
    extern crate env_logger;
    use std::env;
    use super::get_file_list;

    #[test]
    fn test_get_file_list() {
        let _ = env_logger::try_init();

        let files = get_file_list(env::current_dir().unwrap());
        assert!(files.is_ok());
        assert!(files.unwrap().len() > 0);

        let files = get_file_list(env::current_dir().unwrap().join("Cargo.toml")).unwrap();
        assert_eq!(files[0], std::path::Path::new("Cargo.toml"));
    }
}
<commit_msg>Do not mark objects as public-read in the S3 bucket<commit_after>//! Simple module to store files in database.
//!
//! cratesfyi is generating more than 5 million files, they are small and mostly html files.
//! They are using so many inodes and it is better to store them in database instead of
//! filesystem. This module is adding files into database and retrieving them.

use std::path::{PathBuf, Path};
use postgres::Connection;
use rustc_serialize::json::{Json, ToJson};
use std::fs;
use std::io::Read;
use error::Result;
use failure::err_msg;
use rusoto_s3::{S3, PutObjectRequest, GetObjectRequest, S3Client};
use rusoto_core::region::Region;
use rusoto_credential::EnvironmentProvider;

fn get_file_list_from_dir<P: AsRef<Path>>(path: P,
                                          files: &mut Vec<PathBuf>)
                                          -> Result<()> {
    let path = path.as_ref();

    for file in try!(path.read_dir()) {
        let file = try!(file);

        if try!(file.file_type()).is_file() {
            files.push(file.path());
        } else if try!(file.file_type()).is_dir() {
            try!(get_file_list_from_dir(file.path(), files));
        }
    }

    Ok(())
}

pub fn get_file_list<P: AsRef<Path>>(path: P) -> Result<Vec<PathBuf>> {
    let path = path.as_ref();
    let mut files = Vec::new();

    if !path.exists() {
        return Err(err_msg("File not found"));
    } else if path.is_file() {
        files.push(PathBuf::from(path.file_name().unwrap()));
    } else if path.is_dir() {
        try!(get_file_list_from_dir(path, &mut files));
        for file_path in &mut files {
            // We want the paths in this list to not be {path}/bar.txt but just bar.txt
            *file_path = PathBuf::from(file_path.strip_prefix(path).unwrap());
        }
    }

    Ok(files)
}

pub struct Blob {
    pub path: String,
    pub mime: String,
    pub date_updated: time::Timespec,
    pub content: Vec<u8>,
}

pub fn get_path(conn: &Connection, path: &str) -> Option<Blob> {
    let rows = conn.query("SELECT path, mime, date_updated, content
                           FROM files
                           WHERE path = $1", &[&path]).unwrap();

    if rows.len() == 0 {
        None
    } else {
        let row = rows.get(0);
        let mut content = row.get(3);
        if content == b"in-s3" {
            let client = s3_client();
            content = client.and_then(|c| c.get_object(GetObjectRequest {
                bucket: "rust-docs-rs".into(),
                key: path.into(),
                ..Default::default()
            }).sync().ok()).and_then(|r| r.body).map(|b| {
                let mut b = b.into_blocking_read();
                let mut content = Vec::new();
                b.read_to_end(&mut content).unwrap();
                content
            }).unwrap();
        };

        Some(Blob {
            path: row.get(0),
            mime: row.get(1),
            date_updated: row.get(2),
            content,
        })
    }
}

fn s3_client() -> Option<S3Client> {
    // If AWS keys aren't configured, then presume we should use the DB exclusively
    // for file storage.
    if std::env::var_os("AWS_ACCESS_KEY_ID").is_none() {
        return None;
    }
    Some(S3Client::new_with(
        rusoto_core::request::HttpClient::new().unwrap(),
        EnvironmentProvider::default(),
        std::env::var("S3_ENDPOINT").ok().map(|e| Region::Custom {
            name: "us-west-1".to_owned(),
            endpoint: e,
        }).unwrap_or(Region::UsWest1),
    ))
}

/// Adds files into database and returns list of files with their mime type in Json
pub fn add_path_into_database<P: AsRef<Path>>(conn: &Connection,
                                              prefix: &str,
                                              path: P)
                                              -> Result<Json> {
    use magic::{Cookie, flags};
    let cookie = try!(Cookie::open(flags::MIME_TYPE));
    try!(cookie.load::<&str>(&[]));

    let trans = try!(conn.transaction());
    let client = s3_client();
    let mut file_list_with_mimes: Vec<(String, PathBuf)> = Vec::new();

    for file_path in try!(get_file_list(&path)) {
        let (path, content, mime) = {
            let path = Path::new(path.as_ref()).join(&file_path);
            // Some files have insufficient permissions (like .lock file created by cargo in
            // documentation directory). We are skipping this files.
            let mut file = match fs::File::open(path) {
                Ok(f) => f,
                Err(_) => continue,
            };
            let mut content: Vec<u8> = Vec::new();
            try!(file.read_to_end(&mut content));
            let bucket_path = Path::new(prefix).join(&file_path)
                .into_os_string().into_string().unwrap();

            let mime = {
                let mime = try!(cookie.buffer(&content));
                // css's are causing some problem in browsers
                // magic will return text/plain for css file types
                // convert them to text/css
                // do the same for javascript files
                if mime == "text/plain" {
                    let e = file_path.extension().unwrap_or_default();
                    if e == "css" {
                        "text/css".to_owned()
                    } else if e == "js" {
                        "application/javascript".to_owned()
                    } else {
                        mime.to_owned()
                    }
                } else {
                    mime.to_owned()
                }
            };

            let content: Option<Vec<u8>> = if let Some(client) = &client {
                let s3_res = client.put_object(PutObjectRequest {
                    bucket: "rust-docs-rs".into(),
                    key: bucket_path.clone(),
                    body: Some(content.clone().into()),
                    content_type: Some(mime.clone()),
                    ..Default::default()
                }).sync();
                match s3_res {
                    // we've successfully uploaded the content, so steal it;
                    // we don't want to put it in the DB
                    Ok(_) => None,
                    // Since s3 was configured, we want to panic on failure to upload.
                    Err(e) => {
                        panic!("failed to upload to {}: {:?}", bucket_path, e)
                    },
                }
            } else {
                Some(content.clone().into())
            };

            file_list_with_mimes.push((mime.clone(), file_path.clone()));

            (
                bucket_path,
                content,
                mime,
            )
        };

        // check if file already exists in database
        let rows = try!(conn.query("SELECT COUNT(*) FROM files WHERE path = $1", &[&path]));

        let content = content.unwrap_or_else(|| "in-s3".to_owned().into());

        if rows.get(0).get::<usize, i64>(0) == 0 {
            try!(trans.query("INSERT INTO files (path, mime, content) VALUES ($1, $2, $3)",
                             &[&path, &mime, &content]));
        } else {
            try!(trans.query("UPDATE files SET mime = $2, content = $3, date_updated = NOW() \
                              WHERE path = $1",
                             &[&path, &mime, &content]));
        }
    }

    try!(trans.commit());

    file_list_to_json(file_list_with_mimes)
}

fn file_list_to_json(file_list: Vec<(String, PathBuf)>) -> Result<Json> {

    let mut file_list_json: Vec<Json> = Vec::new();

    for file in file_list {
        let mut v: Vec<String> = Vec::new();
        v.push(file.0.clone());
        v.push(file.1.into_os_string().into_string().unwrap());
        file_list_json.push(v.to_json());
    }

    Ok(file_list_json.to_json())
}

#[cfg(test)]
mod test {
    extern crate env_logger;
    use std::env;
    use super::get_file_list;

    #[test]
    fn test_get_file_list() {
        let _ = env_logger::try_init();

        let files = get_file_list(env::current_dir().unwrap());
        assert!(files.is_ok());
        assert!(files.unwrap().len() > 0);

        let files = get_file_list(env::current_dir().unwrap().join("Cargo.toml")).unwrap();
        assert_eq!(files[0], std::path::Path::new("Cargo.toml"));
    }
}
<|endoftext|>


<commit_before>
use piston::window::WindowSettings;
use piston::input::*;
use glutin_window::GlutinWindow as Window;
use opengl_graphics::{ GlGraphics, OpenGL };
use piston::event_loop::Events;

use std::sync::{Arc, Mutex};

pub struct App {
    // OpenGL drawing backend.
    gl: GlGraphics,
    fft_magnitudes: Arc<Mutex<Vec<f32>>>,
    vertical_lines : Arc<Mutex<Vec<([f32 ; 4], f32)>>>
}

impl App {
    #[allow(dead_code)]
    pub fn set_fft_magnitudes(&mut self, mags : &Vec<f32>) {
        let mut app_mags = self.fft_magnitudes.lock().unwrap();
        app_mags.clear();
        for f in mags.iter() {
            app_mags.push(*f);
        }
    }
}

impl App {
    fn render(&mut self, args: &RenderArgs) {
        use graphics::*;

        const WHITE: [f32; 4] = [231.0/255.0, 222.0/255.0, 219.0/255.0, 1.0];
        const BLUE:   [f32; 4] = [18.0/255.0, 87.0/255.0, 150.0/255.0, 1.0];
        let fft_magnitudes = self.fft_magnitudes.lock().unwrap();
        let vertical_lines = self.vertical_lines.lock().unwrap();
        if fft_magnitudes.len() == 0{
            return;
        }

        let n = f64::min(fft_magnitudes.len() as f64, 2048.);

        self.gl.draw(args.viewport(), |c, gl| {
            let w = args.width;
            let h = args.height;
            let side_length = w as f64 / n;

            // Clear the screen.
            clear(BLUE, gl);

            // Draw a box rotating around the middle of the screen.
            let mut i = 0;
            for fft_mag in fft_magnitudes.iter() {
                if i as f64 >= n {
                    break;
                }
                rectangle(
                    WHITE,
                    [i as f64 * side_length, (h - 1) as f64, side_length, -(*fft_mag as f64 * h as f64 /1.)],
                    c.transform,
                    gl);
                i += 1;
            }
            for &(color, vert_idx) in vertical_lines.iter() {
                rectangle(
                    color,
                    [vert_idx as f64 / n as f64 * w as f64, 0.0, 1.0, h as f64],
                    c.transform,
                    gl);
            }
        });
    }

    fn update(&mut self, _: &UpdateArgs) {
    }
}

pub fn init(fft_magnitudes : Arc<Mutex<Vec<f32>>>,
            vertical_lines : Arc<Mutex<Vec<([f32; 4], f32)>>>) {
    let opengl = OpenGL::V3_2;

    // Create an Glutin window.
    let mut window : Window = WindowSettings::new(
            "meter | Opera of the Future",
            [920, 500]
        )
        .opengl(opengl)
        .exit_on_esc(true).build().unwrap();

    // Create a new game and run it.
    let mut app = App {
        gl: GlGraphics::new(opengl),
        fft_magnitudes: fft_magnitudes,
        vertical_lines : vertical_lines
    };
    let mut events = window.events();
    while let Some(e) = events.next(&mut window) {
        if let Some(r) = e.render_args() {
            app.render(&r);
        }

        if let Some(u) = e.update_args() {
            app.update(&u);
        }
    }
}
<commit_msg>window title -> Kevin King<commit_after>
use piston::window::WindowSettings;
use piston::input::*;
use glutin_window::GlutinWindow as Window;
use opengl_graphics::{ GlGraphics, OpenGL };
use piston::event_loop::Events;

use std::sync::{Arc, Mutex};

pub struct App {
    // OpenGL drawing backend.
    gl: GlGraphics,
    fft_magnitudes: Arc<Mutex<Vec<f32>>>,
    vertical_lines : Arc<Mutex<Vec<([f32 ; 4], f32)>>>
}

impl App {
    #[allow(dead_code)]
    pub fn set_fft_magnitudes(&mut self, mags : &Vec<f32>) {
        let mut app_mags = self.fft_magnitudes.lock().unwrap();
        app_mags.clear();
        for f in mags.iter() {
            app_mags.push(*f);
        }
    }
}

impl App {
    fn render(&mut self, args: &RenderArgs) {
        use graphics::*;

        const WHITE: [f32; 4] = [231.0/255.0, 222.0/255.0, 219.0/255.0, 1.0];
        const BLUE:   [f32; 4] = [18.0/255.0, 87.0/255.0, 150.0/255.0, 1.0];
        let fft_magnitudes = self.fft_magnitudes.lock().unwrap();
        let vertical_lines = self.vertical_lines.lock().unwrap();
        if fft_magnitudes.len() == 0{
            return;
        }

        let n = f64::min(fft_magnitudes.len() as f64, 2048.);

        self.gl.draw(args.viewport(), |c, gl| {
            let w = args.width;
            let h = args.height;
            let side_length = w as f64 / n;

            // Clear the screen.
            clear(BLUE, gl);

            // Draw a box rotating around the middle of the screen.
            let mut i = 0;
            for fft_mag in fft_magnitudes.iter() {
                if i as f64 >= n {
                    break;
                }
                rectangle(
                    WHITE,
                    [i as f64 * side_length, (h - 1) as f64, side_length, -(*fft_mag as f64 * h as f64 /1.)],
                    c.transform,
                    gl);
                i += 1;
            }
            for &(color, vert_idx) in vertical_lines.iter() {
                rectangle(
                    color,
                    [vert_idx as f64 / n as f64 * w as f64, 0.0, 1.0, h as f64],
                    c.transform,
                    gl);
            }
        });
    }

    fn update(&mut self, _: &UpdateArgs) {
    }
}

pub fn init(fft_magnitudes : Arc<Mutex<Vec<f32>>>,
            vertical_lines : Arc<Mutex<Vec<([f32; 4], f32)>>>) {
    let opengl = OpenGL::V3_2;

    // Create an Glutin window.
    let mut window : Window = WindowSettings::new(
            "meter | Kevin King",
            [920, 500]
        )
        .opengl(opengl)
        .exit_on_esc(true).build().unwrap();

    // Create a new game and run it.
    let mut app = App {
        gl: GlGraphics::new(opengl),
        fft_magnitudes: fft_magnitudes,
        vertical_lines : vertical_lines
    };
    let mut events = window.events();
    while let Some(e) = events.next(&mut window) {
        if let Some(r) = e.render_args() {
            app.render(&r);
        }

        if let Some(u) = e.update_args() {
            app.update(&u);
        }
    }
}
<|endoftext|>


<commit_before>//! Binary encoding for lambda expressions

use lambda_calculus::term::*;
use lambda_calculus::term::Term::*;
use self::Error::*;

#[derive(Debug, PartialEq)]
pub enum Error {
    NotATerm
}

fn _from_binary(input: &[u8]) -> Option<(Term, &[u8])> {
    if input.len() == 0 { return None }

    if [9, 10, 13, 32].contains(&input[0]) {
        _from_binary(&input[1..])
    } else {
        match &input[0..2] {
            b"00" => {
                if let Some((term, rest)) = _from_binary(&input[2..]) {
                    Some((abs(term), rest))
                } else {
                    None
                }
            },
            b"01" => {
                if let Some((term1, rest1)) = _from_binary(&input[2..]) {
                    if let Some((term2, rest2)) = _from_binary(&rest1) {
                        Some((app(term1, term2), &rest2))
                    } else {
                        None
                    }
                } else {
                    None
                }
            },
            b"10" | b"11" => {
                let i = input.iter().take_while(|&b| *b == b'1').count();
                if input[2..].len() == 0 {
                    Some((Var(i), &*b""))
                } else {
                    Some((Var(i), &input[i+1..]))
                }
            },
            _ => None
        }
    }
}

/// Parse a binary-encoded lambda `Term`.
///
/// # Example
/// ```
/// use blc::binary_encoding::{from_binary, to_binary};
///
/// let k = from_binary(b"0000110");
///
/// assert!(k.is_ok());
/// assert_eq!(to_binary(&k.unwrap()), "0000110".to_owned());
/// ```
pub fn from_binary(input: &[u8]) -> Result<Term, Error> {
    if let Some((result, _)) = _from_binary(input) {
        Ok(result)
    } else {
        Err(NotATerm)
    }
}

/// Represent a lambda `Term` in binary.
///
/// # Example
/// ```
/// use blc::binary_encoding::{from_binary, to_binary};
///
/// let k = from_binary(b"0000110");
///
/// assert!(k.is_ok());
/// assert_eq!(to_binary(&k.unwrap()), "0000110".to_owned());
/// ```
pub fn to_binary(term: &Term) -> String {
    match *term {
        Var(i) => format!("{}0", "1".repeat(i)),
        Abs(ref t) => format!("00{}", to_binary(t)),
        App(ref t1, ref t2) => format!("01{}{}", to_binary(t1), to_binary(t2))
    }
}

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

    #[test]
    fn variables() {
        assert_eq!(from_binary(b"10"),   Ok(Var(1)));
        assert_eq!(from_binary(b"110"),  Ok(Var(2)));
        assert_eq!(from_binary(b"1110"), Ok(Var(3)));
    }

    #[test]
    fn abstractions() {
        assert_eq!(from_binary(b"0010"),     Ok(abs(Var(1))));
        assert_eq!(from_binary(b"000010"),   Ok(abs(abs(Var(1)))));
        assert_eq!(from_binary(b"00000010"), Ok(abs(abs(abs((Var(1)))))));
    }

    #[test]
    fn applications() {
        assert_eq!(from_binary(b"011010"),  Ok(app(Var(1), Var(1))));
        assert_eq!(from_binary(b"0110110"), Ok(app(Var(1), Var(2))));
        assert_eq!(from_binary(b"0111010"), Ok(app(Var(2), Var(1))));
    }

    #[test]
    fn ignoring_whitespaces() {
        assert_eq!(from_binary(b"00 00\t00\n10\r\n"), Ok(abs(abs(abs((Var(1)))))));
    }

    #[test]
    fn parse_and_display() {
        let k =      b"0000110";
        let v15 =    b"1111111111111110";
        let s =      b"00000001011110100111010";
        let succ =   b"000000011100101111011010";
        let quine =  b"000101100100011010000000000001011011110010111100111111011111011010";
        let primes = b"000100011001100101000110100000000101100000100100010101111101111010010001101\
                       000011100110100000000001011011100111001111111011110000000011111001101110000\
                       00101100000110110";
        let blc =    b"010100011010000000010101100000000001111000010111111001111000010111001111000\
                       000111100001011011011100111110000111110000101111010011101001011001110000110\
                       110000101111100001111100001110011011110111110011110111011000011001000110100\
                       0011010";

        assert_eq!(format!("{}", from_binary(&*k).unwrap()),      "λλ2");
        assert_eq!(format!("{}", from_binary(&*v15).unwrap()),    "F");
        assert_eq!(format!("{}", from_binary(&*s).unwrap()),      "λλλ31(21)");
        assert_eq!(format!("{}", from_binary(&*succ).unwrap()),   "λλλ2(321)");
        assert_eq!(format!("{}", from_binary(&*quine).unwrap()),  "λ1((λ11)(λλλλλ14(3(55)2)))1");
        assert_eq!(format!("{}", from_binary(&*primes).unwrap()), "λ(λ1(1((λ11)(λλλ1(λλ1)((λ441((λ\
            11)(λ2(11))))(λλλλ13(2(64)))))(λλλ4(13)))))(λλ1(λλ2)2)");
        assert_eq!(format!("{}", from_binary(&*blc).unwrap()),    "(λ11)(λλλ1(λλλλ3(λ5(3(λ2(3(λλ3(\
            λ123)))(4(λ4(λ31(21))))))(1(2(λ12))(λ4(λ4(λ2(14)))5))))(33)2)(λ1((λ11)(λ11)))");
    }
}
<commit_msg>Beef up a test<commit_after>//! Binary encoding for lambda expressions

use lambda_calculus::term::*;
use lambda_calculus::term::Term::*;
use self::Error::*;
use std::str::from_utf8;

#[derive(Debug, PartialEq)]
pub enum Error {
    NotATerm
}

fn _from_binary(input: &[u8]) -> Option<(Term, &[u8])> {
    if input.len() == 0 { return None }

    if [9, 10, 13, 32].contains(&input[0]) {
        _from_binary(&input[1..])
    } else {
        match &input[0..2] {
            b"00" => {
                if let Some((term, rest)) = _from_binary(&input[2..]) {
                    Some((abs(term), rest))
                } else {
                    None
                }
            },
            b"01" => {
                if let Some((term1, rest1)) = _from_binary(&input[2..]) {
                    if let Some((term2, rest2)) = _from_binary(&rest1) {
                        Some((app(term1, term2), &rest2))
                    } else {
                        None
                    }
                } else {
                    None
                }
            },
            b"10" | b"11" => {
                let i = input.iter().take_while(|&b| *b == b'1').count();
                if input[2..].len() == 0 {
                    Some((Var(i), &*b""))
                } else {
                    Some((Var(i), &input[i+1..]))
                }
            },
            _ => None
        }
    }
}

/// Parse a binary-encoded lambda `Term`.
///
/// # Example
/// ```
/// use blc::binary_encoding::{from_binary, to_binary};
///
/// let k = from_binary(b"0000110");
///
/// assert!(k.is_ok());
/// assert_eq!(to_binary(&k.unwrap()), "0000110".to_owned());
/// ```
pub fn from_binary(input: &[u8]) -> Result<Term, Error> {
    if let Some((result, _)) = _from_binary(input) {
        Ok(result)
    } else {
        Err(NotATerm)
    }
}

/// Represent a lambda `Term` in binary.
///
/// # Example
/// ```
/// use blc::binary_encoding::{from_binary, to_binary};
///
/// let k = from_binary(b"0000110");
///
/// assert!(k.is_ok());
/// assert_eq!(to_binary(&k.unwrap()), "0000110".to_owned());
/// ```
pub fn to_binary(term: &Term) -> String {
    match *term {
        Var(i) => format!("{}0", "1".repeat(i)),
        Abs(ref t) => format!("00{}", to_binary(t)),
        App(ref t1, ref t2) => format!("01{}{}", to_binary(t1), to_binary(t2))
    }
}

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

    #[test]
    fn variables() {
        assert_eq!(from_binary(b"10"),   Ok(Var(1)));
        assert_eq!(from_binary(b"110"),  Ok(Var(2)));
        assert_eq!(from_binary(b"1110"), Ok(Var(3)));
    }

    #[test]
    fn abstractions() {
        assert_eq!(from_binary(b"0010"),     Ok(abs(Var(1))));
        assert_eq!(from_binary(b"000010"),   Ok(abs(abs(Var(1)))));
        assert_eq!(from_binary(b"00000010"), Ok(abs(abs(abs((Var(1)))))));
    }

    #[test]
    fn applications() {
        assert_eq!(from_binary(b"011010"),  Ok(app(Var(1), Var(1))));
        assert_eq!(from_binary(b"0110110"), Ok(app(Var(1), Var(2))));
        assert_eq!(from_binary(b"0111010"), Ok(app(Var(2), Var(1))));
    }

    #[test]
    fn ignoring_whitespaces() {
        assert_eq!(from_binary(b"00 00\t00\n10\r\n"), Ok(abs(abs(abs((Var(1)))))));
    }

    #[test]
    fn from_binary_and_back() {
        let k =      b"0000110";
        let v15 =    b"1111111111111110";
        let s =      b"00000001011110100111010";
        let succ =   b"000000011100101111011010";
        let quine =  b"000101100100011010000000000001011011110010111100111111011111011010";
        let primes = b"000100011001100101000110100000000101100000100100010101111101111010010001101\
                       000011100110100000000001011011100111001111111011110000000011111001101110000\
                       00101100000110110";
        let blc =    b"010100011010000000010101100000000001111000010111111001111000010111001111000\
                       000111100001011011011100111110000111110000101111010011101001011001110000110\
                       110000101111100001111100001110011011110111110011110111011000011001000110100\
                       0011010";

        assert_eq!(to_binary(&from_binary(&*k).unwrap()).as_bytes(),    k);
        assert_eq!(to_binary(&from_binary(&*v15).unwrap()).as_bytes(),  v15);
        assert_eq!(to_binary(&from_binary(&*s).unwrap()).as_bytes(),    s);
        assert_eq!(to_binary(&from_binary(&*succ).unwrap()).as_bytes(), succ);
        assert_eq!(to_binary(&from_binary(&*quine).unwrap()),           from_utf8(quine).unwrap());
        assert_eq!(to_binary(&from_binary(&*primes).unwrap()),          from_utf8(primes).unwrap());
        assert_eq!(to_binary(&from_binary(&*blc).unwrap()),             from_utf8(blc).unwrap());
    }
}
<|endoftext|>


<commit_before>//! Implementation of the fast sweeping method.

/// Computes the solution of the eikonal equation in 3D using the fast sweeping algorithm.
///
/// `d` should be initialized to a large value at the unknown nodes.
///
/// `inv_dual_norm(d, [d1, d2, d3], [s1, s2, s3]) -> t` needs to solve the "inverse problem" for the norm:
/// Given values `d_i` at points `-s_i e_i`, find the largest value `t ≤ d` at the origin such that
/// `||p|| ≤ 1`, where `p_i = (s_i (t - d_i))_+` and `||p||` is the __dual__ anisotropic norm.
pub fn fast_sweep_3d<F>(
    d: &mut [f64],
    dim: (usize, usize, usize),
    mut inv_dual_norm: F,
) where
    F: FnMut(f64, [f64; 3], [f64; 3]) -> f64,
{
    let (nx, ny, nz) = dim;
    assert_eq!(nx * ny * nz, d.len());
    let (sx, sy, sz) = (ny * nz, nz, 1);
    // sweep in 8 directions
    for m in 0..8 {
        for p in 1..nx {
            let (i, ip, isign) = if m & 0b001 == 0 {
                (nx - 1 - p, nx - 1 - p + 1, -1.)
            } else {
                (p, p - 1, 1.)
            };
            for q in 1..ny {
                let (j, jp, jsign) = if m & 0b010 == 0 {
                    (ny - 1 - q, ny - 1 - q + 1, -1.)
                } else {
                    (q, q - 1, 1.)
                };

                if m & 0b100 == 0 {
                    let ksign = -1.;
                    for k in (0..nz - 1).rev() {
                        let kp = k + 1;
                        let s = i * sx + j * sy + k * sz;

                        d[s] = inv_dual_norm(
                            d[s],
                            [
                                d[ip * sx + j * sy + k * sz],
                                d[i * sx + jp * sy + k * sz],
                                d[i * sx + j * sy + kp * sz],
                            ],
                            [isign, jsign, ksign],
                        );
                    }
                } else {
                    let ksign = 1.;
                    for k in 1..nz {
                        let kp = k - 1;
                        let s = i * sx + j * sy + k * sz;

                        d[s] = inv_dual_norm(
                            d[s],
                            [
                                d[ip * sx + j * sy + k * sz],
                                d[i * sx + jp * sy + k * sz],
                                d[i * sx + j * sy + kp * sz],
                            ],
                            [isign, jsign, ksign],
                        );
                    }
                }
            }
        }
    }
}

/// Computes the solution of the eikonal equation in 2D using the fast sweeping algorithm.
///
/// `inv_dual_norm(d, [d1, d2], [s1, s2]) -> t` needs to solve the "inverse problem" for the norm:
/// Given values `d_i` at points `-s_i e_i`, find the largest value `t ≤ d` at the origin such that
/// `||p|| ≤ 1`, where `p_i = (s_i (t - d_i))_+` and `||p||` is the __dual__ anisotropic norm.
pub fn fast_sweep_2d<F>(d: &mut [f64], dim: (usize, usize), mut inv_dual_norm: F)
where
    F: FnMut(f64, [f64; 2], [f64; 2]) -> f64,
{
    let (nx, ny) = dim;
    let (sx, _sy) = (ny, 1);
    assert_eq!(nx * ny, d.len());
    // sweep in 4 directions
    // for m in 0..4 {
    //     for p in 1..nx {
    //         let (i, ip, isign) = if m & 0b001 == 0 {
    //             (nx - 1 - p, nx - 1 - p + 1, -1.)
    //         } else {
    //             (p, p - 1, 1.)
    //         };
    //         for q in 1..ny {
    //             let (j, jp, jsign) = if m & 0b010 == 0 {
    //                 (ny - 1 - q, ny - 1 - q + 1, -1.)
    //             } else {
    //                 (q, q - 1, 1.)
    //             };
    //
    //             let s = i * sx + j * sy;
    //
    //             d[s] = inv_dual_norm(
    //                 d[s],
    //                 [d[ip * sx + j * sy], d[i * sx + jp * sy]],
    //                 [isign, jsign],
    //             );
    //         }
    //     }
    // }

    // sweep in 4 directions
    // try to avoid bounds checks and impove cache locality (about 45% faster than the above version)
    for p in 1..nx {
        let (di, dj) = d.split_at_mut(p * sx);
        let di = &di[(p - 1) * sx..][..ny];
        let dj = &mut dj[..ny];
        for q in 1..ny {
            let j = q;
            dj[j] = inv_dual_norm(dj[j], [di[j], dj[j - 1]], [1., 1.]);
            // Rust 1.30 cannot optimize away 2 bounds checks here :(
            let j = ny - 1 - q;
            dj[j] = inv_dual_norm(dj[j], [di[j], dj[j + 1]], [1., -1.]);
        }
    }
    for p in (0..nx - 1).rev() {
        let (dj, di) = d.split_at_mut((p + 1) * sx);
        let di = &di[..ny];
        let dj = &mut dj[p * sx..][..ny];
        for q in 1..ny {
            let j = q;
            dj[j] = inv_dual_norm(dj[j], [di[j], dj[j - 1]], [-1., 1.]);
            let j = ny - 1 - q;
            dj[j] = inv_dual_norm(dj[j], [di[j], dj[j + 1]], [-1., -1.]);
        }
    }
}
<commit_msg>Try using iterators to avoid bounds checks<commit_after>//! Implementation of the fast sweeping method.

/// Computes the solution of the eikonal equation in 3D using the fast sweeping algorithm.
///
/// `d` should be initialized to a large value at the unknown nodes.
///
/// `inv_dual_norm(d, [d1, d2, d3], [s1, s2, s3]) -> t` needs to solve the "inverse problem" for the norm:
/// Given values `d_i` at points `-s_i e_i`, find the largest value `t ≤ d` at the origin such that
/// `||p|| ≤ 1`, where `p_i = (s_i (t - d_i))_+` and `||p||` is the __dual__ anisotropic norm.
pub fn fast_sweep_3d<F>(
    d: &mut [f64],
    dim: (usize, usize, usize),
    mut inv_dual_norm: F,
) where
    F: FnMut(f64, [f64; 3], [f64; 3]) -> f64,
{
    let (nx, ny, nz) = dim;
    assert_eq!(nx * ny * nz, d.len());
    let (sx, sy, sz) = (ny * nz, nz, 1);
    // sweep in 8 directions
    for m in 0..8 {
        for p in 1..nx {
            let (i, ip, isign) = if m & 0b001 == 0 {
                (nx - 1 - p, nx - 1 - p + 1, -1.)
            } else {
                (p, p - 1, 1.)
            };
            for q in 1..ny {
                let (j, jp, jsign) = if m & 0b010 == 0 {
                    (ny - 1 - q, ny - 1 - q + 1, -1.)
                } else {
                    (q, q - 1, 1.)
                };

                if m & 0b100 == 0 {
                    let ksign = -1.;
                    for k in (0..nz - 1).rev() {
                        let kp = k + 1;
                        let s = i * sx + j * sy + k * sz;

                        d[s] = inv_dual_norm(
                            d[s],
                            [
                                d[ip * sx + j * sy + k * sz],
                                d[i * sx + jp * sy + k * sz],
                                d[i * sx + j * sy + kp * sz],
                            ],
                            [isign, jsign, ksign],
                        );
                    }
                } else {
                    let ksign = 1.;
                    for k in 1..nz {
                        let kp = k - 1;
                        let s = i * sx + j * sy + k * sz;

                        d[s] = inv_dual_norm(
                            d[s],
                            [
                                d[ip * sx + j * sy + k * sz],
                                d[i * sx + jp * sy + k * sz],
                                d[i * sx + j * sy + kp * sz],
                            ],
                            [isign, jsign, ksign],
                        );
                    }
                }
            }
        }
    }
}

/// Computes the solution of the eikonal equation in 2D using the fast sweeping algorithm.
///
/// `inv_dual_norm(d, [d1, d2], [s1, s2]) -> t` needs to solve the "inverse problem" for the norm:
/// Given values `d_i` at points `-s_i e_i`, find the largest value `t ≤ d` at the origin such that
/// `||p|| ≤ 1`, where `p_i = (s_i (t - d_i))_+` and `||p||` is the __dual__ anisotropic norm.
pub fn fast_sweep_2d<F>(d: &mut [f64], dim: (usize, usize), mut inv_dual_norm: F)
where
    F: FnMut(f64, [f64; 2], [f64; 2]) -> f64,
{
    let (nx, ny) = dim;
    let (sx, _sy) = (ny, 1);
    assert_eq!(nx * ny, d.len());
    // sweep in 4 directions
    // for m in 0..4 {
    //     for p in 1..nx {
    //         let (i, ip, isign) = if m & 0b001 == 0 {
    //             (nx - 1 - p, nx - 1 - p + 1, -1.)
    //         } else {
    //             (p, p - 1, 1.)
    //         };
    //         for q in 1..ny {
    //             let (j, jp, jsign) = if m & 0b010 == 0 {
    //                 (ny - 1 - q, ny - 1 - q + 1, -1.)
    //             } else {
    //                 (q, q - 1, 1.)
    //             };
    //
    //             let s = i * sx + j * sy;
    //
    //             d[s] = inv_dual_norm(
    //                 d[s],
    //                 [d[ip * sx + j * sy], d[i * sx + jp * sy]],
    //                 [isign, jsign],
    //             );
    //         }
    //     }
    // }

    // sweep in 4 directions
    // try to avoid bounds checks and impove cache locality (about 45% faster than the above version)
    for p in 1..nx {
        let (di, dj) = d.split_at_mut(p * sx);
        let di = &di[(p - 1) * sx..][..ny];
        let dj = &mut dj[..ny];
        for q in 1..ny {
            let j = q;
            // Two independent computations (both forward and reversed sweep at once). Instruction
            // level parallelism! Major performance gain.
            dj[j] = inv_dual_norm(dj[j], [di[j], dj[j - 1]], [1., 1.]);
            // rust 1.30 cannot optimize away 2 bounds checks here :(
            let j = ny - 1 - q;
            dj[j] = inv_dual_norm(dj[j], [di[j], dj[j + 1]], [1., -1.]);
        }
        // The following code avoids bounds checks, but cannot exploit instruction level parallelism in the
        // above loop.
        // let mut prev = dj[0];
        // for (dj, di) in (&mut dj[1..]).into_iter().zip(di[1..].into_iter()) {
        //     prev = inv_dual_norm(*dj, [*di, prev], [1., 1.]);
        //     *dj = prev;
        // }
        // let mut prev = dj[ny - 1];
        // for (dj, di) in (&mut dj[..ny-1]).into_iter().zip(di[..ny-1].into_iter()).rev() {
        //     prev = inv_dual_norm(*dj, [*di, prev], [1., -1.]);
        //     *dj = prev;
        // }
    }
    for p in (0..nx - 1).rev() {
        let (dj, di) = d.split_at_mut((p + 1) * sx);
        let di = &di[..ny];
        let dj = &mut dj[p * sx..][..ny];
        for q in 1..ny {
            let j = q;
            dj[j] = inv_dual_norm(dj[j], [di[j], dj[j - 1]], [-1., 1.]);
            let j = ny - 1 - q;
            dj[j] = inv_dual_norm(dj[j], [di[j], dj[j + 1]], [-1., -1.]);
        }
    }
}
<|endoftext|>