<commit_before>extern crate hyper;
extern crate multipart;
extern crate serde_json;

use hyper::net::Streaming;
use hyper::method::Method;
use hyper::client::Request;

use hyper::client::RequestBuilder;
use hyper::Client;
use hyper::Url;

use multipart::client::Multipart;

use serde_json::value::Value;

use std::result::Result;
use std::sync::Arc;
use std::io::Read;
use std::{fmt, error};

pub mod types {
    extern crate serde_json;
    use serde_json::value::Value;

    include!(concat!(env!("OUT_DIR"), "/types.rs"));
}

pub mod args;
pub mod builders;

use types::*;

// TODO: Organize this mess and get rid of most unwraps

#[derive(Debug)]
pub enum BotError {
    Http (hyper::error::Error),
    Api {
        error_code: i64,
        description: String,
        parameters: Option<ResponseParameters>
    }
}

impl fmt::Display for BotError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &BotError::Http(ref e) => {
                write!(f, "{}", e)
            },
            &BotError::Api { error_code, ref description, parameters: _ } => {
                write!(f, "Error {0}: {1}", error_code, description)
            }
        }
    }
}

impl error::Error for BotError {
    fn description(&self) -> &str {
        "Something unexpected occured while talking to the telegram bot api." // meh
    }
}

fn parse_request(response: Result<hyper::client::Response, hyper::Error>) -> Result<Value, BotError> {
    match response {
        Ok(mut res) => {
            let mut body = String::new();
            res.read_to_string(&mut body).unwrap();
            let got_me: ApiResult = serde_json::from_str(&body).unwrap();
            if let Some(val) = got_me.result {
                Ok(val)
            } else {
                Err(BotError::Api{
                    error_code: got_me.error_code.unwrap(),
                    description: got_me.description.unwrap(),
                    parameters: got_me.parameters
                })
            }
        },
        Err(e) => {
            Err(BotError::Http(e))
        }
    }
}

#[derive(Debug)]
pub struct BotApi {
    base_url: Url,
    client: Client,
}

impl Clone for BotApi {
    fn clone(&self) -> BotApi {
        BotApi {
            base_url: self.base_url.clone(),
            client: Client::new(),
        }
    }
}

impl BotApi {
    pub fn new(bot_token: &str) -> BotApi {
        let url = format!("https://api.telegram.org/bot{}/", bot_token);

        BotApi {
            base_url: url.parse().unwrap(),
            client: Client::new(),
        }
    }

    pub fn get_me(&self) -> Result<User, BotError> {
        let url = self.base_url.join("getMe").unwrap();
        let res = parse_request(self.client.get(url).send());
        match res {
            Ok(val) => Ok(serde_json::value::from_value(val).unwrap()),
            Err(e) => Err(e),
        }
    }

    pub fn get_updates(&self, params: &args::GetUpdates) -> Result<Vec<Update>, BotError> {
        let url = self.base_url.join("getUpdates").unwrap();

        // All these unwraps make me uncomfortable, someone is going to yell
        // at me to get some good error handling. And they would be right
        // but I'm really lazy and I don't want to deal with this. I should
        // though because it's good practice and no real software should ever
        // just throw errors around like they don't matter.

        // Manage your errors

        let req = Request::new(Method::Post, url).unwrap();

        let mut multi = Multipart::from_request(req).unwrap();

        if let Some(offset) = params.offset {
            multi.write_text("offset", offset.to_string()).unwrap();
        }

        if let Some(limit) = params.limit {
            multi.write_text("limit", limit.to_string()).unwrap();
        }

        if let Some(timeout) = params.timeout {
            multi.write_text("timeout", timeout.to_string()).unwrap();
        }

        if let Some(allowed_updates) = params.allowed_updates {
            for allowed_update in allowed_updates {
                multi.write_text("allowed_updates[]", allowed_update).unwrap();
            }
        }

        match parse_request(multi.send()) {
            Ok(val) => Ok(serde_json::value::from_value(val).unwrap()),
            Err(e) => Err(e),
        }
    }

    pub fn send_message(&self, params: &args::SendMessage) -> Result<Message, BotError> {
        let url = self.base_url.join("sendMessage").unwrap();
        let req = Request::new(Method::Post, url).unwrap();
        let mut multi = Multipart::from_request(req).unwrap();

        if let Some(chat_id) = params.chat_id {
            multi.write_text("chat_id", chat_id.to_string()).unwrap();
        } else
        if let Some(chat_username) = params.chat_username {
            multi.write_text("chat_id", chat_username).unwrap();
        }

        multi.write_text("text", params.text).unwrap();

        if let Some(parse_mode) = params.parse_mode {
            multi.write_text("parse_mode", parse_mode).unwrap();
        }

        if let Some(disable_web_page_preview) = params.disable_web_page_preview {
            multi.write_text("disable_web_page_preview", disable_web_page_preview.to_string()).unwrap();
        }

        if let Some(disable_notification) = params.disable_notification {
            multi.write_text("disable_notification", disable_notification.to_string()).unwrap();
        }

        if let Some(reply_to_message_id) = params.reply_to_message_id {
            multi.write_text("reply_to_message_id", reply_to_message_id.to_string()).unwrap();
        }

        if let Some(reply_markup) = params.reply_markup {
            value_to_multi(&mut multi, "reply_markup", serde_json::to_value(reply_markup), false);
        }

        match parse_request(multi.send()) {
            Ok(val) => Ok(serde_json::value::from_value(val).unwrap()),
            Err(e) => Err(e),
        }
    }
} // 2: TODO don't use multipart when you don't have to
//multipart::client::Multipart<>
fn value_to_multi(multi: &mut multipart::client::Multipart<hyper::client::Request<hyper::net::Streaming>>, key: &str, val: Value, from_obj: bool) {
    match val {
        Value::Null => {
            multi.write_text(key, "null").unwrap();
        }
        Value::Bool(v) => {
            if from_obj {
                multi.write_text(&str::replace(key, "{}", ""), v.to_string()).unwrap();
            } else {
                multi.write_text(key, v.to_string()).unwrap();
            }
        }
        Value::I64(v) => {
            if from_obj {
                multi.write_text(&str::replace(key, "{}", ""), v.to_string()).unwrap();
            } else {
                multi.write_text(key, v.to_string()).unwrap();
            }
        }
        Value::U64(v) => {
            if from_obj {
                multi.write_text(&str::replace(key, "{}", ""), v.to_string()).unwrap();
            } else {
                multi.write_text(key, v.to_string()).unwrap();
            }
        }
        Value::F64(v) => {
            if from_obj {
                multi.write_text(&str::replace(key, "{}", ""), v.to_string()).unwrap();
            } else {
                multi.write_text(key, v.to_string()).unwrap();
            }
        }
        Value::String(v) => {
            if from_obj {
                multi.write_text(&str::replace(key, "{}", ""), v.to_string()).unwrap();
            } else {
                multi.write_text(key, v.to_string()).unwrap();
            }
        }
        Value::Array(a) => {
            let mut n = String::from(key);
            n.push_str("[]");
            for item in a {
                value_to_multi(multi, &n, item, false);
            }
        }
        Value::Object(map) => {
            for (map_key, map_value) in map {
                let n = String::from(key);
                n.replace("{}", &map_key);
                value_to_multi(multi, &n, map_value, true);
            }
        }
    }
}

#[cfg(test)]
mod tests { // These aren't going to be the actual tests, just a place for me to easily test things as I go along
    use super::*;
    extern crate serde_json;
    #[test]
    fn it_works() {
        let token = "";
        let bot = BotApi::new(token);

        let mut update_args = args::GetUpdates {
            offset: Some(0),
            limit: None,
            timeout: Some(600),
            allowed_updates: None,
        };

        'update_loop: loop {
            let updates = bot.get_updates(&update_args).unwrap();

            for update in updates {
                update_args.offset = Some(update.update_id + 1);
                println!("{:?}", update_args.offset);

                if let Some(message) = update.message {
                    let from = message.from.unwrap();
                    let text = format!("Hi {} [{}]!", from.first_name,
                                                      from.id);

                    let mut msg_args = args::SendMessage {
                        chat_id: None,
                        chat_username: None,
                        text: "",
                        parse_mode: Some("Markdown"),
                        disable_web_page_preview: None,
                        disable_notification: None,
                        reply_to_message_id: None,
                        reply_markup: None,
                    };

                    msg_args.text = &text;
                    msg_args.chat_id = Some(message.chat.id);
                    msg_args.reply_to_message_id = Some(message.message_id);

                    bot.send_message(&msg_args);

                    if let Some(text) = message.text {
                        if text == "/exit" {
                            break 'update_loop;
                        }
                    }
                }
            }
        }
        bot.get_updates(&update_args);
        // Alright, so if you ever decide to have a function that terminates
        // your bot, make sure you have a check at the beginning of the loop
        // that makes sure you aren't processing old messages. You could also
        // just make a getUpdates at the end of the execution that just uses
        // the latest offset. This prevents you from having to reread any
        // updates that were in the update array you got that had the terminate
        // command. Because telegram only will stop sending you the update
        // after you have used an offset greater than its. So if you never make
        // another getUpdates, you will boot up, and terminate, forever. :)
    }
}
<commit_msg>Final fix for value to multi<commit_after>extern crate hyper;
extern crate multipart;
extern crate serde_json;

use hyper::net::Streaming;
use hyper::method::Method;
use hyper::client::Request;

use hyper::client::RequestBuilder;
use hyper::Client;
use hyper::Url;

use multipart::client::Multipart;

use serde_json::value::Value;

use std::result::Result;
use std::sync::Arc;
use std::io::Read;
use std::{fmt, error};

pub mod types {
    extern crate serde_json;
    use serde_json::value::Value;

    include!(concat!(env!("OUT_DIR"), "/types.rs"));
}

pub mod args;
pub mod builders;

use types::*;

// TODO: Organize this mess and get rid of most unwraps

#[derive(Debug)]
pub enum BotError {
    Http (hyper::error::Error),
    Api {
        error_code: i64,
        description: String,
        parameters: Option<ResponseParameters>
    }
}

impl fmt::Display for BotError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &BotError::Http(ref e) => {
                write!(f, "{}", e)
            },
            &BotError::Api { error_code, ref description, parameters: _ } => {
                write!(f, "Error {0}: {1}", error_code, description)
            }
        }
    }
}

impl error::Error for BotError {
    fn description(&self) -> &str {
        "Something unexpected occured while talking to the telegram bot api." // meh
    }
}

fn parse_request(response: Result<hyper::client::Response, hyper::Error>) -> Result<Value, BotError> {
    match response {
        Ok(mut res) => {
            let mut body = String::new();
            res.read_to_string(&mut body).unwrap();
            let got_me: ApiResult = serde_json::from_str(&body).unwrap();
            if let Some(val) = got_me.result {
                Ok(val)
            } else {
                Err(BotError::Api{
                    error_code: got_me.error_code.unwrap(),
                    description: got_me.description.unwrap(),
                    parameters: got_me.parameters
                })
            }
        },
        Err(e) => {
            Err(BotError::Http(e))
        }
    }
}

#[derive(Debug)]
pub struct BotApi {
    base_url: Url,
    client: Client,
}

impl Clone for BotApi {
    fn clone(&self) -> BotApi {
        BotApi {
            base_url: self.base_url.clone(),
            client: Client::new(),
        }
    }
}

impl BotApi {
    pub fn new(bot_token: &str) -> BotApi {
        let url = format!("https://api.telegram.org/bot{}/", bot_token);

        BotApi {
            base_url: url.parse().unwrap(),
            client: Client::new(),
        }
    }

    pub fn get_me(&self) -> Result<User, BotError> {
        let url = self.base_url.join("getMe").unwrap();
        let res = parse_request(self.client.get(url).send());
        match res {
            Ok(val) => Ok(serde_json::value::from_value(val).unwrap()),
            Err(e) => Err(e),
        }
    }

    pub fn get_updates(&self, params: &args::GetUpdates) -> Result<Vec<Update>, BotError> {
        let url = self.base_url.join("getUpdates").unwrap();

        // All these unwraps make me uncomfortable, someone is going to yell
        // at me to get some good error handling. And they would be right
        // but I'm really lazy and I don't want to deal with this. I should
        // though because it's good practice and no real software should ever
        // just throw errors around like they don't matter.

        // Manage your errors

        let req = Request::new(Method::Post, url).unwrap();

        let mut multi = Multipart::from_request(req).unwrap();

        if let Some(offset) = params.offset {
            multi.write_text("offset", offset.to_string()).unwrap();
        }

        if let Some(limit) = params.limit {
            multi.write_text("limit", limit.to_string()).unwrap();
        }

        if let Some(timeout) = params.timeout {
            multi.write_text("timeout", timeout.to_string()).unwrap();
        }

        if let Some(allowed_updates) = params.allowed_updates {
            value_to_multi(&mut multi, "allowed_updates", serde_json::to_value(allowed_updates));
        }

        match parse_request(multi.send()) {
            Ok(val) => Ok(serde_json::value::from_value(val).unwrap()),
            Err(e) => Err(e),
        }
    }

    pub fn send_message(&self, params: &args::SendMessage) -> Result<Message, BotError> {
        let url = self.base_url.join("sendMessage").unwrap();
        let req = Request::new(Method::Post, url).unwrap();
        let mut multi = Multipart::from_request(req).unwrap();

        if let Some(chat_id) = params.chat_id {
            multi.write_text("chat_id", chat_id.to_string()).unwrap();
        } else
        if let Some(chat_username) = params.chat_username {
            multi.write_text("chat_id", chat_username).unwrap();
        }

        multi.write_text("text", params.text).unwrap();

        if let Some(parse_mode) = params.parse_mode {
            multi.write_text("parse_mode", parse_mode).unwrap();
        }

        if let Some(disable_web_page_preview) = params.disable_web_page_preview {
            multi.write_text("disable_web_page_preview", disable_web_page_preview.to_string()).unwrap();
        }

        if let Some(disable_notification) = params.disable_notification {
            multi.write_text("disable_notification", disable_notification.to_string()).unwrap();
        }

        if let Some(reply_to_message_id) = params.reply_to_message_id {
            multi.write_text("reply_to_message_id", reply_to_message_id.to_string()).unwrap();
        }

        if let Some(reply_markup) = params.reply_markup {
            value_to_multi(&mut multi, "reply_markup", serde_json::to_value(reply_markup));
        }

        match parse_request(multi.send()) {
            Ok(val) => Ok(serde_json::value::from_value(val).unwrap()),
            Err(e) => Err(e),
        }
    }
} // 2: TODO don't use multipart when you don't have to

fn value_to_multi(multi: &mut Multipart<Request<hyper::net::Streaming>>, key: &str, val: Value) {
    match val {
        Value::Null => {
            multi.write_text(key, "null").unwrap();
        }
        Value::Bool(b) => {
            multi.write_text(key, b.to_string()).unwrap();
        }
        Value::I64(i) => {
            multi.write_text(key, i.to_string()).unwrap();
        }
        Value::U64(u) => {
            multi.write_text(key, u.to_string()).unwrap();
        }
        Value::F64(f) => {
            multi.write_text(key, f.to_string()).unwrap();
        }
        Value::String(s) => {
            multi.write_text(key, s.to_string()).unwrap();
        }
        Value::Array(a) => {
            let mut new_key = String::from(key);
            new_key.push_str("[[]]");

            let mut index = 0;
            for item in a {
                let final_key = match item {
                    Value::Array(_) | Value::Object(_) => {
                        new_key.replace("[]", &index.to_string())
                    }
                    _ => {
                        new_key.replace("[]", "")
                    }
                };

                value_to_multi(multi, &final_key, item);
                index += 1;
            }
        }
        Value::Object(map) => {
            let mut new_key = String::from(key);
            new_key.push_str("[{}]");

            for (map_key, map_value) in map {
                value_to_multi(multi, &new_key.replace("{}", &map_key), map_value);
            }
        }
    }
}

#[cfg(test)]
mod tests { // These aren't going to be the actual tests, just a place for me to easily test things as I go along
    use super::*;
    extern crate serde_json;
    #[test]
    fn it_works() {
        let token = "";
        let bot = BotApi::new(token);

        let mut update_args = args::GetUpdates {
            offset: Some(0),
            limit: None,
            timeout: Some(600),
            allowed_updates: None,
        };

        'update_loop: loop {
            let updates = bot.get_updates(&update_args).unwrap();

            for update in updates {
                update_args.offset = Some(update.update_id + 1);
                println!("{:?}", update_args.offset);

                if let Some(message) = update.message {
                    let from = message.from.unwrap();
                    let text = format!("Hi {} [{}]!", from.first_name,
                                                      from.id);

                    let mut msg_args = args::SendMessage {
                        chat_id: None,
                        chat_username: None,
                        text: "",
                        parse_mode: Some("Markdown"),
                        disable_web_page_preview: None,
                        disable_notification: None,
                        reply_to_message_id: None,
                        reply_markup: None,
                    };

                    msg_args.text = &text;
                    msg_args.chat_id = Some(message.chat.id);
                    msg_args.reply_to_message_id = Some(message.message_id);

                    bot.send_message(&msg_args);

                    if let Some(text) = message.text {
                        if text == "/exit" {
                            break 'update_loop;
                        }
                    }
                }
            }
        }
        bot.get_updates(&update_args);
        // Alright, so if you ever decide to have a function that terminates
        // your bot, make sure you have a check at the beginning of the loop
        // that makes sure you aren't processing old messages. You could also
        // just make a getUpdates at the end of the execution that just uses
        // the latest offset. This prevents you from having to reread any
        // updates that were in the update array you got that had the terminate
        // command. Because telegram only will stop sending you the update
        // after you have used an offset greater than its. So if you never make
        // another getUpdates, you will boot up, and terminate, forever. :)
    }
}
<|endoftext|>


<commit_before>//
// bitwise_nif : examples of NIF scheduling
//
// This is a Rust port of Steve Vinoski's bitwise, NIF examples
// showing Erlang scheduler concerns. The original C program
// can be found at: https://github.com/vinoski/bitwise
//

#[macro_use]
extern crate ruster_unsafe;
use ruster_unsafe::*;

use std::mem::uninitialized;
use std::slice;

extern crate libc;
use libc::c_uint;

/// (module doc)
/// The exor functions here take a binary and a byte and generate a new
/// binary by applying xor of the byte value to each byte of the binary.
/// It returns a tuple of the new binary and a count of how many times
/// the Erlang scheduler thread is yielded during processing of the binary.

/// Create NIF module data and init function.
/// Note that exor, exor_bad, and exor_dirty all run the same Rust function,
/// but exor and exor_bad run it on a regular scheduler thread whereas
/// exor_dirty runs it on a dirty CPU scheduler thread.

// Erlang: Set the NIF name to b"bitwise\0"
// Elixir: Set the NIF name to b"Elixir.BitwiseNif\0"
nif_init!(b"bitwise\0", Some(load), Some(reload), Some(upgrade), Some(unload),
          nif!(b"exor\0",       2, exor),
          nif!(b"exor_bad\0",   2, exor),
          // nif!(b"exor_yield\0", 2, exor_yield),
          nif!(b"exor_dirty\0", 2, exor, ERL_NIF_DIRTY_JOB_CPU_BOUND)
          );

/// Does nothing, reports success
extern "C" fn load(_env: *mut ErlNifEnv,
                   _priv_data: *mut *mut c_void,
                   _load_info: ERL_NIF_TERM)-> c_int { 0 }

/// Does nothing, reports success
extern "C" fn reload(_env: *mut ErlNifEnv,
                     _priv_data: *mut *mut c_void,
                     _load_info: ERL_NIF_TERM) -> c_int { 0 }

/// Does nothing, reports success
extern "C" fn upgrade(_env: *mut ErlNifEnv,
                      _priv_data: *mut *mut c_void,
                      _old_priv_data: *mut *mut c_void,
                      _load_info: ERL_NIF_TERM) -> c_int { 0 }

/// Does nothing, reports success
extern "C" fn unload(_env: *mut ErlNifEnv,
                     _priv_data: *mut c_void) {}

/// Erlang: -spec exor(binary(), byte::0..255) -> binary().
///
/// exor misbehaves on a regular scheduler thread when the incomng binary is
/// large because it blocks the thread for too long. But it works fine on a
/// dirty scheduler.
extern "C" fn exor(env: *mut ErlNifEnv,
                   argc: c_int,
                   args: *const ERL_NIF_TERM) -> ERL_NIF_TERM {
    let mut in_bin: ErlNifBinary  = unsafe { uninitialized() };
    let mut out_bin: ErlNifBinary = unsafe { uninitialized() };
    let mut byte: c_uint          = unsafe { uninitialized() };

    if argc != 2
        || 0 == unsafe { enif_inspect_binary(env, *args, &mut in_bin) }
        || 0 == unsafe { enif_get_uint(env, *args.offset(1), &mut byte) }
        || byte > 255 {
        return unsafe { enif_make_badarg(env) };
    }
    if in_bin.size == 0 {
        return unsafe { *args };
    }

    unsafe { enif_alloc_binary(in_bin.size, &mut out_bin) };

    let in_bin_slice  = unsafe { slice::from_raw_parts(in_bin.data, in_bin.size) };
    let out_bin_slice = unsafe { slice::from_raw_parts_mut(out_bin.data, in_bin.size) };

    apply_xor(in_bin_slice, out_bin_slice, byte as u8);

    // @TODO: Implement enif_make_tuple2() and friends in ruster_unsafe
    // unsafe { enif_make_tuple2(env,
    //                           enif_make_binary(env, &mut outbin),
    //                           enif_make_int(env, 0)) }
    unsafe { enif_make_binary(env, &mut out_bin) }
}

fn apply_xor(source: &[u8], target: &mut[u8], byte: u8) {
    for (src_b, tgt_b) in source.iter().zip(target.iter_mut()) {
        (*tgt_b) = (*src_b) ^ byte;
    }
}

// C lang
//
// / exor_yield just schedules exor2 for execution, providing an initial
// / guess of 4MB for the max number of bytes to process before yielding the
// / scheduler thread
// static ERL_NIF_TERM
// exor_yield(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
// {
//     ErlNifResourceType* res_type = (ErlNifResourceType*)enif_priv_data(env);
//     ERL_NIF_TERM newargv[6];
//     ErlNifBinary bin;
//     unsigned val;
//     void* res;
//
//     if (argc != 2 || !enif_inspect_binary(env, argv[0], &bin) ||
//         !enif_get_uint(env, argv[1], &val) || val > 255)
//         return enif_make_badarg(env);
//     if (bin.size == 0)
//         return argv[0];
//     newargv[0] = argv[0];
//     newargv[1] = argv[1];
//     newargv[2] = enif_make_ulong(env, 4194304);
//     newargv[3] = enif_make_ulong(env, 0);
//     res = enif_alloc_resource(res_type, bin.size);
//     newargv[4] = enif_make_resource(env, res);
//     newargv[5] = enif_make_int(env, 0);
//     enif_release_resource(res);
//     return enif_schedule_nif(env, "exor2", 0, exor2, 6, newargv);
// }

// C lang
//
// / exor2 is an "internal NIF" scheduled by exor_yield above. It takes the
// / binary and byte arguments, same as the other functions here, but also
// / takes a count of the max number of bytes to process per timeslice, the
// / offset into the binary at which to start processing, the resource type
// / holding the resulting data, and the number of times rescheduling is done
// / via enif_schedule_nif.
// static ERL_NIF_TERM
// exor2(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
// {
//     ErlNifResourceType* res_type = (ErlNifResourceType*)enif_priv_data(env);
//     unsigned long offset, i, end, max_per_slice;
//     struct timeval start, stop, slice;
//     int pct, total = 0, yields;
//     ERL_NIF_TERM newargv[6];
//     ERL_NIF_TERM result;
//     unsigned char byte;
//     ErlNifBinary bin;
//     unsigned val;
//     void* res;
//
//     if (argc != 6 || !enif_inspect_binary(env, argv[0], &bin) ||
//         !enif_get_uint(env, argv[1], &val) || val > 255 ||
//         !enif_get_ulong(env, argv[2], &max_per_slice) ||
//         !enif_get_ulong(env, argv[3], &offset) ||
//         !enif_get_resource(env, argv[4], res_type, &res) ||
//         !enif_get_int(env, argv[5], &yields))
//         return enif_make_badarg(env);
//     byte = (unsigned char)val;
//     end = offset + max_per_slice;
//     if (end > bin.size) end = bin.size;
//     i = offset;
//     while (i < bin.size) {
//         gettimeofday(&start, NULL);
//         do {
//             ((char*)res)[i] = bin.data[i] ^ byte;
//         } while (++i < end);
//         if (i == bin.size) break;
//         gettimeofday(&stop, NULL);
//         /* determine how much of the timeslice was used */
//         timersub(&stop, &start, &slice);
//         pct = (int)((slice.tv_sec*1000000+slice.tv_usec)/10);
//         total += pct;
//         if (pct > 100) pct = 100;
//         else if (pct == 0) pct = 1;
//         if (enif_consume_timeslice(env, pct)) {
//             /* the timeslice has been used up, so adjust our max_per_slice byte count based on
//              * the processing we've done, then reschedule to run again */
//             max_per_slice = i - offset;
//             if (total > 100) {
//                 int m = (int)(total/100);
//                 if (m == 1)
//                     max_per_slice -= (unsigned long)(max_per_slice*(total-100)/100);
//                 else
//                     max_per_slice = (unsigned long)(max_per_slice/m);
//             }
//             newargv[0] = argv[0];
//             newargv[1] = argv[1];
//             newargv[2] = enif_make_ulong(env, max_per_slice);
//             newargv[3] = enif_make_ulong(env, i);
//             newargv[4] = argv[4];
//             newargv[5] = enif_make_int(env, yields+1);
//             return enif_schedule_nif(env, "exor2", 0, exor2, argc, newargv);
//         }
//         end += max_per_slice;
//         if (end > bin.size) end = bin.size;
//     }
//     result = enif_make_resource_binary(env, res, res, bin.size);
//     return enif_make_tuple2(env, result, enif_make_int(env, yields));
// }
<commit_msg>Implementing exor_yield() and exor2() (in-progress)<commit_after>//
// bitwise_nif : examples of NIF scheduling
//
// This is a Rust port of Steve Vinoski's bitwise, NIF examples
// showing Erlang scheduler concerns. The original C program
// can be found at: https://github.com/vinoski/bitwise
//

#[macro_use]
extern crate ruster_unsafe;
use ruster_unsafe::*;

use std::mem::uninitialized;
use std::slice;

extern crate libc;
use libc::c_uchar;
use libc::c_uint;
use libc::c_ulong;

// @TODO: This need to be a module doc.
// (see https://doc.rust-lang.org/book/documentation.html#documenting-modules)
//
// The exor functions here take a binary and a byte and generate a new
// binary by applying xor of the byte value to each byte of the binary.
// It returns a tuple of the new binary and a count of how many times
// the Erlang scheduler thread is yielded during processing of the binary.
//
// Create NIF module data and init function.
// Note that exor, exor_bad, and exor_dirty all run the same Rust function,
// but exor and exor_bad run it on a regular scheduler thread whereas
// exor_dirty runs it on a dirty CPU scheduler thread.

// Erlang: Set the NIF name to b"bitwise\0"
// Elixir: Set the NIF name to b"Elixir.BitwiseNif\0"
nif_init!(b"Elixir.BitwiseNif\0",
          Some(load),    // on-load
          None,          // on-reload
          Some(upgrade), // on-upgrade
          None,          // on-unload
          nif!(b"exor\0",       2, exor),
          nif!(b"exor_bad\0",   2, exor),
          nif!(b"exor_yield\0", 2, exor_yield),
          nif!(b"exor_dirty\0", 2, exor, ERL_NIF_DIRTY_JOB_CPU_BOUND)
          );

const DEFAULT_MAX_BYTES_PER_SLICE: c_ulong = 4 * 1024 * 1024;
const TIMESLICE_EXHAUSTED: c_int = 1;

extern "C" fn load(_env: *mut ErlNifEnv,
                   _priv_data: *mut *mut c_void,
                   _load_info: ERL_NIF_TERM)-> c_int {
    0
}

extern "C" fn upgrade(_env: *mut ErlNifEnv,
                      _priv_data: *mut *mut c_void,
                      _old_priv_data: *mut *mut c_void,
                      _load_info: ERL_NIF_TERM)-> c_int {
    0
}

/// Erlang: -spec exor(binary(), byte::0..255) -> binary().
///
/// exor misbehaves on a regular scheduler thread when the incomng binary is
/// large because it blocks the thread for too long. But it works fine on a
/// dirty scheduler.
extern "C" fn exor(env: *mut ErlNifEnv,
                   argc: c_int,
                   args: *const ERL_NIF_TERM) -> ERL_NIF_TERM {
    let mut in_bin:  ErlNifBinary = unsafe { uninitialized() };
    let mut out_bin: ErlNifBinary = unsafe { uninitialized() };
    let mut byte: c_uint          = unsafe { uninitialized() };

    if argc != 2
        || 0 == unsafe { enif_inspect_binary(env, *args, &mut in_bin) }
        || 0 == unsafe { enif_get_uint(env, *args.offset(1), &mut byte) }
        || byte > 255 {
        return unsafe { enif_make_badarg(env) };
    }
    if in_bin.size == 0 {
        return unsafe { *args };
    }

    unsafe { enif_alloc_binary(in_bin.size, &mut out_bin) };

    let in_bin_slice  = unsafe { slice::from_raw_parts(in_bin.data, in_bin.size) };
    let out_bin_slice = unsafe { slice::from_raw_parts_mut(out_bin.data, in_bin.size) };

    apply_xor(in_bin_slice, out_bin_slice, byte as u8);

    let yields = 0;
    unsafe {make_tuple2(env,
                        &enif_make_binary(env, &mut out_bin),
                        &enif_make_int(env, yields)) }
}

/// Erlang: -spec exor_yield(binary(), byte::0..255) -> binary().
///
/// exor_yield just schedules exor2 for execution, providing an
/// initial guess of 4MB for the max number of bytes to process before
/// yielding the scheduler thread.
extern "C" fn exor_yield(env: *mut ErlNifEnv,
                         argc: c_int,
                         args: *const ERL_NIF_TERM) -> ERL_NIF_TERM {
    let mut in_bin: ErlNifBinary = unsafe { uninitialized() };
    let mut byte: c_uint = unsafe { uninitialized() };

    if argc != 2
        || 0 == unsafe { enif_inspect_binary(env, *args, &mut in_bin) }
        || 0 == unsafe { enif_get_uint(env, *args.offset(1), &mut byte) }
        || byte > 255 {
        return unsafe { enif_make_badarg(env) };
    }

    if in_bin.size == 0 {
        return unsafe { *args };
    }

    let res_type: *mut ErlNifResourceType =
        unsafe { enif_priv_data(env) } as *mut ErlNifResourceType;
    let res: *mut c_void = unsafe { enif_alloc_resource(res_type, in_bin.size) };

    let new_args = unsafe {
        [*args.offset(0),
         *args.offset(1),
         enif_make_ulong(env, DEFAULT_MAX_BYTES_PER_SLICE),
         enif_make_ulong(env, 0),
         enif_make_resource(env, res),
         enif_make_int(env, 0)]
    };

    unsafe { enif_release_resource(res) };
    unsafe { enif_schedule_nif(env, b"exor2\0" as *const u8, 0,
                               Some(exor2), 6, new_args.as_ptr()) }
}

/// exor2 is an "internal NIF" scheduled by exor_yield above. It takes
/// the binary and byte arguments, same as the other functions here,
/// but also takes a count of the max number of bytes to process per
/// timeslice, the offset into the binary at which to start
/// processing, the resource type holding the resulting data, and the
/// number of times rescheduling is done via enif_schedule_nif.
extern "C" fn exor2(env: *mut ErlNifEnv,
                    argc: c_int,
                    args: *const ERL_NIF_TERM) -> ERL_NIF_TERM {
    let res_type: *mut ErlNifResourceType =
        unsafe { enif_priv_data(env) } as *mut ErlNifResourceType;

    let mut in_bin: ErlNifBinary          = unsafe { uninitialized() };
    let mut val: c_uint                   = unsafe { uninitialized() };
    let mut max_bytes_per_slice: c_ulong  = unsafe { uninitialized() };
    let mut start_offset: c_ulong         = unsafe { uninitialized() };
    let mut res: *mut c_void              = unsafe { uninitialized() };
    let mut yields: c_int                 = unsafe { uninitialized() };

    if argc != 6
        || 0 == unsafe { enif_inspect_binary(env, *args, &mut in_bin) }
        || 0 == unsafe { enif_get_uint(env, *args.offset(1), &mut val) }
        || val > 255
        || 0 == unsafe { enif_get_ulong(env, *args.offset(2), &mut max_bytes_per_slice) }
        || 0 == unsafe { enif_get_ulong(env, *args.offset(3), &mut start_offset) }
        || 0 == unsafe { enif_get_resource(env, *args.offset(4), res_type, &mut res) }
        || 0 == unsafe { enif_get_int(env, *args.offset(5), &mut yields) } {
        return unsafe { enif_make_badarg(env) };
    }

    let byte = val as c_uchar;

    let mut pos = start_offset as usize;
    let mut end_offset = (start_offset + max_bytes_per_slice) as usize;
    if end_offset > in_bin.size {
        end_offset = in_bin.size;
    }
    let mut consumed_timeslice: c_int = 0;

    loop {
        // gettimeofday(&start, NULL);

        let in_bin_slice = unsafe {
            slice::from_raw_parts(in_bin.data.offset(pos as isize),
                                  end_offset - pos + 1)
        };
        let res_bin_slice = unsafe {
            slice::from_raw_parts_mut(res.offset(pos as isize) as *mut u8,
                                      end_offset - pos + 1)
        };

        apply_xor(in_bin_slice, res_bin_slice, byte as u8);

        pos = end_offset;
        if pos == in_bin.size {
            // We are done. Break out from the loop and return the result.
            break;
        }

        // gettimeofday(&stop, NULL);
        // determine how much of the timeslice was used
        // timersub(&stop, &start, &slice);
        // let percent: c_int = (slice.tv_sec*1000000+slice.tv_usec)/10) as c_int;
        let percent: c_int = 100;  // @TODO: Replace with above.
        consumed_timeslice += percent;

        let resp = unsafe { enif_consume_timeslice(env, fix_range(percent)) };
        if resp == TIMESLICE_EXHAUSTED {
            // the timeslice has been used up, so adjust our max_bytes_per_slice byte
            // count based on the processing we've done, then reschedule to run
            // again.
            let max_bytes_per_slice =
                adjust_slice_size((pos as c_ulong) - start_offset,
                                  consumed_timeslice as c_ulong);
            let new_args = unsafe {
                [*args.offset(0),
                 *args.offset(1),
                 enif_make_ulong(env, max_bytes_per_slice),
                 enif_make_ulong(env, pos as c_ulong),
                 *args.offset(4),
                 enif_make_int(env, yields + 1)]
            };
            return unsafe { enif_schedule_nif(env, b"exor2\0" as *const u8, 0,
                                              Some(exor2), argc, new_args.as_ptr()) };
        }
        end_offset += max_bytes_per_slice as usize;
        if end_offset > in_bin.size {
            end_offset = in_bin.size;
        }
    }

    // We are done. Return the result.
    let out_bin = unsafe { enif_make_resource_binary(env, res, res, in_bin.size) };
    unsafe { make_tuple2(env, &out_bin, &enif_make_int(env, yields)) }
}

fn apply_xor(source: &[u8], target: &mut[u8], byte: u8) {
    for (src_b, tgt_b) in source.iter().zip(target.iter_mut()) {
        (*tgt_b) = (*src_b) ^ byte;
    }
}

fn fix_range(percent: c_int) -> c_int {
    // enif_consume_timeslice only accepts percent between 1 and 100.
    if percent <= 0 {
        1
    } else if percent > 100 {
        100
    } else {
        percent
    }
}

fn adjust_slice_size(bytes_processed: c_ulong,
                     consumed_timeslice: c_ulong) -> c_ulong {
    if consumed_timeslice <= 100 {
        bytes_processed
    } else {
        let m = consumed_timeslice / 100;
        if m == 1 {
            bytes_processed - (bytes_processed * (consumed_timeslice - 100) / 100)
        } else {
           bytes_processed / m
        }
    }
}

fn make_tuple2(env: *mut ErlNifEnv,
               e1: *const ERL_NIF_TERM, e2: *const ERL_NIF_TERM) -> ERL_NIF_TERM {
    let tuple_elements = unsafe { [*e1, *e2] };
    unsafe { enif_make_tuple_from_array(env, tuple_elements.as_ptr(), 2) }
}
<|endoftext|>


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

#![crate_name = "js"]
#![crate_type = "rlib"]

#![feature(core_intrinsics)]
#![feature(link_args)]
#![feature(str_utf16)]
#![feature(unsafe_no_drop_flag)]
#![feature(const_fn)]

#![allow(non_upper_case_globals, non_camel_case_types, non_snake_case, improper_ctypes, raw_pointer_derive)]

#[macro_use]
extern crate heapsize;
extern crate libc;
#[macro_use]
extern crate log;
extern crate mozjs_sys;
extern crate num;
extern crate rustc_serialize as serialize;

#[cfg(target_os = "linux")]
#[cfg(target_pointer_width = "64")]
mod jsapi_linux_64;

#[cfg(target_os = "macos")]
#[cfg(target_pointer_width = "64")]
mod jsapi_macos_64;

#[cfg(target_os = "windows")]
#[cfg(target_pointer_width = "64")]
mod jsapi_windows_gcc_64;

#[cfg(not(target_os = "windows"))]
#[cfg(target_pointer_width = "32")]
mod jsapi_linux_32;

pub mod jsapi {
    #[cfg(target_os = "linux")]
    #[cfg(target_pointer_width = "64")]
    pub use jsapi_linux_64::*;

    #[cfg(target_os = "macos")]
    #[cfg(target_pointer_width = "64")]
    pub use jsapi_macos_64::*;

    #[cfg(target_os = "windows")]
    #[cfg(target_pointer_width = "64")]
    pub use jsapi_windows_gcc_64::*;

    #[cfg(not(target_os = "windows"))]
    #[cfg(target_pointer_width = "32")]
    pub use jsapi_linux_32::*;
}

mod consts;
pub mod conversions;
pub mod error;
pub mod glue;
pub mod jsval;
pub mod rust;

#[cfg(test)]
mod tests;

pub use consts::*;

use heapsize::HeapSizeOf;
use jsapi::{JSContext, Heap};
use jsval::JSVal;
use rust::GCMethods;

#[inline(always)]
pub unsafe fn JS_ARGV(_cx: *mut JSContext, vp: *mut JSVal) -> *mut JSVal {
    vp.offset(2)
}

#[inline(always)]
pub unsafe fn JS_CALLEE(_cx: *mut JSContext, vp: *mut JSVal) -> JSVal {
    *vp
}

// This is measured properly by the heap measurement implemented in SpiderMonkey.
impl<T: Copy + GCMethods<T>> HeapSizeOf for Heap<T> {
    fn heap_size_of_children(&self) -> usize {
        0
    }
}
known_heap_size!(0, JSVal);

<commit_msg>Auto merge of #243 - KiChjang:silence-warning, r=Wafflespeanut<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

#![crate_name = "js"]
#![crate_type = "rlib"]

#![feature(core_intrinsics)]
#![feature(link_args)]
#![feature(str_utf16)]
#![feature(unsafe_no_drop_flag)]
#![feature(const_fn)]

#![allow(non_upper_case_globals, non_camel_case_types, non_snake_case, improper_ctypes)]

#[macro_use]
extern crate heapsize;
extern crate libc;
#[macro_use]
extern crate log;
extern crate mozjs_sys;
extern crate num;
extern crate rustc_serialize as serialize;

#[cfg(target_os = "linux")]
#[cfg(target_pointer_width = "64")]
mod jsapi_linux_64;

#[cfg(target_os = "macos")]
#[cfg(target_pointer_width = "64")]
mod jsapi_macos_64;

#[cfg(target_os = "windows")]
#[cfg(target_pointer_width = "64")]
mod jsapi_windows_gcc_64;

#[cfg(not(target_os = "windows"))]
#[cfg(target_pointer_width = "32")]
mod jsapi_linux_32;

pub mod jsapi {
    #[cfg(target_os = "linux")]
    #[cfg(target_pointer_width = "64")]
    pub use jsapi_linux_64::*;

    #[cfg(target_os = "macos")]
    #[cfg(target_pointer_width = "64")]
    pub use jsapi_macos_64::*;

    #[cfg(target_os = "windows")]
    #[cfg(target_pointer_width = "64")]
    pub use jsapi_windows_gcc_64::*;

    #[cfg(not(target_os = "windows"))]
    #[cfg(target_pointer_width = "32")]
    pub use jsapi_linux_32::*;
}

mod consts;
pub mod conversions;
pub mod error;
pub mod glue;
pub mod jsval;
pub mod rust;

#[cfg(test)]
mod tests;

pub use consts::*;

use heapsize::HeapSizeOf;
use jsapi::{JSContext, Heap};
use jsval::JSVal;
use rust::GCMethods;

#[inline(always)]
pub unsafe fn JS_ARGV(_cx: *mut JSContext, vp: *mut JSVal) -> *mut JSVal {
    vp.offset(2)
}

#[inline(always)]
pub unsafe fn JS_CALLEE(_cx: *mut JSContext, vp: *mut JSVal) -> JSVal {
    *vp
}

// This is measured properly by the heap measurement implemented in SpiderMonkey.
impl<T: Copy + GCMethods<T>> HeapSizeOf for Heap<T> {
    fn heap_size_of_children(&self) -> usize {
        0
    }
}
known_heap_size!(0, JSVal);

<|endoftext|>


<commit_before>/*
 * diosix microkernel 'menchi'
 *
 * Glue for portable Rust kernel code
 *
 * Maintainer: Chris Williams (diosix.org)
 *
 */

#![feature(no_std, lang_items, core_str_ext, const_fn, asm)]
#![no_std]

/* bring in the kernel debugging features, provides kprintln! and kprint! */
#[macro_use]
mod debug;

mod errors;

/* bare-metal libc, needed to provide various runtime
 * things like memcpy - see: https://crates.io/crates/rlibc */
extern crate rlibc;

/* bare-metal atomic operations because we can't use the std lib.
 * see: https://crates.io/crates/spin */
extern crate spin;

/* select appropriate platform-specific routines from build target's arch */
#[cfg(target_arch = "x86_64")]
#[path = "../platform/x86/src/mod.rs"] pub mod hardware;

/* entry point for our kernel */
#[no_mangle]
pub extern fn kmain()
{
    /* display boot banner */
    kprintln!("diosix {} 'menchi' now running", env!("CARGO_PKG_VERSION"));

    /* initialize interrupts so we can catch exceptions at this early stage */
    hardware::interrupts::init().ok().expect("failed during interrupt init");
}

/* handle panics by writing to the debug log and bailing out */
#[lang = "panic_fmt"]
extern fn panic_fmt(args: ::core::fmt::Arguments, file: &'static str, line: usize) -> !
{
    kprintln!("==> PANIC! {:?} in {}:{}", args, file, line);
    kprintln!("Halting.");
    loop{} /* end of the road */
}

#[lang = "eh_personality"] extern fn eh_personality() {} /* defined internally for panic()s but not needed */
#[lang="stack_exhausted"] extern fn stack_exhausted() {}
<commit_msg>tidied formatting<commit_after>/*
 * diosix microkernel 'menchi'
 *
 * Glue for portable Rust kernel code
 *
 * Maintainer: Chris Williams (diosix.org)
 *
 */

#![feature(no_std, lang_items, core_str_ext, const_fn, asm)]
#![no_std]

/* bring in the kernel debugging features, provides kprintln! and kprint! */
#[macro_use]
mod debug;

mod errors;

/* bare-metal libc, needed to provide various runtime
 * things like memcpy - see: https://crates.io/crates/rlibc */
extern crate rlibc;

/* bare-metal atomic operations because we can't use the std lib.
 * see: https://crates.io/crates/spin */
extern crate spin;

/* select appropriate platform-specific routines from build target's arch */
#[cfg(target_arch = "x86_64")]
#[path = "../platform/x86/src/mod.rs"] pub mod hardware;

/* entry point for our kernel */
#[no_mangle]
pub extern fn kmain()
{
    /* display boot banner */
    kprintln!("diosix {} 'menchi' now running", env!("CARGO_PKG_VERSION"));

    /* initialize interrupts so we can catch exceptions at this early stage */
    hardware::interrupts::init().ok().expect("failed during interrupt init");
}

/* handle panics by writing to the debug log and bailing out */
#[lang = "panic_fmt"]
extern fn panic_fmt(args: ::core::fmt::Arguments, file: &'static str, line: usize) -> !
{
    kprintln!("==> PANIC! {:?} in {}:{}", args, file, line);
    kprintln!("Halting.");
    loop{} /* end of the road */
}

#[lang = "eh_personality"] extern fn eh_personality() {} /* defined internally for panic()s but not needed */
#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
<|endoftext|>


<commit_before>#![crate_name = "amethyst"]
#![crate_type = "lib"]

//! Amethyst is a free and open source SDK (software development kit) written in
//! idiomatic [Rust](https://www.rust-lang.org/) for building video games and
//! interactive multimedia applications.
//!
//! This project is a work in progress and is very incomplete. Pardon the dust!
//!
//! # Example
//!
//! ```ignore
//! extern crate amethyst;
//!
//! use amethyst::*;
//!
//! struct GameState;
//!
//! impl State for GameState {
//!     fn handle_events(&mut self, events: &Vec<Event>) -> Trans {
//!         for e in events {
//!             match e {
//!                 Event::Closed => Trans::Quit,
//!                 Event::Resized(x, y) => println!("x: {}, y: {}", x, y),
//!                 Event::KeyPressed(k) => if k == Key::Esc { Trans::Quit },
//!             }
//!         }
//!
//!         Trans::None
//!     }
//!
//!     fn update(&mut self, delta: Duration) -> Trans {
//!         println!("Computing some more whoop-ass...");
//!         Trans::None
//!     }
//! }
//!
//! fn main() {
//!     let mut game = Application::new(GameState);
//!     game.run();
//! }
//! ```

mod engine;
pub mod renderer;

pub use self::engine::app::Application;
pub use self::engine::state::{State, StateMachine, Trans};
pub use self::engine::timing::{Duration, Stopwatch};
<commit_msg>eliminate unused var warning for lib.rs doc comment<commit_after>#![crate_name = "amethyst"]
#![crate_type = "lib"]

//! Amethyst is a free and open source SDK (software development kit) written in
//! idiomatic [Rust](https://www.rust-lang.org/) for building video games and
//! interactive multimedia applications.
//!
//! This project is a work in progress and is very incomplete. Pardon the dust!
//!
//! # Example
//!
//! ```ignore
//! extern crate amethyst;
//!
//! use amethyst::*;
//!
//! struct GameState;
//!
//! impl State for GameState {
//!     fn handle_events(&mut self, events: &Vec<Event>) -> Trans {
//!         for e in events {
//!             match e {
//!                 Event::Closed => Trans::Quit,
//!                 Event::Resized(x, y) => println!("x: {}, y: {}", x, y),
//!                 Event::KeyPressed(k) => if k == Key::Esc { Trans::Quit },
//!             }
//!         }
//!
//!         Trans::None
//!     }
//!
//!     fn update(&mut self, _delta: Duration) -> Trans {
//!         println!("Computing some more whoop-ass...");
//!         Trans::None
//!     }
//! }
//!
//! fn main() {
//!     let mut game = Application::new(GameState);
//!     game.run();
//! }
//! ```

mod engine;
pub mod renderer;

pub use self::engine::app::Application;
pub use self::engine::state::{State, StateMachine, Trans};
pub use self::engine::timing::{Duration, Stopwatch};
<|endoftext|>


<commit_before>pub fn pihex(d: u32) -> String {
    let fraction: f64 = [(1, 4.0), (4, -2.0), (5, -1.0), (6, -1.0)]
        .iter()
        .map(|&(j, k)| k * series_sum(d, j as u32))
        .sum();
    (0..4)
        .scan(fraction, |x, _| {
            *x = (*x - x.floor()) * 16.0;
            Some(*x)
        })
        .map(|x| format!("{:x}", x.floor() as u64))
        .fold(String::new(), |s, t| s + &t)
}

fn series_sum(d: u32, j: u32) -> f64 {
    let fraction1: f64 = (0..d + 1)
        .map(|i| (powmod(16, d - i, (8 * i + j) as u64) as f64) / ((8 * i + j) as f64))
        .sum();
    let fraction2: f64 = (d + 1..)
        .map(|i| 16.0_f64.powi(d as i32 - i as i32) / ((8 * i + j) as f64))
        .take_while(|&x| x > 1e-10_f64)
        .sum();
    (fraction1 + fraction2).fract()
}

fn powmod(n: u64, m: u32, d: u64) -> u64 {
    if m == 0 {
        1 % d
    } else if m == 1 {
        n % d
    } else {
        let k: u64 = powmod(n, m / 2, d);
        if m % 2 == 0 {
            (k * k) % d
        } else {
            (k * k * n) % d
        }
    }
}
<commit_msg>improve performance by using std::thread and calculate the sums in each thread<commit_after>use std::thread;
use std::sync::mpsc;

pub fn pihex(d: u32) -> String {
    let (tx, rx) = mpsc::channel();
    for &(j, k) in &[(1, 4.0), (4, -2.0), (5, -1.0), (6, -1.0)] {
        let tx = tx.clone();
        thread::spawn(move || tx.send(k * series_sum(d, j as u32)).unwrap());
    }
    drop(tx);
    let fraction: f64 = rx.iter().sum();
    (0..4)
        .scan(fraction, |x, _| {
            *x = (*x - x.floor()) * 16.0;
            Some(*x)
        })
        .map(|x| format!("{:x}", x.floor() as u64))
        .fold(String::new(), |s, t| s + &t)
}

fn series_sum(d: u32, j: u32) -> f64 {
    let fraction1: f64 = (0..d + 1)
        .map(|i| (powmod(16, d - i, (8 * i + j) as u64) as f64) / ((8 * i + j) as f64))
        .sum();
    let fraction2: f64 = (d + 1..)
        .map(|i| 16.0_f64.powi(d as i32 - i as i32) / ((8 * i + j) as f64))
        .take_while(|&x| x > 1e-10_f64)
        .sum();
    (fraction1 + fraction2).fract()
}

fn powmod(n: u64, m: u32, d: u64) -> u64 {
    if m == 0 {
        1 % d
    } else if m == 1 {
        n % d
    } else {
        let k: u64 = powmod(n, m / 2, d);
        if m % 2 == 0 {
            (k * k) % d
        } else {
            (k * k * n) % d
        }
    }
}
<|endoftext|>


<commit_before>pub mod ssh_config;
pub mod known_hosts;
pub mod launchagent;
pub mod errors;

#[macro_use] extern crate error_chain;

use std::path::{Path, PathBuf};
use std::io::BufReader;
use std::io::prelude::*;
use std::fs::File;

use errors::*;

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Host {
    name: String,
    protocol: String,
}

impl Host {
    pub fn new(name: &str, protocol: &str) -> Host {
        Host{
            name: name.to_string(),
            protocol: protocol.to_string(),
        }
    }

    pub fn named(name: &str) -> Host {
        Host{
            name: name.to_string(),
            protocol: "ssh".to_string(),
        }
    }

    pub fn write_bookmark(&self, dir: &Path) -> Result<()> {
        let name = format!("{} ({}).webloc", self.name, self.protocol);
        let namepart = Path::new(&name);

        let mut path = PathBuf::from(dir);
        if namepart.is_absolute() {
            bail!(ErrorKind::NameError(self.name.to_string(), self.protocol.to_string()));
        }
        path.push(namepart);

        let mut bookmark_text = String::new();
        bookmark_text.push_str(self.protocol.as_str());
        bookmark_text.push_str("://");
        bookmark_text.push_str(self.name.as_str());
        let bookmark = format!(r#"<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"><dict><key>URL</key><string>{}</string></dict></plist>
"#,
                               bookmark_text);

        let mut f = try!(File::create(path));
        try!(f.write_all(bookmark.as_bytes()));
        Ok(())
    }

    pub fn ineligible(&self) -> bool {
        self.name.contains('*') || self.name.contains('?')
    }
}

pub trait ConfigFile {
    fn pathname<'a>(&'a self) -> &'a Path;

    fn parse_entries<R: BufRead>(&self, r: R) -> Result<Vec<Host>>;

    fn entries(&self) -> Result<Vec<Host>> {
        let f = try!(File::open(self.pathname()));
        let file = BufReader::new(&f);
        self.parse_entries(file)
    }
}

pub fn process<T>(pathnames: Vec<String>) -> Result<Vec<Host>>
    where T: From<PathBuf> + ConfigFile {

    let mut hosts: Vec<Host> = vec![];
    for pn in pathnames {
        let path = PathBuf::from(pn);
        let file = T::from(path);
        hosts.extend(try!(file.entries()));
    }
    Ok(hosts)
}

#[test]
fn test_host_creation() {
    let ohai = Host::named("ohai");
    assert_eq!(ohai.name, "ohai");
    assert_eq!(ohai.protocol, "ssh");

    let mosh_ohai = Host::new("ohai", "mosh");
    assert_eq!(mosh_ohai.name, "ohai");
    assert_eq!(mosh_ohai.protocol, "mosh");
}

#[test]
fn test_host_eligibility() {
    assert_eq!(Host::named("foo*.oink.example.com").ineligible(), true);
    assert_eq!(Host::named("*").ineligible(), true);

    assert_eq!(Host::named("foobar.oink.example.com").ineligible(), false);
}
<commit_msg>Handle non-existent files gracefully<commit_after>pub mod ssh_config;
pub mod known_hosts;
pub mod launchagent;
pub mod errors;

#[macro_use] extern crate error_chain;

use std::path::{Path, PathBuf};
use std::io::BufReader;
use std::io::prelude::*;
use std::fs::File;

use errors::*;

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Host {
    name: String,
    protocol: String,
}

impl Host {
    pub fn new(name: &str, protocol: &str) -> Host {
        Host{
            name: name.to_string(),
            protocol: protocol.to_string(),
        }
    }

    pub fn named(name: &str) -> Host {
        Host{
            name: name.to_string(),
            protocol: "ssh".to_string(),
        }
    }

    pub fn write_bookmark(&self, dir: &Path) -> Result<()> {
        let name = format!("{} ({}).webloc", self.name, self.protocol);
        let namepart = Path::new(&name);

        let mut path = PathBuf::from(dir);
        if namepart.is_absolute() {
            bail!(ErrorKind::NameError(self.name.to_string(), self.protocol.to_string()));
        }
        path.push(namepart);

        let mut bookmark_text = String::new();
        bookmark_text.push_str(self.protocol.as_str());
        bookmark_text.push_str("://");
        bookmark_text.push_str(self.name.as_str());
        let bookmark = format!(r#"<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"><dict><key>URL</key><string>{}</string></dict></plist>
"#,
                               bookmark_text);

        let mut f = try!(File::create(path));
        try!(f.write_all(bookmark.as_bytes()));
        Ok(())
    }

    pub fn ineligible(&self) -> bool {
        self.name.contains('*') || self.name.contains('?')
    }
}

pub trait ConfigFile {
    fn pathname<'a>(&'a self) -> &'a Path;

    fn parse_entries<R: BufRead>(&self, r: R) -> Result<Vec<Host>>;

    fn entries(&self) -> Result<Vec<Host>> {
        let f = try!(File::open(self.pathname()));
        let file = BufReader::new(&f);
        self.parse_entries(file)
    }
}

pub fn process<T>(pathnames: Vec<String>) -> Result<Vec<Host>>
    where T: From<PathBuf> + ConfigFile {

    let mut hosts: Vec<Host> = vec![];
    for pn in pathnames {
        let path = PathBuf::from(pn);
        let file = T::from(path);
        match file.entries() {
            Ok(entries) => hosts.extend(entries),
            Err(e) => println!("Could not read config file {:?} ({}), continuing", file.pathname(), e)
        }
    }
    Ok(hosts)
}

#[test]
fn test_host_creation() {
    let ohai = Host::named("ohai");
    assert_eq!(ohai.name, "ohai");
    assert_eq!(ohai.protocol, "ssh");

    let mosh_ohai = Host::new("ohai", "mosh");
    assert_eq!(mosh_ohai.name, "ohai");
    assert_eq!(mosh_ohai.protocol, "mosh");
}

#[test]
fn test_host_eligibility() {
    assert_eq!(Host::named("foo*.oink.example.com").ineligible(), true);
    assert_eq!(Host::named("*").ineligible(), true);

    assert_eq!(Host::named("foobar.oink.example.com").ineligible(), false);
}
<|endoftext|>


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

#![feature(asm, custom_derive, plugin, repr_simd, test)]
#![feature(augmented_assignments)]
#![feature(op_assign_traits)]

#![cfg_attr(feature = "plugins", plugin(heapsize_plugin))]
#![cfg_attr(feature = "plugins", plugin(serde_macros))]

#[cfg(feature = "plugins")]
#[macro_use]
extern crate heapsize;

#[macro_use]
extern crate log;
extern crate rustc_serialize;
#[cfg(feature = "plugins")]
extern crate serde;

#[cfg(test)]
extern crate rand;
extern crate test;
extern crate num as num_lib;

pub use matrix::Matrix4;
pub use matrix2d::Matrix2D;
pub use point::{Point2D, Point3D, Point4D};
pub use rect::Rect;
pub use side_offsets::SideOffsets2D;
pub use side_offsets::SideOffsets2DSimdI32;
pub use size::Size2D;

pub mod approxeq;
pub mod length;
pub mod matrix;
pub mod matrix2d;
pub mod num;
pub mod point;
pub mod rect;
pub mod scale_factor;
pub mod side_offsets;
pub mod size;
<commit_msg>Move some plugin-only feature gates behind a cfg.<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(asm, repr_simd, test)]
#![feature(augmented_assignments)]
#![feature(op_assign_traits)]

#![cfg_attr(feature = "plugins", feature(custom_derive, plugin))]
#![cfg_attr(feature = "plugins", plugin(heapsize_plugin))]
#![cfg_attr(feature = "plugins", plugin(serde_macros))]

#[cfg(feature = "plugins")]
#[macro_use]
extern crate heapsize;

#[macro_use]
extern crate log;
extern crate rustc_serialize;
#[cfg(feature = "plugins")]
extern crate serde;

#[cfg(test)]
extern crate rand;
extern crate test;
extern crate num as num_lib;

pub use matrix::Matrix4;
pub use matrix2d::Matrix2D;
pub use point::{Point2D, Point3D, Point4D};
pub use rect::Rect;
pub use side_offsets::SideOffsets2D;
pub use side_offsets::SideOffsets2DSimdI32;
pub use size::Size2D;

pub mod approxeq;
pub mod length;
pub mod matrix;
pub mod matrix2d;
pub mod num;
pub mod point;
pub mod rect;
pub mod scale_factor;
pub mod side_offsets;
pub mod size;
<|endoftext|>


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

#[macro_use]
extern crate error_chain;

extern crate rusqlite;

extern crate edn;
extern crate mentat_core;
extern crate mentat_db;
extern crate mentat_query;
extern crate mentat_query_algebrizer;
extern crate mentat_query_parser;
extern crate mentat_query_projector;
extern crate mentat_query_translator;
extern crate mentat_sql;
extern crate mentat_tx_parser;

use rusqlite::Connection;

pub mod errors;
pub mod ident;
pub mod conn;
pub mod query;

pub fn get_name() -> String {
    return String::from("mentat");
}

// Will ultimately not return the sqlite connection directly
pub fn get_connection() -> Connection {
    return Connection::open_in_memory().unwrap();
}

pub use mentat_db::{
    new_connection,
};

pub use query::{
    NamespacedKeyword,
    PlainSymbol,
    QueryInputs,
    QueryResults,
    Variable,
    q_once,
};

#[cfg(test)]
mod tests {
    use edn::symbols::Keyword;

    #[test]
    fn can_import_edn() {
        assert_eq!("foo", Keyword::new("foo").0);
    }
}
<commit_msg>Expose mentat_core::{TypedValue,ValueType} and conn::{Conn,Metadata}. (#443)<commit_after>// Copyright 2016 Mozilla
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
// this file except in compliance with the License. You may obtain a copy of the
// License at http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.

#[macro_use]
extern crate error_chain;

extern crate rusqlite;

extern crate edn;
extern crate mentat_core;
extern crate mentat_db;
extern crate mentat_query;
extern crate mentat_query_algebrizer;
extern crate mentat_query_parser;
extern crate mentat_query_projector;
extern crate mentat_query_translator;
extern crate mentat_sql;
extern crate mentat_tx_parser;

use rusqlite::Connection;

pub mod errors;
pub mod ident;
pub mod conn;
pub mod query;

pub fn get_name() -> String {
    return String::from("mentat");
}

// Will ultimately not return the sqlite connection directly
pub fn get_connection() -> Connection {
    return Connection::open_in_memory().unwrap();
}

pub use mentat_core::{
    TypedValue,
    ValueType,
};

pub use mentat_db::{
    new_connection,
};

pub use query::{
    NamespacedKeyword,
    PlainSymbol,
    QueryInputs,
    QueryResults,
    Variable,
    q_once,
};

pub use conn::{
    Conn,
    Metadata,
};

#[cfg(test)]
mod tests {
    use edn::symbols::Keyword;

    #[test]
    fn can_import_edn() {
        assert_eq!("foo", Keyword::new("foo").0);
    }
}
<|endoftext|>


<commit_before>//! Lettre is a mailer written in Rust. It provides a simple email builder and several transports.
//!
//! This mailer contains the available transports for your emails.
//!

#![doc(html_root_url = "https://docs.rs/lettre/0.9.2")]
#![deny(
    missing_copy_implementations,
    trivial_casts,
    trivial_numeric_casts,
    unsafe_code,
    unstable_features,
    unused_import_braces
)]

pub mod error;
#[cfg(feature = "file-transport")]
pub mod file;
#[cfg(feature = "sendmail-transport")]
pub mod sendmail;
#[cfg(feature = "smtp-transport")]
pub mod smtp;
pub mod stub;

use crate::error::EmailResult;
use crate::error::Error;
#[cfg(feature = "file-transport")]
pub use crate::file::FileTransport;
#[cfg(feature = "sendmail-transport")]
pub use crate::sendmail::SendmailTransport;
#[cfg(feature = "smtp-transport")]
pub use crate::smtp::client::net::ClientTlsParameters;
#[cfg(all(feature = "smtp-transport", feature = "connection-pool"))]
pub use crate::smtp::r2d2::SmtpConnectionManager;
#[cfg(feature = "smtp-transport")]
pub use crate::smtp::{ClientSecurity, SmtpClient, SmtpTransport};
use fast_chemail::is_valid_email;
use std::ffi::OsStr;
use std::fmt::{self, Display, Formatter};
use std::io;
use std::io::Cursor;
use std::io::Read;
use std::str::FromStr;

/// Email address
#[derive(PartialEq, Eq, Clone, Debug)]
#[cfg_attr(
    feature = "serde-impls",
    derive(serde::Serialize, serde::Deserialize)
)]
pub struct EmailAddress(String);

impl EmailAddress {
    pub fn new(address: String) -> EmailResult<EmailAddress> {
        if !is_valid_email(&address) && !address.ends_with("localhost") {
            Err(Error::InvalidEmailAddress)?;
        }
        Ok(EmailAddress(address))
    }
}

impl FromStr for EmailAddress {
    type Err = Error;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        EmailAddress::new(s.to_string())
    }
}

impl Display for EmailAddress {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        f.write_str(&self.0)
    }
}

impl AsRef<str> for EmailAddress {
    fn as_ref(&self) -> &str {
        &self.0
    }
}

impl AsRef<OsStr> for EmailAddress {
    fn as_ref(&self) -> &OsStr {
        &self.0.as_ref()
    }
}

/// Simple email envelope representation
///
/// We only accept mailboxes, and do not support source routes (as per RFC).
#[derive(PartialEq, Eq, Clone, Debug)]
#[cfg_attr(
    feature = "serde-impls",
    derive(serde::Serialize, serde::Deserialize)
)]
pub struct Envelope {
    /// The envelope recipients' addresses
    ///
    /// This can not be empty.
    forward_path: Vec<EmailAddress>,
    /// The envelope sender address
    reverse_path: Option<EmailAddress>,
}

impl Envelope {
    /// Creates a new envelope, which may fail if `to` is empty.
    pub fn new(from: Option<EmailAddress>, to: Vec<EmailAddress>) -> EmailResult<Envelope> {
        if to.is_empty() {
            Err(Error::MissingTo)?;
        }
        Ok(Envelope {
            forward_path: to,
            reverse_path: from,
        })
    }

    /// Destination addresses of the envelope
    pub fn to(&self) -> &[EmailAddress] {
        self.forward_path.as_slice()
    }

    /// Source address of the envelope
    pub fn from(&self) -> Option<&EmailAddress> {
        self.reverse_path.as_ref()
    }
}

pub enum Message {
    Reader(Box<dyn Read + Send>),
    Bytes(Cursor<Vec<u8>>),
}

impl Read for Message {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        match *self {
            Message::Reader(ref mut rdr) => rdr.read(buf),
            Message::Bytes(ref mut rdr) => rdr.read(buf),
        }
    }
}

/// Sendable email structure
pub struct SendableEmail {
    envelope: Envelope,
    message_id: String,
    message: Message,
}

impl SendableEmail {
    pub fn new(envelope: Envelope, message_id: String, message: Vec<u8>) -> SendableEmail {
        SendableEmail {
            envelope,
            message_id,
            message: Message::Bytes(Cursor::new(message)),
        }
    }

    pub fn new_with_reader(
        envelope: Envelope,
        message_id: String,
        message: Box<dyn Read + Send>,
    ) -> SendableEmail {
        SendableEmail {
            envelope,
            message_id,
            message: Message::Reader(message),
        }
    }

    pub fn envelope(&self) -> &Envelope {
        &self.envelope
    }

    pub fn message_id(&self) -> &str {
        &self.message_id
    }

    pub fn message(self) -> Message {
        self.message
    }

    pub fn message_to_string(mut self) -> Result<String, io::Error> {
        let mut message_content = String::new();
        self.message.read_to_string(&mut message_content)?;
        Ok(message_content)
    }
}

/// Transport method for emails
pub trait Transport<'a> {
    /// Result type for the transport
    type Result;

    /// Sends the email
    fn send(&mut self, email: SendableEmail) -> Self::Result;
}
<commit_msg>feat(email): Add EmailAddress::is_valid and into_inner<commit_after>//! Lettre is a mailer written in Rust. It provides a simple email builder and several transports.
//!
//! This mailer contains the available transports for your emails.
//!

#![doc(html_root_url = "https://docs.rs/lettre/0.9.2")]
#![deny(
    missing_copy_implementations,
    trivial_casts,
    trivial_numeric_casts,
    unsafe_code,
    unstable_features,
    unused_import_braces
)]

pub mod error;
#[cfg(feature = "file-transport")]
pub mod file;
#[cfg(feature = "sendmail-transport")]
pub mod sendmail;
#[cfg(feature = "smtp-transport")]
pub mod smtp;
pub mod stub;

use crate::error::EmailResult;
use crate::error::Error;
#[cfg(feature = "file-transport")]
pub use crate::file::FileTransport;
#[cfg(feature = "sendmail-transport")]
pub use crate::sendmail::SendmailTransport;
#[cfg(feature = "smtp-transport")]
pub use crate::smtp::client::net::ClientTlsParameters;
#[cfg(all(feature = "smtp-transport", feature = "connection-pool"))]
pub use crate::smtp::r2d2::SmtpConnectionManager;
#[cfg(feature = "smtp-transport")]
pub use crate::smtp::{ClientSecurity, SmtpClient, SmtpTransport};
use fast_chemail::is_valid_email;
use std::ffi::OsStr;
use std::fmt::{self, Display, Formatter};
use std::io;
use std::io::Cursor;
use std::io::Read;
use std::str::FromStr;

/// Email address
#[derive(PartialEq, Eq, Clone, Debug)]
#[cfg_attr(
    feature = "serde-impls",
    derive(serde::Serialize, serde::Deserialize)
)]
pub struct EmailAddress(String);

impl EmailAddress {
    pub fn new(address: String) -> EmailResult<EmailAddress> {
        if !EmailAddress::is_valid(&address) {
            Err(Error::InvalidEmailAddress)?;
        }
        Ok(EmailAddress(address))
    }

    pub fn is_valid(addr: &str) -> bool {
        is_valid_email(addr) || addr.ends_with("localhost")
    }

    pub fn into_inner(self) -> String {
        self.0
    }
}

impl FromStr for EmailAddress {
    type Err = Error;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        EmailAddress::new(s.to_string())
    }
}

impl Display for EmailAddress {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        f.write_str(&self.0)
    }
}

impl AsRef<str> for EmailAddress {
    fn as_ref(&self) -> &str {
        &self.0
    }
}

impl AsRef<OsStr> for EmailAddress {
    fn as_ref(&self) -> &OsStr {
        &self.0.as_ref()
    }
}

/// Simple email envelope representation
///
/// We only accept mailboxes, and do not support source routes (as per RFC).
#[derive(PartialEq, Eq, Clone, Debug)]
#[cfg_attr(
    feature = "serde-impls",
    derive(serde::Serialize, serde::Deserialize)
)]
pub struct Envelope {
    /// The envelope recipients' addresses
    ///
    /// This can not be empty.
    forward_path: Vec<EmailAddress>,
    /// The envelope sender address
    reverse_path: Option<EmailAddress>,
}

impl Envelope {
    /// Creates a new envelope, which may fail if `to` is empty.
    pub fn new(from: Option<EmailAddress>, to: Vec<EmailAddress>) -> EmailResult<Envelope> {
        if to.is_empty() {
            Err(Error::MissingTo)?;
        }
        Ok(Envelope {
            forward_path: to,
            reverse_path: from,
        })
    }

    /// Destination addresses of the envelope
    pub fn to(&self) -> &[EmailAddress] {
        self.forward_path.as_slice()
    }

    /// Source address of the envelope
    pub fn from(&self) -> Option<&EmailAddress> {
        self.reverse_path.as_ref()
    }
}

pub enum Message {
    Reader(Box<dyn Read + Send>),
    Bytes(Cursor<Vec<u8>>),
}

impl Read for Message {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        match *self {
            Message::Reader(ref mut rdr) => rdr.read(buf),
            Message::Bytes(ref mut rdr) => rdr.read(buf),
        }
    }
}

/// Sendable email structure
pub struct SendableEmail {
    envelope: Envelope,
    message_id: String,
    message: Message,
}

impl SendableEmail {
    pub fn new(envelope: Envelope, message_id: String, message: Vec<u8>) -> SendableEmail {
        SendableEmail {
            envelope,
            message_id,
            message: Message::Bytes(Cursor::new(message)),
        }
    }

    pub fn new_with_reader(
        envelope: Envelope,
        message_id: String,
        message: Box<dyn Read + Send>,
    ) -> SendableEmail {
        SendableEmail {
            envelope,
            message_id,
            message: Message::Reader(message),
        }
    }

    pub fn envelope(&self) -> &Envelope {
        &self.envelope
    }

    pub fn message_id(&self) -> &str {
        &self.message_id
    }

    pub fn message(self) -> Message {
        self.message
    }

    pub fn message_to_string(mut self) -> Result<String, io::Error> {
        let mut message_content = String::new();
        self.message.read_to_string(&mut message_content)?;
        Ok(message_content)
    }
}

/// Transport method for emails
pub trait Transport<'a> {
    /// Result type for the transport
    type Result;

    /// Sends the email
    fn send(&mut self, email: SendableEmail) -> Self::Result;
}
<|endoftext|>


<commit_before>extern crate protobuf;
mod raftpb;
<commit_msg>*: Address comments<commit_after>mod raftpb;
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

//! Interface between StateSynchronizer and Network layers.

use crate::{chunk_request::GetChunkRequest, chunk_response::GetChunkResponse, counters};
use channel::message_queues::QueueStyle;
use libra_types::PeerId;
use network::{
    error::NetworkError,
    peer_manager::{ConnectionRequestSender, PeerManagerRequestSender},
    protocols::network::{NetworkEvents, NetworkSender},
    validator_network::network_builder::{NetworkBuilder, NETWORK_CHANNEL_SIZE},
    ProtocolId,
};
use serde::{Deserialize, Serialize};

/// StateSynchronizer network messages
#[derive(Clone, Debug, Deserialize, Serialize)]
pub enum StateSynchronizerMsg {
    GetChunkRequest(Box<GetChunkRequest>),
    GetChunkResponse(Box<GetChunkResponse>),
}

/// The interface from Network to StateSynchronizer layer.
///
/// `StateSynchronizerEvents` is a `Stream` of `PeerManagerNotification` where the
/// raw `Bytes` direct-send messages are deserialized into `StateSynchronizerMsg`
/// types. `StateSynchronizerEvents` is a thin wrapper around an
/// `channel::Receiver<PeerManagerNotification>`.
pub type StateSynchronizerEvents = NetworkEvents<StateSynchronizerMsg>;

/// The interface from StateSynchronizer to Networking layer.
///
/// This is a thin wrapper around a `NetworkSender<StateSynchronizerMsg>`, so it
/// is easy to clone and send off to a separate task. For example, the rpc
/// requests return Futures that encapsulate the whole flow, from sending the
/// request to remote, to finally receiving the response and deserializing. It
/// therefore makes the most sense to make the rpc call on a separate async task,
/// which requires the `StateSynchronizerSender` to be `Clone` and `Send`.
#[derive(Clone)]
pub struct StateSynchronizerSender {
    inner: NetworkSender<StateSynchronizerMsg>,
}

pub fn add_to_network(
    network: &mut NetworkBuilder,
) -> (StateSynchronizerSender, StateSynchronizerEvents) {
    let (sender, receiver, connection_reqs_tx, connection_notifs_rx) = network
        .add_protocol_handler(
            vec![],
            vec![ProtocolId::StateSynchronizerDirectSend],
            QueueStyle::FIFO,
            NETWORK_CHANNEL_SIZE,
            Some(&counters::PENDING_STATE_SYNCHRONIZER_NETWORK_EVENTS),
        );
    (
        StateSynchronizerSender::new(sender, connection_reqs_tx),
        StateSynchronizerEvents::new(receiver, connection_notifs_rx),
    )
}

impl StateSynchronizerSender {
    pub fn new(
        peer_mgr_reqs_tx: PeerManagerRequestSender,
        connection_reqs_tx: ConnectionRequestSender,
    ) -> Self {
        Self {
            inner: NetworkSender::new(peer_mgr_reqs_tx, connection_reqs_tx),
        }
    }

    pub fn send_to(
        &mut self,
        recipient: PeerId,
        message: StateSynchronizerMsg,
    ) -> Result<(), NetworkError> {
        let protocol = ProtocolId::StateSynchronizerDirectSend;
        self.inner.send_to(recipient, protocol, message)
    }
}
<commit_msg>[state sync] tune libra channel<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

//! Interface between StateSynchronizer and Network layers.

use crate::{chunk_request::GetChunkRequest, chunk_response::GetChunkResponse, counters};
use channel::message_queues::QueueStyle;
use libra_types::PeerId;
use network::{
    error::NetworkError,
    peer_manager::{ConnectionRequestSender, PeerManagerRequestSender},
    protocols::network::{NetworkEvents, NetworkSender},
    validator_network::network_builder::NetworkBuilder,
    ProtocolId,
};
use serde::{Deserialize, Serialize};

/// StateSynchronizer network messages
#[derive(Clone, Debug, Deserialize, Serialize)]
pub enum StateSynchronizerMsg {
    GetChunkRequest(Box<GetChunkRequest>),
    GetChunkResponse(Box<GetChunkResponse>),
}

/// The interface from Network to StateSynchronizer layer.
///
/// `StateSynchronizerEvents` is a `Stream` of `PeerManagerNotification` where the
/// raw `Bytes` direct-send messages are deserialized into `StateSynchronizerMsg`
/// types. `StateSynchronizerEvents` is a thin wrapper around an
/// `channel::Receiver<PeerManagerNotification>`.
pub type StateSynchronizerEvents = NetworkEvents<StateSynchronizerMsg>;

/// The interface from StateSynchronizer to Networking layer.
///
/// This is a thin wrapper around a `NetworkSender<StateSynchronizerMsg>`, so it
/// is easy to clone and send off to a separate task. For example, the rpc
/// requests return Futures that encapsulate the whole flow, from sending the
/// request to remote, to finally receiving the response and deserializing. It
/// therefore makes the most sense to make the rpc call on a separate async task,
/// which requires the `StateSynchronizerSender` to be `Clone` and `Send`.
#[derive(Clone)]
pub struct StateSynchronizerSender {
    inner: NetworkSender<StateSynchronizerMsg>,
}

pub fn add_to_network(
    network: &mut NetworkBuilder,
) -> (StateSynchronizerSender, StateSynchronizerEvents) {
    let (sender, receiver, connection_reqs_tx, connection_notifs_rx) = network
        .add_protocol_handler(
            vec![],
            vec![ProtocolId::StateSynchronizerDirectSend],
            QueueStyle::LIFO,
            1,
            Some(&counters::PENDING_STATE_SYNCHRONIZER_NETWORK_EVENTS),
        );
    (
        StateSynchronizerSender::new(sender, connection_reqs_tx),
        StateSynchronizerEvents::new(receiver, connection_notifs_rx),
    )
}

impl StateSynchronizerSender {
    pub fn new(
        peer_mgr_reqs_tx: PeerManagerRequestSender,
        connection_reqs_tx: ConnectionRequestSender,
    ) -> Self {
        Self {
            inner: NetworkSender::new(peer_mgr_reqs_tx, connection_reqs_tx),
        }
    }

    pub fn send_to(
        &mut self,
        recipient: PeerId,
        message: StateSynchronizerMsg,
    ) -> Result<(), NetworkError> {
        let protocol = ProtocolId::StateSynchronizerDirectSend;
        self.inner.send_to(recipient, protocol, message)
    }
}
<|endoftext|>