<commit_before>use bot::LalafellBot;
use database::models::{Message as DbMessage, Edit};

use lalafell::bot::Bot;
use lalafell::commands::prelude::*;
use lalafell::error::*;

use discord::model::{Message, LiveServer, PublicChannel, permissions};

use diesel::prelude::*;

use std::sync::Arc;

const USAGE: &'static str = "!viewedits <message ID>";

pub struct ViewEditsCommand {
  bot: Arc<LalafellBot>
}

impl ViewEditsCommand {
  pub fn new(bot: Arc<LalafellBot>) -> ViewEditsCommand {
    ViewEditsCommand {
      bot: bot
    }
  }
}

impl HasBot for ViewEditsCommand {
  fn bot(&self) -> &Bot {
    self.bot.as_ref()
  }
}

#[derive(Debug, Deserialize)]
pub struct Params {
  message_id: u64
}

impl HasParams for ViewEditsCommand {
  type Params = Params;
}

impl<'a> PublicChannelCommand<'a> for ViewEditsCommand {
  fn run(&self, message: &Message, server: &LiveServer, channel: &PublicChannel, params: &[&str]) -> CommandResult<'a> {
    let params = self.params(USAGE, params)?;

    let has_perms = server.permissions_for(channel.id, message.author.id).contains(permissions::MANAGE_MESSAGES);
    if !has_perms {
      return Err(ExternalCommandFailure::default()
        .message(|e: EmbedBuilder| e
          .title("Not enough permissions.")
          .description("You don't have enough permissions to use this command."))
        .wrap());
    }

    let message: Option<DbMessage> = ::bot::CONNECTION.with(|c| {
      use database::schema::messages::dsl;
      dsl::messages
        .filter(dsl::message_id.eq(params.message_id.to_string()))
        .first::<DbMessage>(c)
        .optional()
        .chain_err(|| "could not load messages")
    })?;
    let message = match message {
      Some(m) => m,
      None => return Err("No message with that ID recorded.".into())
    };

    if !server.channels.iter().any(|c| c.id.0 == *message.channel_id) {
      return Err("You cannot view messages not on the current server.".into());
    }

    let edits: Vec<Edit> = ::bot::CONNECTION.with(|c| Edit::belonging_to(&message).load(c).chain_err(|| "could not load edits"))?;
    if edits.is_empty() {
      return Err("That message has not been edited.".into());
    }

    let mut result = String::new();
    let mut messages: Vec<String> = edits.into_iter().map(|x| x.content).collect();
    messages.insert(0, message.content);

    for edits in messages.windows(2) {
      result.push_str("- ");
      result.push_str(&edits[0]);
      result.push('\n');
      result.push_str("+ ");
      result.push_str(&edits[1]);
      result.push_str("\n\n");
    }

    Ok(format!("```diff\n{}```", result).into())
  }
}
<commit_msg>feat: include more information in !viewedits<commit_after>use bot::LalafellBot;
use database::models::{Message as DbMessage, Edit};

use lalafell::bot::Bot;
use lalafell::commands::prelude::*;
use lalafell::error::*;

use discord::model::{Message, LiveServer, PublicChannel, permissions, ChannelId, MessageId};

use diesel::prelude::*;

use std::sync::Arc;

const USAGE: &'static str = "!viewedits <message ID>";

pub struct ViewEditsCommand {
  bot: Arc<LalafellBot>
}

impl ViewEditsCommand {
  pub fn new(bot: Arc<LalafellBot>) -> ViewEditsCommand {
    ViewEditsCommand {
      bot: bot
    }
  }
}

impl HasBot for ViewEditsCommand {
  fn bot(&self) -> &Bot {
    self.bot.as_ref()
  }
}

#[derive(Debug, Deserialize)]
pub struct Params {
  message_id: u64
}

impl HasParams for ViewEditsCommand {
  type Params = Params;
}

impl<'a> PublicChannelCommand<'a> for ViewEditsCommand {
  fn run(&self, message: &Message, server: &LiveServer, channel: &PublicChannel, params: &[&str]) -> CommandResult<'a> {
    let params = self.params(USAGE, params)?;

    let has_perms = server.permissions_for(channel.id, message.author.id).contains(permissions::MANAGE_MESSAGES);
    if !has_perms {
      return Err(ExternalCommandFailure::default()
        .message(|e: EmbedBuilder| e
          .title("Not enough permissions.")
          .description("You don't have enough permissions to use this command."))
        .wrap());
    }

    let message: Option<DbMessage> = ::bot::CONNECTION.with(|c| {
      use database::schema::messages::dsl;
      dsl::messages
        .filter(dsl::message_id.eq(params.message_id.to_string()))
        .first::<DbMessage>(c)
        .optional()
        .chain_err(|| "could not load messages")
    })?;
    let message = match message {
      Some(m) => m,
      None => return Err("No message with that ID recorded.".into())
    };

    let channel = match server.channels.iter().find(|c| c.id.0 == *message.channel_id) {
      Some(c) => c,
      None => return Err("You cannot view messages not on the current server.".into())
    };

    let discord_message = self.bot.discord.get_message(ChannelId(*message.channel_id), MessageId(params.message_id)).ok();

    let edits: Vec<Edit> = ::bot::CONNECTION.with(|c| Edit::belonging_to(&message).load(c).chain_err(|| "could not load edits"))?;
    if edits.is_empty() {
      return Err("That message has not been edited.".into());
    }

    let mut result = String::new();
    let mut messages: Vec<String> = edits.into_iter().map(|x| x.content).collect();
    messages.insert(0, message.content);

    for edits in messages.windows(2) {
      result.push_str("- ");
      result.push_str(&edits[0]);
      result.push('\n');
      result.push_str("+ ");
      result.push_str(&edits[1]);
      result.push_str("\n\n");
    }

    let author = discord_message.map(|m| format!(" by {}", m.author.name)).unwrap_or_default();
    let channel_name = channel.name.clone();

    Ok(CommandSuccess::default()
      .message(move |e: EmbedBuilder| e
        .title(&format!("Message{} in #{}", author, channel_name))
        .description(&format!("```diff\n{}```", result))))
  }
}
<|endoftext|>


<commit_before>import run::spawn_process;
import io::writer_util;
import libc::{c_int, pid_t};

export run;

#[cfg(target_os = "win32")]
fn target_env(lib_path: str, prog: str) -> [(str,str)] {

    let env = os::env();

    env = vec::map(env) {|pair|
        let (k,v) = pair;
        if k == "PATH" { ("PATH", v + ";" + lib_path) }
        else { (k,v) }
    };
    if str::ends_with(prog, "rustc.exe") {
        env += [("RUST_THREADS", "1")]
    }
    ret env;
}

#[cfg(target_os = "linux")]
#[cfg(target_os = "macos")]
#[cfg(target_os = "freebsd")]
fn target_env(_lib_path: str, _prog: str) -> [(str,str)] {
    []
}

fn run(lib_path: str,
       prog: str,
       args: [str],
       env: [(str, str)],
       input: option<str>) -> {status: int, out: str, err: str} {

    let pipe_in = os::pipe();
    let pipe_out = os::pipe();
    let pipe_err = os::pipe();
    let pid = spawn_process(prog, args,
                            some(env + target_env(lib_path, prog)),
                            none, pipe_in.in, pipe_out.out, pipe_err.out);

    os::close(pipe_in.in);
    os::close(pipe_out.out);
    os::close(pipe_err.out);
    if pid == -1i32 {
        os::close(pipe_in.out);
        os::close(pipe_out.in);
        os::close(pipe_err.in);
        fail;
    }

    writeclose(pipe_in.out, input);
    let p = comm::port();
    let ch = comm::chan(p);
    task::spawn_sched(task::single_threaded) {||
        let errput = readclose(pipe_err.in);
        comm::send(ch, (2, errput));
    };
    task::spawn_sched(task::single_threaded) {||
        let output = readclose(pipe_out.in);
        comm::send(ch, (1, output));
    };
    let status = run::waitpid(pid);
    let mut errs = "";
    let mut outs = "";
    let mut count = 2;
    while count > 0 {
        let stream = comm::recv(p);
        alt check stream {
            (1, s) {
                outs = s;
            }
            (2, s) {
                errs = s;
            }
        };
        count -= 1;
    };
    ret {status: status, out: outs, err: errs};
}

fn writeclose(fd: c_int, s: option<str>) {
    if option::is_some(s) {
        let writer = io::fd_writer(fd, false);
        writer.write_str(option::get(s));
    }

    os::close(fd);
}

fn readclose(fd: c_int) -> str {
    // Copied from run::program_output
    let file = os::fdopen(fd);
    let reader = io::FILE_reader(file, false);
    let mut buf = "";
    while !reader.eof() {
        let bytes = reader.read_bytes(4096u);
        buf += str::from_bytes(bytes);
    }
    os::fclose(file);
    ret buf;
}
<commit_msg>compiletest: Unbreak on Win32<commit_after>import run::spawn_process;
import io::writer_util;
import libc::{c_int, pid_t};

export run;

#[cfg(target_os = "win32")]
fn target_env(lib_path: str, prog: str) -> [(str,str)] {

    let mut env = os::env();

    env = vec::map(env) {|pair|
        let (k,v) = pair;
        if k == "PATH" { ("PATH", v + ";" + lib_path) }
        else { (k,v) }
    };
    if str::ends_with(prog, "rustc.exe") {
        env += [("RUST_THREADS", "1")]
    }
    ret env;
}

#[cfg(target_os = "linux")]
#[cfg(target_os = "macos")]
#[cfg(target_os = "freebsd")]
fn target_env(_lib_path: str, _prog: str) -> [(str,str)] {
    []
}

fn run(lib_path: str,
       prog: str,
       args: [str],
       env: [(str, str)],
       input: option<str>) -> {status: int, out: str, err: str} {

    let pipe_in = os::pipe();
    let pipe_out = os::pipe();
    let pipe_err = os::pipe();
    let pid = spawn_process(prog, args,
                            some(env + target_env(lib_path, prog)),
                            none, pipe_in.in, pipe_out.out, pipe_err.out);

    os::close(pipe_in.in);
    os::close(pipe_out.out);
    os::close(pipe_err.out);
    if pid == -1i32 {
        os::close(pipe_in.out);
        os::close(pipe_out.in);
        os::close(pipe_err.in);
        fail;
    }

    writeclose(pipe_in.out, input);
    let p = comm::port();
    let ch = comm::chan(p);
    task::spawn_sched(task::single_threaded) {||
        let errput = readclose(pipe_err.in);
        comm::send(ch, (2, errput));
    };
    task::spawn_sched(task::single_threaded) {||
        let output = readclose(pipe_out.in);
        comm::send(ch, (1, output));
    };
    let status = run::waitpid(pid);
    let mut errs = "";
    let mut outs = "";
    let mut count = 2;
    while count > 0 {
        let stream = comm::recv(p);
        alt check stream {
            (1, s) {
                outs = s;
            }
            (2, s) {
                errs = s;
            }
        };
        count -= 1;
    };
    ret {status: status, out: outs, err: errs};
}

fn writeclose(fd: c_int, s: option<str>) {
    if option::is_some(s) {
        let writer = io::fd_writer(fd, false);
        writer.write_str(option::get(s));
    }

    os::close(fd);
}

fn readclose(fd: c_int) -> str {
    // Copied from run::program_output
    let file = os::fdopen(fd);
    let reader = io::FILE_reader(file, false);
    let mut buf = "";
    while !reader.eof() {
        let bytes = reader.read_bytes(4096u);
        buf += str::from_bytes(bytes);
    }
    os::fclose(file);
    ret buf;
}
<|endoftext|>


<commit_before>use seed::prelude::*;
use crate::Msg;

use num_traits::{ToPrimitive};

const PERFECTS_COUNT: usize = 27;

mod perfects_utils {
	use num_bigint::{BigUint,ToBigUint};
    use seed::prelude::*;
	use crate::Model;
    use crate::Msg;

	pub struct Perfect<'a> {
		pub n: u64,
		pub p: u64,
		pub digits: u64,
		pub discovery: &'a str,
	}

	pub fn perfects<'a>() -> Vec<Perfect<'a>> {
        vec![
			/*Perfect {n: 51, p: 82589934, digits: 49724095, discovery: "2018 Laroche, Woltman, Kurowski, Blosser, et al."},
			Perfect {n: 50, p: 77232917, digits: 46498850, discovery: "2017 Jonathan Pace, George Woltman, Scott Kurowski, Aaron Blosser, et al.." },
			Perfect {n: 49, p: 74207281, digits: 44677235, discovery: "2016 Cooper, Woltman, Kurowski, Blosser et al." },
			Perfect {n: 48, p: 57885161, digits: 34850340, discovery: "2013 Cooper, Woltman, Kurowski, et al." },
			Perfect {n: 47, p: 43112609, digits: 25956377, discovery: "2008 Smith, Woltman, Kurowski, et al." },
			Perfect {n: 46, p: 42643801, digits: 42643801, discovery: "2009 Strindmo, Woltman, Kurowski, et al." },
			Perfect {n: 45, p: 37156667, digits: 22370543, discovery: "2008 Elvenich, Woltman, Kurowski, et al." },
			Perfect {n: 44, p: 32582657, digits: 19616714, discovery: "2006 Cooper, Boone, Woltman, Kurowski, et al." },
			Perfect {n: 43, p: 30402457, digits: 18304103, discovery: "2005 Cooper, Boone, Woltman, Kurowski, et al." },
			Perfect {n: 42, p: 25964951, digits: 15632458, discovery: "2005 Nowak, Woltman, Kurowski, et. al." },
			Perfect {n: 41, p: 24036583, digits: 14471465, discovery: "2004 Findley, Woltman, Kurowski, et. al." },
			Perfect {n: 40, p: 20996011, digits: 12640858, discovery: "2003 Shafer, Woltman, Kurowski, et. al." },
			Perfect {n: 39, p: 13466917, digits: 8107892, discovery: "2001 Cameron, Woltman, Kurowski, et. al." },
			Perfect {n: 38, p: 6972593, digits: 4197919, discovery: "1999 Hajratwala, Woltman, Kurowski, et. al." },
			Perfect {n: 37, p: 3021377, digits: 1819050, discovery: "1998 Clarkson, Woltman, Kurowski, et. al." },
			Perfect {n: 36, p: 2976221, digits: 1791864, discovery: "1997 Spence, Woltman, et. al." },
			Perfect {n: 35, p: 1398269, digits: 841842, discovery: "1996 Armengaud, Woltman, et. al." },
			Perfect {n: 34, p: 1257787, digits: 757263, discovery: "1996 Slowinski&Gage" },
			Perfect {n: 33, p: 859433, digits: 517430, discovery: "1994 Slowinski&Gage" },
			Perfect {n: 32, p: 756839, digits: 455663, discovery: "1992 Slowinski&Gage" },
			Perfect {n: 31, p: 216091, digits: 130100, discovery: "1985 Slowinski" },
			Perfect {n: 30, p: 132049, digits: 79502, discovery: "1983 Slowinski" },
			Perfect {n: 29, p: 110503, digits: 66530, discovery: "1988 Colquitt&Welsh" },
			Perfect {n: 28, p: 86243, digits: 51924, discovery: "1982 Slowinski" },*/
			Perfect {n: 27, p: 44497, digits: 26790, discovery: "1979 Nelson&Slowinski" },
			Perfect {n: 26, p: 23209, digits: 13973, discovery: "1979 Noll" },
			Perfect {n: 25, p: 21701, digits: 13066, discovery: "1978 Noll&Nickel" },
			Perfect {n: 24, p: 19937, digits: 12003, discovery: "1971 Tuckerman" },
			Perfect {n: 23, p: 11213, digits: 6751, discovery: "1963 Gillies" },
			Perfect {n: 22, p: 9941, digits: 5985, discovery: "1963 Gillies" },
			Perfect {n: 21, p: 9689, digits: 5834, discovery: "1963 Gillies" },
			Perfect {n: 20, p: 4423, digits: 2663, discovery: "1961 Hurwitz" },
			Perfect {n: 19, p: 4253, digits: 2561, discovery: "1961 Hurwitz" },
			Perfect {n: 18, p: 3217, digits: 1937, discovery: "1957 Riesel" },
			Perfect {n: 17, p: 2281, digits: 1373, discovery: "1952 Robinson" },
			Perfect {n: 16, p: 2203, digits: 1327, discovery: "1952 Robinson" },
			Perfect {n: 15, p: 1279, digits: 770, discovery: "1952 Robinson" },
			Perfect {n: 14, p: 607, digits: 366, discovery: "1952 Robinson" },
			Perfect {n: 13, p: 521, digits: 314, discovery: "1952 Robinson" },
			Perfect {n: 12, p: 127, digits: 77, discovery: "1876 Lucas" },
			Perfect {n: 11, p: 107, digits: 65, discovery: "1914 Powers" },
			Perfect {n: 10, p: 89, digits: 54, discovery: "1911 Powers" },
			Perfect {n: 9, p: 61, digits: 37, discovery: "1883 Pervushin" },
			Perfect {n: 8, p: 31, digits: 19, discovery: "1772 Euler" },
			Perfect {n: 7, p: 19, digits: 12, discovery: "1588 Cataldi" },
			Perfect {n: 6, p: 17, digits: 10, discovery: "1588 Cataldi" },
			Perfect {n: 5, p: 13, digits: 8, discovery: "1456 ?" },
			Perfect {n: 4, p: 7, digits: 4, discovery: "?" },
			Perfect {n: 3, p: 5, digits: 3, discovery: "?" },
			Perfect {n: 2, p: 3, digits: 2, discovery: "?" },
			Perfect {n: 1, p: 2, digits: 1, discovery: "?" },
		]
	}

	pub fn save_as_file(filename:String, filecontent:String) -> seed::dom_types::Node<Msg> {
        let href:String = vec!["data:text/plain,",&filecontent].into_iter().collect();
        a![attrs!{At::Download => &filename, At::Href => &href}, "TXT"]
    }

	pub fn generate_file(n:usize, p:usize) -> seed::dom_types::Node<Msg> {
		let download_filename:String = format!("P{}.txt",&n.to_string());
		let two:BigUint = 2.to_biguint().unwrap();
		let power:BigUint = two.clone() << (p-1-1);
        let perfect_value:BigUint = power.clone() * ((power.clone()*two.clone()) -1.to_biguint().unwrap());
        a![attrs!{At::Download => ""}, "TXT"]
    }
}

pub fn render(model: &crate::Model) -> seed::dom_types::Node<Msg> {
    let mut html = vec![];
    let mut perfects = perfects_utils::perfects();

    for n in 0..PERFECTS_COUNT {
		let equation:String = format!("2{} × (2{}-1)",&(perfects[n].p-1).to_string(),&(perfects[n].p).to_string());

		let p:usize = perfects[n].p.to_usize().unwrap();

        html.push(
            tr![
                td![perfects[n].n.to_string()],//rank
				td![El::from_html(&equation)],//perfect number as a formula

                td![perfects[n].digits.to_string()],//digits in length
                td![perfects[n].discovery],//disocvery
				td![a![attrs!{At::OnClick => "",}, "Generate"]],
            ]
        );
    }

    div![
        h1!["The Perfect Numbers"],
        br![],
        br![],
        br![],
        table![
            attrs!{At::Class => "perfecttable text"},
            tbody![
                tr![
                    td![
                        b!["No."]
                    ],
                    td![
                        b!["Prime"]
                    ],
                    td![
                        b!["Digits"]
                    ],
                    td![
                        b!["Discovered"]
                    ],
                    td![
                        b!["Download"]
                    ]
                ],
                html
            ]
        ]
    ]
}

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

    #[test]
    fn perfect_test<'a>() {
        let mut perfects:Vec<perfects_utils::Perfect<'a>> = perfects_utils::perfects();
		perfects.reverse();
        assert_eq!(perfects[49].digits, 46498850);
        assert_eq!(perfects[39].digits, 12640858);
    }
}<commit_msg>Generate button, now doesn't js error<commit_after>use seed::prelude::*;
use crate::Msg;

use num_traits::{ToPrimitive};

const PERFECTS_COUNT: usize = 27;

mod perfects_utils {
	use num_bigint::{BigUint,ToBigUint};
    use seed::prelude::*;
	use crate::Model;
    use crate::Msg;

	pub struct Perfect<'a> {
		pub n: u64,
		pub p: u64,
		pub digits: u64,
		pub discovery: &'a str,
	}

	pub fn perfects<'a>() -> Vec<Perfect<'a>> {
        vec![
			/*Perfect {n: 51, p: 82589934, digits: 49724095, discovery: "2018 Laroche, Woltman, Kurowski, Blosser, et al."},
			Perfect {n: 50, p: 77232917, digits: 46498850, discovery: "2017 Jonathan Pace, George Woltman, Scott Kurowski, Aaron Blosser, et al.." },
			Perfect {n: 49, p: 74207281, digits: 44677235, discovery: "2016 Cooper, Woltman, Kurowski, Blosser et al." },
			Perfect {n: 48, p: 57885161, digits: 34850340, discovery: "2013 Cooper, Woltman, Kurowski, et al." },
			Perfect {n: 47, p: 43112609, digits: 25956377, discovery: "2008 Smith, Woltman, Kurowski, et al." },
			Perfect {n: 46, p: 42643801, digits: 42643801, discovery: "2009 Strindmo, Woltman, Kurowski, et al." },
			Perfect {n: 45, p: 37156667, digits: 22370543, discovery: "2008 Elvenich, Woltman, Kurowski, et al." },
			Perfect {n: 44, p: 32582657, digits: 19616714, discovery: "2006 Cooper, Boone, Woltman, Kurowski, et al." },
			Perfect {n: 43, p: 30402457, digits: 18304103, discovery: "2005 Cooper, Boone, Woltman, Kurowski, et al." },
			Perfect {n: 42, p: 25964951, digits: 15632458, discovery: "2005 Nowak, Woltman, Kurowski, et. al." },
			Perfect {n: 41, p: 24036583, digits: 14471465, discovery: "2004 Findley, Woltman, Kurowski, et. al." },
			Perfect {n: 40, p: 20996011, digits: 12640858, discovery: "2003 Shafer, Woltman, Kurowski, et. al." },
			Perfect {n: 39, p: 13466917, digits: 8107892, discovery: "2001 Cameron, Woltman, Kurowski, et. al." },
			Perfect {n: 38, p: 6972593, digits: 4197919, discovery: "1999 Hajratwala, Woltman, Kurowski, et. al." },
			Perfect {n: 37, p: 3021377, digits: 1819050, discovery: "1998 Clarkson, Woltman, Kurowski, et. al." },
			Perfect {n: 36, p: 2976221, digits: 1791864, discovery: "1997 Spence, Woltman, et. al." },
			Perfect {n: 35, p: 1398269, digits: 841842, discovery: "1996 Armengaud, Woltman, et. al." },
			Perfect {n: 34, p: 1257787, digits: 757263, discovery: "1996 Slowinski&Gage" },
			Perfect {n: 33, p: 859433, digits: 517430, discovery: "1994 Slowinski&Gage" },
			Perfect {n: 32, p: 756839, digits: 455663, discovery: "1992 Slowinski&Gage" },
			Perfect {n: 31, p: 216091, digits: 130100, discovery: "1985 Slowinski" },
			Perfect {n: 30, p: 132049, digits: 79502, discovery: "1983 Slowinski" },
			Perfect {n: 29, p: 110503, digits: 66530, discovery: "1988 Colquitt&Welsh" },
			Perfect {n: 28, p: 86243, digits: 51924, discovery: "1982 Slowinski" },*/
			Perfect {n: 27, p: 44497, digits: 26790, discovery: "1979 Nelson&Slowinski" },
			Perfect {n: 26, p: 23209, digits: 13973, discovery: "1979 Noll" },
			Perfect {n: 25, p: 21701, digits: 13066, discovery: "1978 Noll&Nickel" },
			Perfect {n: 24, p: 19937, digits: 12003, discovery: "1971 Tuckerman" },
			Perfect {n: 23, p: 11213, digits: 6751, discovery: "1963 Gillies" },
			Perfect {n: 22, p: 9941, digits: 5985, discovery: "1963 Gillies" },
			Perfect {n: 21, p: 9689, digits: 5834, discovery: "1963 Gillies" },
			Perfect {n: 20, p: 4423, digits: 2663, discovery: "1961 Hurwitz" },
			Perfect {n: 19, p: 4253, digits: 2561, discovery: "1961 Hurwitz" },
			Perfect {n: 18, p: 3217, digits: 1937, discovery: "1957 Riesel" },
			Perfect {n: 17, p: 2281, digits: 1373, discovery: "1952 Robinson" },
			Perfect {n: 16, p: 2203, digits: 1327, discovery: "1952 Robinson" },
			Perfect {n: 15, p: 1279, digits: 770, discovery: "1952 Robinson" },
			Perfect {n: 14, p: 607, digits: 366, discovery: "1952 Robinson" },
			Perfect {n: 13, p: 521, digits: 314, discovery: "1952 Robinson" },
			Perfect {n: 12, p: 127, digits: 77, discovery: "1876 Lucas" },
			Perfect {n: 11, p: 107, digits: 65, discovery: "1914 Powers" },
			Perfect {n: 10, p: 89, digits: 54, discovery: "1911 Powers" },
			Perfect {n: 9, p: 61, digits: 37, discovery: "1883 Pervushin" },
			Perfect {n: 8, p: 31, digits: 19, discovery: "1772 Euler" },
			Perfect {n: 7, p: 19, digits: 12, discovery: "1588 Cataldi" },
			Perfect {n: 6, p: 17, digits: 10, discovery: "1588 Cataldi" },
			Perfect {n: 5, p: 13, digits: 8, discovery: "1456 ?" },
			Perfect {n: 4, p: 7, digits: 4, discovery: "?" },
			Perfect {n: 3, p: 5, digits: 3, discovery: "?" },
			Perfect {n: 2, p: 3, digits: 2, discovery: "?" },
			Perfect {n: 1, p: 2, digits: 1, discovery: "?" },
		]
	}

	pub fn save_as_file(filename:String, filecontent:String) -> seed::dom_types::Node<Msg> {
        let href:String = vec!["data:text/plain,",&filecontent].into_iter().collect();
        a![attrs!{At::Download => &filename, At::Href => &href}, "TXT"]
    }

	pub fn generate_file(n:usize, p:usize) -> seed::dom_types::Node<Msg> {
		let download_filename:String = format!("P{}.txt",&n.to_string());
		let two:BigUint = 2.to_biguint().unwrap();
		let power:BigUint = two.clone() << (p-1-1);
        let perfect_value:BigUint = power.clone() * ((power.clone()*two.clone()) -1.to_biguint().unwrap());
        a![attrs!{At::Download => ""}, "TXT"]
    }
}

pub fn render(model: &crate::Model) -> seed::dom_types::Node<Msg> {
    let mut html = vec![];
    let mut perfects = perfects_utils::perfects();

    for n in 0..PERFECTS_COUNT {
		let equation:String = format!("2{} × (2{}-1)",&(perfects[n].p-1).to_string(),&(perfects[n].p).to_string());

		let p:usize = perfects[n].p.to_usize().unwrap();

        html.push(
            tr![
                td![perfects[n].n.to_string()],//rank
				td![El::from_html(&equation)],//perfect number as a formula

                td![perfects[n].digits.to_string()],//digits in length
                td![perfects[n].discovery],//disocvery
				td![button!["Generate",input_ev(Ev::Click, Msg::GenerateDownload)]],
            ]
        );
    }

    div![
        h1!["The Perfect Numbers"],
        br![],
        br![],
        br![],
        table![
            attrs!{At::Class => "perfecttable text"},
            tbody![
                tr![
                    td![
                        b!["No."]
                    ],
                    td![
                        b!["Prime"]
                    ],
                    td![
                        b!["Digits"]
                    ],
                    td![
                        b!["Discovered"]
                    ],
                    td![
                        b!["Download"]
                    ]
                ],
                html
            ]
        ]
    ]
}

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

    #[test]
    fn perfect_test<'a>() {
        let mut perfects:Vec<perfects_utils::Perfect<'a>> = perfects_utils::perfects();
		perfects.reverse();
        assert_eq!(perfects[49].digits, 46498850);
        assert_eq!(perfects[39].digits, 12640858);
    }
}<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

use target::Target;

pub fn target() -> Target {
    let mut base = super::draginfly_base::opts();
    base.pre_link_args.push("-m32".to_string());

    Target {
        data_layout: "e-p:32:32-f64:32:64-i64:32:64-f80:32:32-n8:16:32".to_string(),
        llvm_target: "i686-unknown-dragonfly".to_string(),
        target_endian: "little".to_string(),
        target_word_size: "32".to_string(),
        arch: "x86".to_string(),
        target_os: "dragonfly".to_string(),
        options: base,
    }
}
<commit_msg>Rename misspelled module reference.<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

use target::Target;

pub fn target() -> Target {
    let mut base = super::dragonfly_base::opts();
    base.pre_link_args.push("-m32".to_string());

    Target {
        data_layout: "e-p:32:32-f64:32:64-i64:32:64-f80:32:32-n8:16:32".to_string(),
        llvm_target: "i686-unknown-dragonfly".to_string(),
        target_endian: "little".to_string(),
        target_word_size: "32".to_string(),
        arch: "x86".to_string(),
        target_os: "dragonfly".to_string(),
        options: base,
    }
}
<|endoftext|>


<commit_before>use common::constants;

pub fn max(v1: f64, v2: f64, v3: f64) -> f64 {
  max_array(&[v1, v2, v3])
}

pub fn min(v1: f64, v2: f64, v3: f64) -> f64 {
  min_array(&[v1, v2, v3])
}

pub fn max_array(v: &[f64]) -> f64 {
  v.iter().cloned().fold(-constants::INFINITY, f64::max)
}

pub fn min_array(v: &[f64]) -> f64 {
  v.iter().cloned().fold(-constants::INFINITY, f64::min)
}
<commit_msg>add comments for util methods.<commit_after>use common::constants;

// Calculate max of three float values. Due to undefined behaviors of Inf and
// NaN, max and min of floating numbers in an array are not implemented, hereby
// we implement them.
pub fn max(v1: f64, v2: f64, v3: f64) -> f64 {
  max_array(&[v1, v2, v3])
}

// Calculate min of three float values. Due to undefined behaviors of Inf and
// NaN, max and min of floating numbers in an array are not implemented, hereby
// we implement them.
pub fn min(v1: f64, v2: f64, v3: f64) -> f64 {
  min_array(&[v1, v2, v3])
}

// Calculate max of an array of floats. Due to undefined behaviors of Inf and
// NaN, max and min of floating numbers in an array are not implemented, hereby
// we implement them.
pub fn max_array(v: &[f64]) -> f64 {
  v.iter().cloned().fold(-constants::INFINITY, f64::max)
}

// Calculate min of an array of floats. Due to undefined behaviors of Inf and
// NaN, max and min of floating numbers in an array are not implemented, hereby
// we implement them.
pub fn min_array(v: &[f64]) -> f64 {
  v.iter().cloned().fold(-constants::INFINITY, f64::min)
}
<|endoftext|>


<commit_before>use rusoto_core::signature;
use rusoto_core::signature::SignedRequest;
use rusoto_core::param::{Params, ServiceParams};
use rusoto_core::region::Region;
use rusoto_core::credential::AwsCredentials;
use generated::{GetObjectRequest, PutObjectRequest, DeleteObjectRequest};

/// URL encodes an S3 object key. This is necessary for `copy_object` and `upload_part_copy`,
/// which require the `copy_source` field to be URL encoded.
///
/// # Examples
///
/// ```
/// use rusoto_s3::CopyObjectRequest;
///
/// let request = CopyObjectRequest {
///     bucket: "my-bucket".to_owned(),
///     key: "my-key".to_owned(),
///     copy_source: rusoto_s3::util::encode_key("other-buckét/key-to-cöpy"),
///     ..Default::default()
/// };
/// ```
pub fn encode_key<T: AsRef<str>>(key: T) -> String {
    signature::encode_uri_path(key.as_ref())
}

pub enum PresignedRequestMethod {
    Get (GetObjectRequest),
    Put (PutObjectRequest),
    // Post (PostObjectRequest),
    Delete (DeleteObjectRequest),
}

/// Generate a presigned url given arguments.
///
pub fn generate_presigned_url(region: &Region, credentials: &AwsCredentials, input_request: &PresignedRequestMethod) -> String {

    macro_rules! add_headers {
        (
            $input:ident , $req:ident ; $p:ident , $e:expr ; $( $t:tt )*
        ) => (
            {
                if let Some(ref $p) = $input.$p {
                    $req.add_header($e, &$p.to_string());
                }
                add_headers! { $input, $req; $( $t )* }
            }
        );
        (
            $input:pat , $req:expr ;
        ) => ({
        });
    }

    macro_rules! add_params {
        (
            $input:ident , $params:ident ; $p:ident , $e:expr ; $( $t:tt )*
        ) => (
            {
                if let Some(ref $p) = $input.$p {
                    $params.put($e, &$p);
                }
                add_params! { $input, $params; $( $t )* }
            }
        );
        (
            $input:pat , $req:expr ;
        ) => ({
        });
    }

    match input_request {
        PresignedRequestMethod::Get(input) => {
            let request_uri = format!("/{bucket}/{key}", bucket = input.bucket, key = input.key);
            let mut request = SignedRequest::new("GET", "s3", &region, &request_uri);
            let mut params = Params::new();

            // https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectGET.html

            add_headers!(
                input, request;
                range, "Range";
                if_modified_since, "If-Modified-Since";
                if_unmodified_since, "If-Unmodified-Since";
                if_match, "If-Match";
                if_none_match, "If-None-Match";
                sse_customer_algorithm, "x-amz-server-side-encryption-customer-algorithm";
                sse_customer_key, "x-amz-server-side-encryption-customer-key";
                sse_customer_key_md5, "x-amz-server-side-encryption-customer-key-MD5";
            );

            add_params!(
                input, params;
                part_number, "partNumber";
                response_content_type, "response-content-type";
                response_content_language, "response-content-language";
                response_expires, "response-expires";
                response_cache_control, "response-cache-control";
                response_content_disposition, "response-content-disposition";
                response_content_encoding, "response-content-encoding";
                version_id, "versionId";
            );

            request.set_params(params);
            request.generate_presigned_url(&credentials)
        },
        // PresignedRequestMethod::Post(input) => {
        //     let request_uri = format!("/{bucket}/{key}", bucket = input.bucket, key = input.key);
        //     let mut request = SignedRequest::new("POST", "s3", &region, &request_uri);
        //     let mut params = Params::new();

        //     // https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPOST.html

        //     add_headers!(
        //         input, request;
        //     );
        //     add_params!(
        //         input, params;
        //     );

        //     request.set_params(params);
        //     request.generate_presigned_url(&credentials)
        // },
        PresignedRequestMethod::Put(input) => {
            let request_uri = format!("/{bucket}/{key}", bucket = input.bucket, key = input.key);
            let mut request = SignedRequest::new("PUT", "s3", &region, &request_uri);
            let mut params = Params::new();

            // https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPUT.html

            add_headers!(
                input, request;
                cache_control, "Cache-Control";
                content_disposition, "Content-Disposition";
                content_encoding, "Content-Encoding";
                content_length, "Content-Length";
                content_md5, "Content-MD5";
                content_type, "Content-Type";
                //expect, "Expect";
                expires, "Expires";
                storage_class, "x-amz-storage-class";
                tagging, "x-amz-tagging";
                website_redirect_location, "x-amz-website-redirect-location";
                acl, "x-amz-acl";
                grant_read, "x-amz-grant-read";
                //grant_write, "x-amz-grant-write";
                grant_read_acp, "x-amz-grant-read-acp";
                grant_write_acp, "x-amz-grant-write-acp";
                grant_full_control, "x-amz-grant-full-control";
                server_side_encryption, "x-amz-server-side-encryption";
                ssekms_key_id, "x-amz-server-side-encryption-aws-kms-key-id";
                //kms_context, "x-amz-server-side-encryption-context";
                sse_customer_algorithm, "x-amz-server-side-encryption-customer-algorithm";
                sse_customer_key, "x-amz-server-side-encryption-customer-key";
                sse_customer_key_md5, "x-amz-server-side-encryption-customer-key-MD5";
            );

            if let Some(ref metadata) = input.metadata {
                for (key, val) in metadata.iter() {
                    params.put(&format!("x-amz-meta-{}", key), val);
                }
            }

            add_params!(
                input, params;
            );

            request.set_params(params);
            request.generate_presigned_url(&credentials)
        },
        PresignedRequestMethod::Delete(input) => {
            let request_uri = format!("/{bucket}/{key}", bucket = input.bucket, key = input.key);
            let mut request = SignedRequest::new("DELETE", "s3", &region, &request_uri);
            let mut params = Params::new();

            // https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectDELETE.html

            add_headers!(
                input, request;
                mfa, "x-amz-mfa";
            );

            add_params!(
                input, params;
                version_id, "versionId";
            );

            request.set_params(params);
            request.generate_presigned_url(&credentials)
        },
    }
}
<commit_msg>fix test failure<commit_after>use rusoto_core::signature;
use rusoto_core::signature::SignedRequest;
use rusoto_core::param::{Params, ServiceParams};
use rusoto_core::region::Region;
use rusoto_core::credential::AwsCredentials;
use generated::{GetObjectRequest, PutObjectRequest, DeleteObjectRequest};

/// URL encodes an S3 object key. This is necessary for `copy_object` and `upload_part_copy`,
/// which require the `copy_source` field to be URL encoded.
///
/// # Examples
///
/// ```
/// use rusoto_s3::CopyObjectRequest;
///
/// let request = CopyObjectRequest {
///     bucket: "my-bucket".to_owned(),
///     key: "my-key".to_owned(),
///     copy_source: rusoto_s3::util::encode_key("other-buckét/key-to-cöpy"),
///     ..Default::default()
/// };
/// ```
pub fn encode_key<T: AsRef<str>>(key: T) -> String {
    signature::encode_uri_path(key.as_ref())
}

pub enum PresignedRequestMethod {
    Get (GetObjectRequest),
    Put (PutObjectRequest),
    // Post (PostObjectRequest),
    Delete (DeleteObjectRequest),
}

/// Generate a presigned url given arguments.
///
pub fn generate_presigned_url(region: &Region, credentials: &AwsCredentials, input_request: &PresignedRequestMethod) -> String {

    macro_rules! add_headers {
        (
            $input:ident , $req:ident ; $p:ident , $e:expr ; $( $t:tt )*
        ) => (
            {
                if let Some(ref $p) = $input.$p {
                    $req.add_header($e, &$p.to_string());
                }
                add_headers! { $input, $req; $( $t )* }
            }
        );
        (
            $input:pat , $req:expr ;
        ) => ({
        });
    }

    macro_rules! add_params {
        (
            $input:ident , $params:ident ; $p:ident , $e:expr ; $( $t:tt )*
        ) => (
            {
                if let Some(ref $p) = $input.$p {
                    $params.put($e, &$p);
                }
                add_params! { $input, $params; $( $t )* }
            }
        );
        (
            $input:pat , $req:expr ;
        ) => ({
        });
    }

    match input_request {
        PresignedRequestMethod::Get(ref input) => {
            let request_uri = format!("/{bucket}/{key}", bucket = input.bucket, key = input.key);
            let mut request = SignedRequest::new("GET", "s3", &region, &request_uri);
            let mut params = Params::new();

            // https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectGET.html

            add_headers!(
                input, request;
                range, "Range";
                if_modified_since, "If-Modified-Since";
                if_unmodified_since, "If-Unmodified-Since";
                if_match, "If-Match";
                if_none_match, "If-None-Match";
                sse_customer_algorithm, "x-amz-server-side-encryption-customer-algorithm";
                sse_customer_key, "x-amz-server-side-encryption-customer-key";
                sse_customer_key_md5, "x-amz-server-side-encryption-customer-key-MD5";
            );

            add_params!(
                input, params;
                part_number, "partNumber";
                response_content_type, "response-content-type";
                response_content_language, "response-content-language";
                response_expires, "response-expires";
                response_cache_control, "response-cache-control";
                response_content_disposition, "response-content-disposition";
                response_content_encoding, "response-content-encoding";
                version_id, "versionId";
            );

            request.set_params(params);
            request.generate_presigned_url(&credentials)
        },
        // PresignedRequestMethod::Post(ref input) => {
        //     let request_uri = format!("/{bucket}/{key}", bucket = input.bucket, key = input.key);
        //     let mut request = SignedRequest::new("POST", "s3", &region, &request_uri);
        //     let mut params = Params::new();

        //     // https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPOST.html

        //     add_headers!(
        //         input, request;
        //     );
        //     add_params!(
        //         input, params;
        //     );

        //     request.set_params(params);
        //     request.generate_presigned_url(&credentials)
        // },
        PresignedRequestMethod::Put(ref input) => {
            let request_uri = format!("/{bucket}/{key}", bucket = input.bucket, key = input.key);
            let mut request = SignedRequest::new("PUT", "s3", &region, &request_uri);
            let mut params = Params::new();

            // https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPUT.html

            add_headers!(
                input, request;
                cache_control, "Cache-Control";
                content_disposition, "Content-Disposition";
                content_encoding, "Content-Encoding";
                content_length, "Content-Length";
                content_md5, "Content-MD5";
                content_type, "Content-Type";
                //expect, "Expect";
                expires, "Expires";
                storage_class, "x-amz-storage-class";
                tagging, "x-amz-tagging";
                website_redirect_location, "x-amz-website-redirect-location";
                acl, "x-amz-acl";
                grant_read, "x-amz-grant-read";
                //grant_write, "x-amz-grant-write";
                grant_read_acp, "x-amz-grant-read-acp";
                grant_write_acp, "x-amz-grant-write-acp";
                grant_full_control, "x-amz-grant-full-control";
                server_side_encryption, "x-amz-server-side-encryption";
                ssekms_key_id, "x-amz-server-side-encryption-aws-kms-key-id";
                //kms_context, "x-amz-server-side-encryption-context";
                sse_customer_algorithm, "x-amz-server-side-encryption-customer-algorithm";
                sse_customer_key, "x-amz-server-side-encryption-customer-key";
                sse_customer_key_md5, "x-amz-server-side-encryption-customer-key-MD5";
            );

            if let Some(ref metadata) = input.metadata {
                for (key, val) in metadata.iter() {
                    params.put(&format!("x-amz-meta-{}", key), val);
                }
            }

            add_params!(
                input, params;
            );

            request.set_params(params);
            request.generate_presigned_url(&credentials)
        },
        PresignedRequestMethod::Delete(ref input) => {
            let request_uri = format!("/{bucket}/{key}", bucket = input.bucket, key = input.key);
            let mut request = SignedRequest::new("DELETE", "s3", &region, &request_uri);
            let mut params = Params::new();

            // https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectDELETE.html

            add_headers!(
                input, request;
                mfa, "x-amz-mfa";
            );

            add_params!(
                input, params;
                version_id, "versionId";
            );

            request.set_params(params);
            request.generate_presigned_url(&credentials)
        },
    }
}
<|endoftext|>


<commit_before>//! The `pact_mock_server` crate provides the CLI for the pact mock server for mocking HTTP requests
//! and generating responses based on a pact file. It implements the V3 Pact specification
//! (https://github.com/pact-foundation/pact-specification/tree/version-3).

#![warn(missing_docs)]

#[macro_use] extern crate clap;
#[macro_use] extern crate pact_matching;
extern crate pact_mock_server;
#[macro_use] extern crate log;
#[macro_use] extern crate maplit;
extern crate simplelog;
extern crate uuid;
#[macro_use] extern crate serde_json;
extern crate hyper;
extern crate rand;
extern crate webmachine_rust;
extern crate regex;
extern crate lazy_static;

#[cfg(test)]
extern crate quickcheck;

#[cfg(test)]
#[macro_use(expect)]
extern crate expectest;

use clap::{Arg, App, SubCommand, AppSettings, ErrorKind, ArgMatches};
use std::env;
use std::str::FromStr;
use std::fs::{self, File};
use std::io;
use log::{LogLevelFilter};
use simplelog::{CombinedLogger, TermLogger, WriteLogger, SimpleLogger, Config};
use std::path::PathBuf;
use std::fs::OpenOptions;
use uuid::Uuid;
use pact_matching::models::PactSpecification;

fn display_error(error: String, matches: &ArgMatches) -> ! {
    eprintln!("ERROR: {}", error);
    eprintln!();
    eprintln!("{}", matches.usage());
    panic!("{}", error)
}

mod server;
mod create_mock;
mod list;
mod verify;
mod shutdown;

fn print_version() {
    println!("\npact mock server version  : v{}", crate_version!());
    println!("pact specification version: v{}", PactSpecification::V3.version_str());
}

fn setup_log_file(output: Option<&str>) -> Result<File, io::Error> {
  let log_file = match output {
    Some(p) => {
      fs::create_dir_all(p)?;
      let mut path = PathBuf::from(p);
      path.push("pact_mock_server.log");
      path
    },
    None => PathBuf::from("pact_mock_server.log")
  };
  OpenOptions::new()
    .read(false)
    .write(true)
    .append(true)
    .create(true)
    .open(log_file)
}

fn setup_loggers(level: &str, command: &str, output: Option<&str>, no_file_log: bool, no_term_log: bool) -> Result<(), String> {
    let log_level = match level {
        "none" => LogLevelFilter::Off,
        _ => LogLevelFilter::from_str(level).unwrap()
    };

    if command == "start" {
      match (no_file_log, no_term_log) {
        (true, true) => {
          SimpleLogger::init(log_level, Config::default()).map_err(|e| format!("{:?}", e))
        },
        (true, false) => {
          TermLogger::init(log_level, Config::default()).map_err(|e| format!("{:?}", e))
        },
        (false, true) => {
          let log_file = setup_log_file(output).map_err(|e| format!("{:?}", e))?;
          WriteLogger::init(log_level, Config::default(), log_file).map_err(|e| format!("{:?}", e))
        },
        _ => {
          let log_file = setup_log_file(output).map_err(|e| format!("{:?}", e))?;
          match TermLogger::new(log_level, Config::default()) {
            Some(logger) => CombinedLogger::init(vec![logger, WriteLogger::new(log_level,
                                                                               Config::default(), log_file)]).map_err(|e| format!("{:?}", e)),
            None => WriteLogger::init(log_level, Config::default(), log_file).map_err(|e| format!("{:?}", e))
          }
        }
      }
    } else if no_term_log {
      SimpleLogger::init(log_level, Config::default()).map_err(|e| format!("{:?}", e))
    } else {
      TermLogger::init(log_level, Config::default()).map_err(|e| format!("{:?}", e))
    }
}

fn lookup_global_option<'a>(option: &str, matches: &'a ArgMatches<'a>) -> Option<&'a str> {
    let global_value = matches.value_of(option);
    let command_value = matches.subcommand().1.unwrap().value_of(option);
    match (global_value, command_value) {
        (Some(v), None) => Some(v),
        (None, Some(v)) => Some(v),
        (Some(_), Some(v)) => {
            eprintln!("WARNING: The value for '{}' has been provided twice, defaulting to the second value '{}'",
                option, v);
            Some(v)
        },
        (None, None) => None
    }
}

fn global_option_present(option: &str, matches: &ArgMatches) -> bool {
  matches.is_present(option) || matches.subcommand().1.unwrap().is_present(option)
}

fn integer_value(v: String) -> Result<(), String> {
    v.parse::<u16>().map(|_| ()).map_err(|e| format!("'{}' is not a valid port value: {}", v, e) )
}

fn uuid_value(v: String) -> Result<(), String> {
    Uuid::parse_str(v.as_str()).map(|_| ()).map_err(|e| format!("'{}' is not a valid UUID value: {}", v, e) )
}

fn main() {
    match handle_command_args() {
        Ok(_) => (),
        Err(err) => std::process::exit(err)
    }
}

fn handle_command_args() -> Result<(), i32> {
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();

    let version = format!("v{}", crate_version!());
    let app = App::new(program)
        .version(version.as_str())
        .about("Standalone Pact mock server")
        .version_short("v")
        .setting(AppSettings::ArgRequiredElseHelp)
        .setting(AppSettings::SubcommandRequired)
        .setting(AppSettings::GlobalVersion)
        .setting(AppSettings::VersionlessSubcommands)
        .setting(AppSettings::ColoredHelp)
        .arg(Arg::with_name("port")
            .short("p")
            .long("port")
            .takes_value(true)
            .use_delimiter(false)
            .global(true)
            .help("port the master mock server runs on (defaults to 8080)"))
        .arg(Arg::with_name("host")
            .short("h")
            .long("host")
            .takes_value(true)
            .use_delimiter(false)
            .global(true)
            .help("hostname the master mock server runs on (defaults to localhost)"))
        .arg(Arg::with_name("loglevel")
            .short("l")
            .long("loglevel")
            .takes_value(true)
            .use_delimiter(false)
            .global(true)
            .possible_values(&["error", "warn", "info", "debug", "trace", "none"])
            .help("Log level for mock servers to write to the log file (defaults to info)"))
        .arg(Arg::with_name("no-term-log")
          .long("no-term-log")
          .global(true)
          .help("Use a simple logger instead of the term based one"))
        .arg(Arg::with_name("no-file-log")
          .long("no-file-log")
          .global(true)
          .help("Do not log to an output file"))
        .subcommand(SubCommand::with_name("start")
                .about("Starts the master mock server")
                .arg(Arg::with_name("output")
                      .short("o")
                      .long("output")
                      .takes_value(true)
                      .use_delimiter(false)
                      .help("the directory where to write files to (defaults to current directory)"))
                .arg(Arg::with_name("base-port")
                    .long("base-port")
                    .takes_value(true)
                    .use_delimiter(false)
                    .required(false)
                    .help("the base port number that mock server ports will be allocated from. If not specified, ports will be randomly assigned by the OS.")
                    .validator(integer_value))
                .setting(AppSettings::ColoredHelp))
        .subcommand(SubCommand::with_name("list")
                .about("Lists all the running mock servers")
                .setting(AppSettings::ColoredHelp))
        .subcommand(SubCommand::with_name("create")
                .about("Creates a new mock server from a pact file")
                .arg(Arg::with_name("file")
                    .short("f")
                    .long("file")
                    .takes_value(true)
                    .use_delimiter(false)
                    .required(true)
                    .help("the pact file to define the mock server"))
                .setting(AppSettings::ColoredHelp))
        .subcommand(SubCommand::with_name("verify")
                .about("Verify the mock server by id or port number, and generate a pact file if all ok")
                .arg(Arg::with_name("mock-server-id")
                    .short("i")
                    .long("mock-server-id")
                    .takes_value(true)
                    .use_delimiter(false)
                    .required_unless("mock-server-port")
                    .conflicts_with("mock-server-port")
                    .help("the ID of the mock server")
                    .validator(uuid_value))
                .arg(Arg::with_name("mock-server-port")
                    .short("m")
                    .long("mock-server-port")
                    .takes_value(true)
                    .use_delimiter(false)
                    .required_unless("mock-server-host")
                    .help("the port number of the mock server")
                    .validator(integer_value))
                .setting(AppSettings::ColoredHelp))
        .subcommand(SubCommand::with_name("shutdown")
                .about("Shutdown the mock server by id or port number, releasing all its resources")
                .arg(Arg::with_name("mock-server-id")
                    .short("i")
                    .long("mock-server-id")
                    .takes_value(true)
                    .use_delimiter(false)
                    .required_unless("mock-server-port")
                    .conflicts_with("mock-server-port")
                    .help("the ID of the mock server")
                    .validator(uuid_value))
                .arg(Arg::with_name("mock-server-port")
                    .short("m")
                    .long("mock-server-port")
                    .takes_value(true)
                    .use_delimiter(false)
                    .required_unless("mock-server-host")
                    .help("the port number of the mock server")
                    .validator(integer_value))
                .setting(AppSettings::ColoredHelp));

    let matches = app.get_matches_safe();
    match matches {
        Ok(ref matches) => {
            let log_level = lookup_global_option("loglevel", matches);
            if let Err(err) = setup_loggers(log_level.unwrap_or("info"),
                matches.subcommand_name().unwrap(),
                matches.subcommand().1.unwrap().value_of("output"),
                global_option_present("no-file-log", matches),
                global_option_present("no-term-log", matches)) {
                eprintln!("WARN: Could not setup loggers: {}", err);
                eprintln!();
            }
            let port = lookup_global_option("port", matches).unwrap_or("8080");
            let host = lookup_global_option("host", matches).unwrap_or("localhost");
            match port.parse::<u16>() {
                Ok(p) => {
                    match matches.subcommand() {
                        ("start", Some(sub_matches)) => server::start_server(p, sub_matches),
                        ("list", Some(sub_matches)) => list::list_mock_servers(host, p, sub_matches),
                        ("create", Some(sub_matches)) => create_mock::create_mock_server(host, p, sub_matches),
                        ("verify", Some(sub_matches)) => verify::verify_mock_server(host, p, sub_matches),
                        ("shutdown", Some(sub_matches)) => shutdown::shutdown_mock_server(host, p, sub_matches),
                        _ => Err(3)
                    }
                },
                Err(_) => display_error(format!("{} is not a valid port number", port), matches)
            }
        },
        Err(ref err) => {
            match err.kind {
                ErrorKind::HelpDisplayed => {
                    println!("{}", err.message);
                    Ok(())
                },
                ErrorKind::VersionDisplayed => {
                    print_version();
                    println!();
                    Ok(())
                },
                _ => {
                    err.exit()
                }
            }
        }
    }
}

#[cfg(test)]
mod test {

    use quickcheck::{TestResult, quickcheck};
    use rand::Rng;
    use super::{integer_value, uuid_value};
    use expectest::prelude::*;

    #[test]
    fn validates_integer_value() {
        fn prop(s: String) -> TestResult {
            let mut rng = ::rand::thread_rng();
            if rng.gen() && s.chars().any(|ch| !ch.is_numeric()) {
                TestResult::discard()
            } else {
                let validation = integer_value(s.clone());
                match validation {
                    Ok(_) => TestResult::from_bool(!s.is_empty() && s.chars().all(|ch| ch.is_numeric() )),
                    Err(_) => TestResult::from_bool(s.is_empty() || s.chars().find(|ch| !ch.is_numeric() ).is_some())
                }
            }
        }
        quickcheck(prop as fn(_) -> _);

        expect!(integer_value(s!("1234"))).to(be_ok());
        expect!(integer_value(s!("1234x"))).to(be_err());
    }

    #[test]
    fn validates_uuid_value() {
        fn prop(s: String) -> TestResult {
            let mut rng = ::rand::thread_rng();
            if rng.gen() && s.chars().any(|ch| !ch.is_digit(16)) {
                TestResult::discard()
            } else {
                let validation = uuid_value(s.clone());
                match validation {
                    Ok(_) => TestResult::from_bool(!s.is_empty() && s.len() == 32 && s.chars().all(|ch| ch.is_digit(16) )),
                    Err(_) => TestResult::from_bool(s.is_empty() || s.len() != 32 || s.chars().find(|ch| !ch.is_digit(16) ).is_some())
                }
            }
        }
        quickcheck(prop as fn(_) -> _);

        expect!(uuid_value(s!("5159135ceb064af8a6baa447d81e4fbd"))).to(be_ok());
        expect!(uuid_value(s!("1234x"))).to(be_err());
    }

}
<commit_msg>fix: global options no longer incorrectly display a warning about being provided twice #27<commit_after>//! The `pact_mock_server` crate provides the CLI for the pact mock server for mocking HTTP requests
//! and generating responses based on a pact file. It implements the V3 Pact specification
//! (https://github.com/pact-foundation/pact-specification/tree/version-3).

#![warn(missing_docs)]

#[macro_use] extern crate clap;
#[macro_use] extern crate pact_matching;
extern crate pact_mock_server;
#[macro_use] extern crate log;
#[macro_use] extern crate maplit;
extern crate simplelog;
extern crate uuid;
#[macro_use] extern crate serde_json;
extern crate hyper;
extern crate rand;
extern crate webmachine_rust;
extern crate regex;
extern crate lazy_static;
#[allow(unused_imports)] #[macro_use] extern crate p_macro;

#[cfg(test)]
extern crate quickcheck;

#[cfg(test)]
#[macro_use(expect)]
extern crate expectest;

use clap::{Arg, App, SubCommand, AppSettings, ErrorKind, ArgMatches};
use std::env;
use std::str::FromStr;
use std::fs::{self, File};
use std::io;
use log::{LogLevelFilter};
use simplelog::{CombinedLogger, TermLogger, WriteLogger, SimpleLogger, Config};
use std::path::PathBuf;
use std::fs::OpenOptions;
use uuid::Uuid;
use pact_matching::models::PactSpecification;

fn display_error(error: String, matches: &ArgMatches) -> ! {
    eprintln!("ERROR: {}", error);
    eprintln!();
    eprintln!("{}", matches.usage());
    panic!("{}", error)
}

mod server;
mod create_mock;
mod list;
mod verify;
mod shutdown;

fn print_version() {
    println!("\npact mock server version  : v{}", crate_version!());
    println!("pact specification version: v{}", PactSpecification::V3.version_str());
}

fn setup_log_file(output: Option<&str>) -> Result<File, io::Error> {
  let log_file = match output {
    Some(p) => {
      fs::create_dir_all(p)?;
      let mut path = PathBuf::from(p);
      path.push("pact_mock_server.log");
      path
    },
    None => PathBuf::from("pact_mock_server.log")
  };
  OpenOptions::new()
    .read(false)
    .write(true)
    .append(true)
    .create(true)
    .open(log_file)
}

fn setup_loggers(level: &str, command: &str, output: Option<&str>, no_file_log: bool, no_term_log: bool) -> Result<(), String> {
    let log_level = match level {
        "none" => LogLevelFilter::Off,
        _ => LogLevelFilter::from_str(level).unwrap()
    };

    if command == "start" {
      match (no_file_log, no_term_log) {
        (true, true) => {
          SimpleLogger::init(log_level, Config::default()).map_err(|e| format!("{:?}", e))
        },
        (true, false) => {
          TermLogger::init(log_level, Config::default()).map_err(|e| format!("{:?}", e))
        },
        (false, true) => {
          let log_file = setup_log_file(output).map_err(|e| format!("{:?}", e))?;
          WriteLogger::init(log_level, Config::default(), log_file).map_err(|e| format!("{:?}", e))
        },
        _ => {
          let log_file = setup_log_file(output).map_err(|e| format!("{:?}", e))?;
          match TermLogger::new(log_level, Config::default()) {
            Some(logger) => CombinedLogger::init(vec![logger, WriteLogger::new(log_level,
                                                                               Config::default(), log_file)]).map_err(|e| format!("{:?}", e)),
            None => WriteLogger::init(log_level, Config::default(), log_file).map_err(|e| format!("{:?}", e))
          }
        }
      }
    } else if no_term_log {
      SimpleLogger::init(log_level, Config::default()).map_err(|e| format!("{:?}", e))
    } else {
      TermLogger::init(log_level, Config::default()).map_err(|e| format!("{:?}", e))
    }
}

fn global_option_present(option: &str, matches: &ArgMatches) -> bool {
  matches.is_present(option) || matches.subcommand().1.unwrap().is_present(option)
}

fn integer_value(v: String) -> Result<(), String> {
    v.parse::<u16>().map(|_| ()).map_err(|e| format!("'{}' is not a valid port value: {}", v, e) )
}

fn uuid_value(v: String) -> Result<(), String> {
    Uuid::parse_str(v.as_str()).map(|_| ()).map_err(|e| format!("'{}' is not a valid UUID value: {}", v, e) )
}

fn main() {
    match handle_command_args() {
        Ok(_) => (),
        Err(err) => std::process::exit(err)
    }
}

fn handle_command_args() -> Result<(), i32> {
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();

    let version = format!("v{}", crate_version!());
    let app = App::new(program)
        .version(version.as_str())
        .about("Standalone Pact mock server")
        .version_short("v")
        .setting(AppSettings::ArgRequiredElseHelp)
        .setting(AppSettings::SubcommandRequired)
        .setting(AppSettings::GlobalVersion)
        .setting(AppSettings::VersionlessSubcommands)
        .setting(AppSettings::ColoredHelp)
        .arg(Arg::with_name("port")
            .short("p")
            .long("port")
            .takes_value(true)
            .use_delimiter(false)
            .global(true)
            .help("port the master mock server runs on (defaults to 8080)"))
        .arg(Arg::with_name("host")
            .short("h")
            .long("host")
            .takes_value(true)
            .use_delimiter(false)
            .global(true)
            .help("hostname the master mock server runs on (defaults to localhost)"))
        .arg(Arg::with_name("loglevel")
            .short("l")
            .long("loglevel")
            .takes_value(true)
            .use_delimiter(false)
            .global(true)
            .possible_values(&["error", "warn", "info", "debug", "trace", "none"])
            .help("Log level for mock servers to write to the log file (defaults to info)"))
        .arg(Arg::with_name("no-term-log")
          .long("no-term-log")
          .global(true)
          .help("Use a simple logger instead of the term based one"))
        .arg(Arg::with_name("no-file-log")
          .long("no-file-log")
          .global(true)
          .help("Do not log to an output file"))
        .subcommand(SubCommand::with_name("start")
                .about("Starts the master mock server")
                .arg(Arg::with_name("output")
                      .short("o")
                      .long("output")
                      .takes_value(true)
                      .use_delimiter(false)
                      .help("the directory where to write files to (defaults to current directory)"))
                .arg(Arg::with_name("base-port")
                    .long("base-port")
                    .takes_value(true)
                    .use_delimiter(false)
                    .required(false)
                    .help("the base port number that mock server ports will be allocated from. If not specified, ports will be randomly assigned by the OS.")
                    .validator(integer_value))
                .setting(AppSettings::ColoredHelp))
        .subcommand(SubCommand::with_name("list")
                .about("Lists all the running mock servers")
                .setting(AppSettings::ColoredHelp))
        .subcommand(SubCommand::with_name("create")
                .about("Creates a new mock server from a pact file")
                .arg(Arg::with_name("file")
                    .short("f")
                    .long("file")
                    .takes_value(true)
                    .use_delimiter(false)
                    .required(true)
                    .help("the pact file to define the mock server"))
                .setting(AppSettings::ColoredHelp))
        .subcommand(SubCommand::with_name("verify")
                .about("Verify the mock server by id or port number, and generate a pact file if all ok")
                .arg(Arg::with_name("mock-server-id")
                    .short("i")
                    .long("mock-server-id")
                    .takes_value(true)
                    .use_delimiter(false)
                    .required_unless("mock-server-port")
                    .conflicts_with("mock-server-port")
                    .help("the ID of the mock server")
                    .validator(uuid_value))
                .arg(Arg::with_name("mock-server-port")
                    .short("m")
                    .long("mock-server-port")
                    .takes_value(true)
                    .use_delimiter(false)
                    .required_unless("mock-server-host")
                    .help("the port number of the mock server")
                    .validator(integer_value))
                .setting(AppSettings::ColoredHelp))
        .subcommand(SubCommand::with_name("shutdown")
                .about("Shutdown the mock server by id or port number, releasing all its resources")
                .arg(Arg::with_name("mock-server-id")
                    .short("i")
                    .long("mock-server-id")
                    .takes_value(true)
                    .use_delimiter(false)
                    .required_unless("mock-server-port")
                    .conflicts_with("mock-server-port")
                    .help("the ID of the mock server")
                    .validator(uuid_value))
                .arg(Arg::with_name("mock-server-port")
                    .short("m")
                    .long("mock-server-port")
                    .takes_value(true)
                    .use_delimiter(false)
                    .required_unless("mock-server-host")
                    .help("the port number of the mock server")
                    .validator(integer_value))
                .setting(AppSettings::ColoredHelp));

    let matches = app.get_matches_safe();
    match matches {
        Ok(ref matches) => {
            let log_level = matches.value_of("loglevel");
            if let Err(err) = setup_loggers(log_level.unwrap_or("info"),
                matches.subcommand_name().unwrap(),
                matches.subcommand().1.unwrap().value_of("output"),
                global_option_present("no-file-log", matches),
                global_option_present("no-term-log", matches)) {
                eprintln!("WARN: Could not setup loggers: {}", err);
                eprintln!();
            }
            let port = matches.value_of("port").unwrap_or("8080");
            let host = matches.value_of("host").unwrap_or("localhost");
            match port.parse::<u16>() {
                Ok(p) => {
                    match matches.subcommand() {
                        ("start", Some(sub_matches)) => server::start_server(p, sub_matches),
                        ("list", Some(sub_matches)) => list::list_mock_servers(host, p, sub_matches),
                        ("create", Some(sub_matches)) => create_mock::create_mock_server(host, p, sub_matches),
                        ("verify", Some(sub_matches)) => verify::verify_mock_server(host, p, sub_matches),
                        ("shutdown", Some(sub_matches)) => shutdown::shutdown_mock_server(host, p, sub_matches),
                        _ => Err(3)
                    }
                },
                Err(_) => display_error(format!("{} is not a valid port number", port), matches)
            }
        },
        Err(ref err) => {
            match err.kind {
                ErrorKind::HelpDisplayed => {
                    println!("{}", err.message);
                    Ok(())
                },
                ErrorKind::VersionDisplayed => {
                    print_version();
                    println!();
                    Ok(())
                },
                _ => {
                    err.exit()
                }
            }
        }
    }
}

#[cfg(test)]
mod test {

    use quickcheck::{TestResult, quickcheck};
    use rand::Rng;
    use super::{integer_value, uuid_value};
    use expectest::prelude::*;

    #[test]
    fn validates_integer_value() {
        fn prop(s: String) -> TestResult {
            let mut rng = ::rand::thread_rng();
            if rng.gen() && s.chars().any(|ch| !ch.is_numeric()) {
                TestResult::discard()
            } else {
                let validation = integer_value(s.clone());
                match validation {
                    Ok(_) => TestResult::from_bool(!s.is_empty() && s.chars().all(|ch| ch.is_numeric() )),
                    Err(_) => TestResult::from_bool(s.is_empty() || s.chars().find(|ch| !ch.is_numeric() ).is_some())
                }
            }
        }
        quickcheck(prop as fn(_) -> _);

        expect!(integer_value(s!("1234"))).to(be_ok());
        expect!(integer_value(s!("1234x"))).to(be_err());
    }

    #[test]
    fn validates_uuid_value() {
        fn prop(s: String) -> TestResult {
            let mut rng = ::rand::thread_rng();
            if rng.gen() && s.chars().any(|ch| !ch.is_digit(16)) {
                TestResult::discard()
            } else {
                let validation = uuid_value(s.clone());
                match validation {
                    Ok(_) => TestResult::from_bool(!s.is_empty() && s.len() == 32 && s.chars().all(|ch| ch.is_digit(16) )),
                    Err(_) => TestResult::from_bool(s.is_empty() || s.len() != 32 || s.chars().find(|ch| !ch.is_digit(16) ).is_some())
                }
            }
        }
        quickcheck(prop as fn(_) -> _);

        expect!(uuid_value(s!("5159135ceb064af8a6baa447d81e4fbd"))).to(be_ok());
        expect!(uuid_value(s!("1234x"))).to(be_err());
    }

}
<|endoftext|>


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

use crate::chained_bft::{
    common::{Author, Round},
    consensus_types::{sync_info::SyncInfo, vote_msg::VoteMsg},
};
use canonical_serialization::{CanonicalSerialize, CanonicalSerializer, SimpleSerializer};
use crypto::{
    hash::{CryptoHash, CryptoHasher, PacemakerTimeoutHasher, TimeoutMsgHasher},
    HashValue,
};
use failure::prelude::*;
use mirai_annotations::assumed_postcondition;
use network;
use proto_conv::{FromProto, IntoProto};
use protobuf::RepeatedField;
use serde::{Deserialize, Serialize};
use std::{collections::HashSet, convert::TryFrom, fmt, iter::FromIterator};
use types::{
    account_address::AccountAddress,
    crypto_proxies::{Signature, ValidatorSigner, ValidatorVerifier},
};

// Internal use only. Contains all the fields in PaceMakerTimeout that contributes to the
// computation of its hash.
struct PacemakerTimeoutSerializer {
    round: Round,
    author: Author,
}

impl CanonicalSerialize for PacemakerTimeoutSerializer {
    fn serialize(&self, serializer: &mut impl CanonicalSerializer) -> failure::Result<()> {
        serializer.encode_u64(self.round)?;
        serializer.encode_struct(&self.author)?;
        Ok(())
    }
}

impl CryptoHash for PacemakerTimeoutSerializer {
    type Hasher = PacemakerTimeoutHasher;

    fn hash(&self) -> HashValue {
        let mut state = Self::Hasher::default();
        state.write(&SimpleSerializer::<Vec<u8>>::serialize(self).expect("Should serialize."));
        state.finish()
    }
}

/// This message will be broadcast by a pacemaker as part of TimeoutMsg when its local
/// timeout for a round is reached.  Once f+1 PacemakerTimeout structs
/// from unique authors is gathered it forms a TimeoutCertificate.  A TimeoutCertificate is
/// a proof that will cause a replica to advance to the minimum round in the TimeoutCertificate.
#[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Eq)]
pub struct PacemakerTimeout {
    round: Round,
    author: Author,
    signature: Signature,
    vote: Option<VoteMsg>,
}

impl PacemakerTimeout {
    /// Creates new PacemakerTimeout
    pub fn new(round: Round, validator_signer: &ValidatorSigner, vote: Option<VoteMsg>) -> Self {
        let author = validator_signer.author();
        let digest = PacemakerTimeoutSerializer { round, author }.hash();
        let signature = validator_signer
            .sign_message(digest)
            .expect("Failed to sign PacemakerTimeout");
        PacemakerTimeout {
            round,
            author,
            signature: signature.into(),
            vote,
        }
    }

    fn pacemaker_timeout_digest(author: AccountAddress, round: Round) -> HashValue {
        PacemakerTimeoutSerializer { round, author }.hash()
    }

    /// Calculates digest for this struct
    pub fn digest(&self) -> HashValue {
        Self::pacemaker_timeout_digest(self.author, self.round)
    }

    pub fn round(&self) -> Round {
        self.round
    }

    pub fn vote_msg(&self) -> Option<&VoteMsg> {
        self.vote.as_ref()
    }

    /// Verifies that this message has valid signature
    pub fn verify(&self, validator: &ValidatorVerifier) -> failure::Result<()> {
        self.signature
            .verify(validator, self.author, self.digest())
            .map_err(Error::from)
            .and_then(|_| {
                if let Some(vote) = self.vote.as_ref() {
                    vote.verify(validator)?;
                }
                Ok(())
            })
            .with_context(|e| format!("Fail to verify TimeoutMsg: {:?}", e))?;
        Ok(())
    }

    /// Returns the author of the timeout
    pub fn author(&self) -> Author {
        self.author
    }

    /// Returns the signature of the author for this timeout
    pub fn signature(&self) -> &Signature {
        &self.signature
    }
}

impl IntoProto for PacemakerTimeout {
    type ProtoType = network::proto::PacemakerTimeout;

    fn into_proto(self) -> Self::ProtoType {
        let mut proto = Self::ProtoType::new();
        proto.set_round(self.round);
        proto.set_author(self.author.into());
        proto.set_signature(bytes::Bytes::from(self.signature.to_bytes()));
        if let Some(vote) = self.vote {
            proto.set_vote(vote.into_proto());
        }
        proto
    }
}

impl FromProto for PacemakerTimeout {
    type ProtoType = network::proto::PacemakerTimeout;

    fn from_proto(mut object: Self::ProtoType) -> failure::Result<Self> {
        let round = object.get_round();
        let author = Author::try_from(object.take_author())?;
        let signature = Signature::try_from(object.get_signature())?;
        let vote = if let Some(vote_msg) = object.vote.into_option() {
            Some(VoteMsg::from_proto(vote_msg)?)
        } else {
            None
        };
        Ok(PacemakerTimeout {
            round,
            author,
            signature,
            vote,
        })
    }
}

impl TryFrom<network::proto::consensus_prost::PacemakerTimeout> for PacemakerTimeout {
    type Error = failure::Error;

    fn try_from(proto: network::proto::consensus_prost::PacemakerTimeout) -> failure::Result<Self> {
        let round = proto.round;
        let author = Author::try_from(&proto.author[..])?;
        let signature = Signature::try_from(&proto.signature)?;
        let vote = if let Some(vote_msg) = proto.vote {
            Some(VoteMsg::try_from(vote_msg)?)
        } else {
            None
        };
        Ok(PacemakerTimeout {
            round,
            author,
            signature,
            vote,
        })
    }
}

impl From<PacemakerTimeout> for network::proto::consensus_prost::PacemakerTimeout {
    fn from(timeout: PacemakerTimeout) -> Self {
        Self {
            round: timeout.round,
            author: timeout.author.to_vec(),
            signature: timeout.signature.to_bytes(),
            vote: timeout.vote.map(Into::into),
        }
    }
}

// Internal use only. Contains all the fields in TimeoutMsg that contributes to the computation of
// its hash.
struct TimeoutMsgSerializer {
    pacemaker_timeout_digest: HashValue,
}

impl CanonicalSerialize for TimeoutMsgSerializer {
    fn serialize(&self, serializer: &mut impl CanonicalSerializer) -> failure::Result<()> {
        serializer.encode_bytes(self.pacemaker_timeout_digest.as_ref())?;
        Ok(())
    }
}

impl CryptoHash for TimeoutMsgSerializer {
    type Hasher = TimeoutMsgHasher;

    fn hash(&self) -> HashValue {
        let mut state = Self::Hasher::default();
        state.write(&SimpleSerializer::<Vec<u8>>::serialize(self).expect("Should serialize."));
        state.finish()
    }
}

/// This message will be broadcast by a pacemaker when its local timeout for a round is reached.
/// Once the broadcasts start, retries will continue for every timeout until the round changes.
/// Retries are required since, say if a proposer for a round r was unresponsive, it might not
/// propose if it misses even only one PacemakerTimeoutMsg.
///
/// The expected proposer will wait until n-f such messages are received before proposing to
/// ensure liveness (a next proposal has the highest quorum certificate across all replicas
/// as justification). If the expected proposer has a quorum certificate on round r-1, it need
/// not wait until n-f such messages are received and can make a proposal justified
/// by this quorum certificate.
#[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Eq)]
pub struct TimeoutMsg {
    sync_info: SyncInfo,
    pacemaker_timeout: PacemakerTimeout,
    signature: Signature,
}

impl TimeoutMsg {
    /// Creates new TimeoutMsg
    pub fn new(
        sync_info: SyncInfo,
        pacemaker_timeout: PacemakerTimeout,
        validator_signer: &ValidatorSigner,
    ) -> TimeoutMsg {
        let digest = Self::new_round_digest(pacemaker_timeout.digest());
        let signature = validator_signer
            .sign_message(digest)
            .expect("Failed to sign PacemakerTimeoutMsg");
        TimeoutMsg {
            sync_info,
            pacemaker_timeout,
            signature: signature.into(),
        }
    }

    fn new_round_digest(pacemaker_timeout_digest: HashValue) -> HashValue {
        TimeoutMsgSerializer {
            pacemaker_timeout_digest,
        }
        .hash()
    }

    /// SyncInfo of the given timeout message
    pub fn sync_info(&self) -> &SyncInfo {
        &self.sync_info
    }

    /// Returns a reference to the included PacemakerTimeout
    pub fn pacemaker_timeout(&self) -> &PacemakerTimeout {
        &self.pacemaker_timeout
    }

    /// Verifies that this message has valid signature
    pub fn verify(&self, validator: &ValidatorVerifier) -> failure::Result<()> {
        self.pacemaker_timeout.verify(validator)
    }

    /// Returns the author of the TimeoutMsg
    pub fn author(&self) -> Author {
        self.pacemaker_timeout.author()
    }

    /// Returns a reference to the signature of the author
    #[allow(dead_code)]
    pub fn signature(&self) -> &Signature {
        &self.signature
    }
}

impl FromProto for TimeoutMsg {
    type ProtoType = network::proto::TimeoutMsg;

    fn from_proto(mut object: network::proto::TimeoutMsg) -> failure::Result<Self> {
        let sync_info = SyncInfo::from_proto(object.take_sync_info())?;
        let pacemaker_timeout = PacemakerTimeout::from_proto(object.take_pacemaker_timeout())?;
        let signature = Signature::try_from(object.get_signature())?;
        Ok(TimeoutMsg {
            sync_info,
            pacemaker_timeout,
            signature,
        })
    }
}

impl IntoProto for TimeoutMsg {
    type ProtoType = network::proto::TimeoutMsg;

    fn into_proto(self) -> Self::ProtoType {
        let mut proto = Self::ProtoType::new();
        proto.set_sync_info(self.sync_info.into_proto());
        proto.set_pacemaker_timeout(self.pacemaker_timeout.into_proto());
        proto.set_signature(bytes::Bytes::from(self.signature.to_bytes()));
        proto
    }
}

#[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Eq)]
/// Proposal can include this timeout certificate as justification for switching to next round
pub struct PacemakerTimeoutCertificate {
    round: Round,
    timeouts: Vec<PacemakerTimeout>,
}

impl fmt::Display for PacemakerTimeoutCertificate {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "TimeoutCertificate[round: {}, timeouts:[", self.round)?;
        for (idx, timeout) in self.timeouts.iter().enumerate() {
            write!(f, "<{}>", timeout.round())?;
            if idx != self.timeouts.len() - 1 {
                write!(f, ", ")?;
            }
        }
        write!(f, "]")
    }
}

impl PacemakerTimeoutCertificate {
    /// Creates new PacemakerTimeoutCertificate
    pub fn new(round: Round, timeouts: Vec<PacemakerTimeout>) -> PacemakerTimeoutCertificate {
        PacemakerTimeoutCertificate { round, timeouts }
    }

    /// Verifies that timeouts in message actually certify the round
    pub fn verify(&self, validator: &ValidatorVerifier) -> failure::Result<()> {
        let mut min_round: Option<Round> = None;
        let mut unique_authors = HashSet::new();
        for timeout in &self.timeouts {
            timeout
                .signature()
                .verify(validator, timeout.author(), timeout.digest())
                .with_context(|e| format!("Fail to verify TimeoutCert: {:?}", e))?;
            unique_authors.insert(timeout.author());
            let timeout_round = timeout.round();
            min_round = Some(min_round.map_or(timeout_round, move |x| x.min(timeout_round)))
        }
        validator.check_voting_power(unique_authors.iter())?;
        ensure!(
            min_round == Some(self.round),
            "TimeoutCert has inconsistent round {}, expected: {:?}",
            self.round,
            min_round
        );
        Ok(())
    }

    /// Returns the round of the timeout
    pub fn round(&self) -> Round {
        // Round numbers:
        // - are reset to 0 periodically.
        // - do not exceed std::u64::MAX - 2 per the 3 chain safety rule
        // (ConsensusState::commit_rule_for_certified_block)
        assumed_postcondition!(self.round < std::u64::MAX - 1);
        self.round
    }

    /// Returns the timeouts that certify the PacemakerTimeoutCertificate
    pub fn timeouts(&self) -> &Vec<PacemakerTimeout> {
        &self.timeouts
    }
}

impl IntoProto for PacemakerTimeoutCertificate {
    type ProtoType = network::proto::PacemakerTimeoutCertificate;

    fn into_proto(self) -> Self::ProtoType {
        let mut proto = Self::ProtoType::new();
        proto.set_timeouts(RepeatedField::from_iter(
            self.timeouts.into_iter().map(PacemakerTimeout::into_proto),
        ));
        proto.set_round(self.round);
        proto
    }
}

impl FromProto for PacemakerTimeoutCertificate {
    type ProtoType = network::proto::PacemakerTimeoutCertificate;

    fn from_proto(mut object: Self::ProtoType) -> failure::Result<Self> {
        let timeouts = object
            .take_timeouts()
            .into_iter()
            .map(PacemakerTimeout::from_proto)
            .collect::<failure::Result<Vec<_>>>()?;
        Ok(PacemakerTimeoutCertificate::new(
            object.get_round(),
            timeouts,
        ))
    }
}
<commit_msg>[consensus] impl conversions from/to prost proto and PacemakerTimeoutCertificate<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::chained_bft::{
    common::{Author, Round},
    consensus_types::{sync_info::SyncInfo, vote_msg::VoteMsg},
};
use canonical_serialization::{CanonicalSerialize, CanonicalSerializer, SimpleSerializer};
use crypto::{
    hash::{CryptoHash, CryptoHasher, PacemakerTimeoutHasher, TimeoutMsgHasher},
    HashValue,
};
use failure::prelude::*;
use mirai_annotations::assumed_postcondition;
use network;
use proto_conv::{FromProto, IntoProto};
use protobuf::RepeatedField;
use serde::{Deserialize, Serialize};
use std::{collections::HashSet, convert::TryFrom, fmt, iter::FromIterator};
use types::{
    account_address::AccountAddress,
    crypto_proxies::{Signature, ValidatorSigner, ValidatorVerifier},
};

// Internal use only. Contains all the fields in PaceMakerTimeout that contributes to the
// computation of its hash.
struct PacemakerTimeoutSerializer {
    round: Round,
    author: Author,
}

impl CanonicalSerialize for PacemakerTimeoutSerializer {
    fn serialize(&self, serializer: &mut impl CanonicalSerializer) -> failure::Result<()> {
        serializer.encode_u64(self.round)?;
        serializer.encode_struct(&self.author)?;
        Ok(())
    }
}

impl CryptoHash for PacemakerTimeoutSerializer {
    type Hasher = PacemakerTimeoutHasher;

    fn hash(&self) -> HashValue {
        let mut state = Self::Hasher::default();
        state.write(&SimpleSerializer::<Vec<u8>>::serialize(self).expect("Should serialize."));
        state.finish()
    }
}

/// This message will be broadcast by a pacemaker as part of TimeoutMsg when its local
/// timeout for a round is reached.  Once f+1 PacemakerTimeout structs
/// from unique authors is gathered it forms a TimeoutCertificate.  A TimeoutCertificate is
/// a proof that will cause a replica to advance to the minimum round in the TimeoutCertificate.
#[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Eq)]
pub struct PacemakerTimeout {
    round: Round,
    author: Author,
    signature: Signature,
    vote: Option<VoteMsg>,
}

impl PacemakerTimeout {
    /// Creates new PacemakerTimeout
    pub fn new(round: Round, validator_signer: &ValidatorSigner, vote: Option<VoteMsg>) -> Self {
        let author = validator_signer.author();
        let digest = PacemakerTimeoutSerializer { round, author }.hash();
        let signature = validator_signer
            .sign_message(digest)
            .expect("Failed to sign PacemakerTimeout");
        PacemakerTimeout {
            round,
            author,
            signature: signature.into(),
            vote,
        }
    }

    fn pacemaker_timeout_digest(author: AccountAddress, round: Round) -> HashValue {
        PacemakerTimeoutSerializer { round, author }.hash()
    }

    /// Calculates digest for this struct
    pub fn digest(&self) -> HashValue {
        Self::pacemaker_timeout_digest(self.author, self.round)
    }

    pub fn round(&self) -> Round {
        self.round
    }

    pub fn vote_msg(&self) -> Option<&VoteMsg> {
        self.vote.as_ref()
    }

    /// Verifies that this message has valid signature
    pub fn verify(&self, validator: &ValidatorVerifier) -> failure::Result<()> {
        self.signature
            .verify(validator, self.author, self.digest())
            .map_err(Error::from)
            .and_then(|_| {
                if let Some(vote) = self.vote.as_ref() {
                    vote.verify(validator)?;
                }
                Ok(())
            })
            .with_context(|e| format!("Fail to verify TimeoutMsg: {:?}", e))?;
        Ok(())
    }

    /// Returns the author of the timeout
    pub fn author(&self) -> Author {
        self.author
    }

    /// Returns the signature of the author for this timeout
    pub fn signature(&self) -> &Signature {
        &self.signature
    }
}

impl IntoProto for PacemakerTimeout {
    type ProtoType = network::proto::PacemakerTimeout;

    fn into_proto(self) -> Self::ProtoType {
        let mut proto = Self::ProtoType::new();
        proto.set_round(self.round);
        proto.set_author(self.author.into());
        proto.set_signature(bytes::Bytes::from(self.signature.to_bytes()));
        if let Some(vote) = self.vote {
            proto.set_vote(vote.into_proto());
        }
        proto
    }
}

impl FromProto for PacemakerTimeout {
    type ProtoType = network::proto::PacemakerTimeout;

    fn from_proto(mut object: Self::ProtoType) -> failure::Result<Self> {
        let round = object.get_round();
        let author = Author::try_from(object.take_author())?;
        let signature = Signature::try_from(object.get_signature())?;
        let vote = if let Some(vote_msg) = object.vote.into_option() {
            Some(VoteMsg::from_proto(vote_msg)?)
        } else {
            None
        };
        Ok(PacemakerTimeout {
            round,
            author,
            signature,
            vote,
        })
    }
}

impl TryFrom<network::proto::consensus_prost::PacemakerTimeout> for PacemakerTimeout {
    type Error = failure::Error;

    fn try_from(proto: network::proto::consensus_prost::PacemakerTimeout) -> failure::Result<Self> {
        let round = proto.round;
        let author = Author::try_from(&proto.author[..])?;
        let signature = Signature::try_from(&proto.signature)?;
        let vote = if let Some(vote_msg) = proto.vote {
            Some(VoteMsg::try_from(vote_msg)?)
        } else {
            None
        };
        Ok(PacemakerTimeout {
            round,
            author,
            signature,
            vote,
        })
    }
}

impl From<PacemakerTimeout> for network::proto::consensus_prost::PacemakerTimeout {
    fn from(timeout: PacemakerTimeout) -> Self {
        Self {
            round: timeout.round,
            author: timeout.author.to_vec(),
            signature: timeout.signature.to_bytes(),
            vote: timeout.vote.map(Into::into),
        }
    }
}

// Internal use only. Contains all the fields in TimeoutMsg that contributes to the computation of
// its hash.
struct TimeoutMsgSerializer {
    pacemaker_timeout_digest: HashValue,
}

impl CanonicalSerialize for TimeoutMsgSerializer {
    fn serialize(&self, serializer: &mut impl CanonicalSerializer) -> failure::Result<()> {
        serializer.encode_bytes(self.pacemaker_timeout_digest.as_ref())?;
        Ok(())
    }
}

impl CryptoHash for TimeoutMsgSerializer {
    type Hasher = TimeoutMsgHasher;

    fn hash(&self) -> HashValue {
        let mut state = Self::Hasher::default();
        state.write(&SimpleSerializer::<Vec<u8>>::serialize(self).expect("Should serialize."));
        state.finish()
    }
}

/// This message will be broadcast by a pacemaker when its local timeout for a round is reached.
/// Once the broadcasts start, retries will continue for every timeout until the round changes.
/// Retries are required since, say if a proposer for a round r was unresponsive, it might not
/// propose if it misses even only one PacemakerTimeoutMsg.
///
/// The expected proposer will wait until n-f such messages are received before proposing to
/// ensure liveness (a next proposal has the highest quorum certificate across all replicas
/// as justification). If the expected proposer has a quorum certificate on round r-1, it need
/// not wait until n-f such messages are received and can make a proposal justified
/// by this quorum certificate.
#[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Eq)]
pub struct TimeoutMsg {
    sync_info: SyncInfo,
    pacemaker_timeout: PacemakerTimeout,
    signature: Signature,
}

impl TimeoutMsg {
    /// Creates new TimeoutMsg
    pub fn new(
        sync_info: SyncInfo,
        pacemaker_timeout: PacemakerTimeout,
        validator_signer: &ValidatorSigner,
    ) -> TimeoutMsg {
        let digest = Self::new_round_digest(pacemaker_timeout.digest());
        let signature = validator_signer
            .sign_message(digest)
            .expect("Failed to sign PacemakerTimeoutMsg");
        TimeoutMsg {
            sync_info,
            pacemaker_timeout,
            signature: signature.into(),
        }
    }

    fn new_round_digest(pacemaker_timeout_digest: HashValue) -> HashValue {
        TimeoutMsgSerializer {
            pacemaker_timeout_digest,
        }
        .hash()
    }

    /// SyncInfo of the given timeout message
    pub fn sync_info(&self) -> &SyncInfo {
        &self.sync_info
    }

    /// Returns a reference to the included PacemakerTimeout
    pub fn pacemaker_timeout(&self) -> &PacemakerTimeout {
        &self.pacemaker_timeout
    }

    /// Verifies that this message has valid signature
    pub fn verify(&self, validator: &ValidatorVerifier) -> failure::Result<()> {
        self.pacemaker_timeout.verify(validator)
    }

    /// Returns the author of the TimeoutMsg
    pub fn author(&self) -> Author {
        self.pacemaker_timeout.author()
    }

    /// Returns a reference to the signature of the author
    #[allow(dead_code)]
    pub fn signature(&self) -> &Signature {
        &self.signature
    }
}

impl FromProto for TimeoutMsg {
    type ProtoType = network::proto::TimeoutMsg;

    fn from_proto(mut object: network::proto::TimeoutMsg) -> failure::Result<Self> {
        let sync_info = SyncInfo::from_proto(object.take_sync_info())?;
        let pacemaker_timeout = PacemakerTimeout::from_proto(object.take_pacemaker_timeout())?;
        let signature = Signature::try_from(object.get_signature())?;
        Ok(TimeoutMsg {
            sync_info,
            pacemaker_timeout,
            signature,
        })
    }
}

impl IntoProto for TimeoutMsg {
    type ProtoType = network::proto::TimeoutMsg;

    fn into_proto(self) -> Self::ProtoType {
        let mut proto = Self::ProtoType::new();
        proto.set_sync_info(self.sync_info.into_proto());
        proto.set_pacemaker_timeout(self.pacemaker_timeout.into_proto());
        proto.set_signature(bytes::Bytes::from(self.signature.to_bytes()));
        proto
    }
}

#[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Eq)]
/// Proposal can include this timeout certificate as justification for switching to next round
pub struct PacemakerTimeoutCertificate {
    round: Round,
    timeouts: Vec<PacemakerTimeout>,
}

impl fmt::Display for PacemakerTimeoutCertificate {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "TimeoutCertificate[round: {}, timeouts:[", self.round)?;
        for (idx, timeout) in self.timeouts.iter().enumerate() {
            write!(f, "<{}>", timeout.round())?;
            if idx != self.timeouts.len() - 1 {
                write!(f, ", ")?;
            }
        }
        write!(f, "]")
    }
}

impl PacemakerTimeoutCertificate {
    /// Creates new PacemakerTimeoutCertificate
    pub fn new(round: Round, timeouts: Vec<PacemakerTimeout>) -> PacemakerTimeoutCertificate {
        PacemakerTimeoutCertificate { round, timeouts }
    }

    /// Verifies that timeouts in message actually certify the round
    pub fn verify(&self, validator: &ValidatorVerifier) -> failure::Result<()> {
        let mut min_round: Option<Round> = None;
        let mut unique_authors = HashSet::new();
        for timeout in &self.timeouts {
            timeout
                .signature()
                .verify(validator, timeout.author(), timeout.digest())
                .with_context(|e| format!("Fail to verify TimeoutCert: {:?}", e))?;
            unique_authors.insert(timeout.author());
            let timeout_round = timeout.round();
            min_round = Some(min_round.map_or(timeout_round, move |x| x.min(timeout_round)))
        }
        validator.check_voting_power(unique_authors.iter())?;
        ensure!(
            min_round == Some(self.round),
            "TimeoutCert has inconsistent round {}, expected: {:?}",
            self.round,
            min_round
        );
        Ok(())
    }

    /// Returns the round of the timeout
    pub fn round(&self) -> Round {
        // Round numbers:
        // - are reset to 0 periodically.
        // - do not exceed std::u64::MAX - 2 per the 3 chain safety rule
        // (ConsensusState::commit_rule_for_certified_block)
        assumed_postcondition!(self.round < std::u64::MAX - 1);
        self.round
    }

    /// Returns the timeouts that certify the PacemakerTimeoutCertificate
    pub fn timeouts(&self) -> &Vec<PacemakerTimeout> {
        &self.timeouts
    }
}

impl IntoProto for PacemakerTimeoutCertificate {
    type ProtoType = network::proto::PacemakerTimeoutCertificate;

    fn into_proto(self) -> Self::ProtoType {
        let mut proto = Self::ProtoType::new();
        proto.set_timeouts(RepeatedField::from_iter(
            self.timeouts.into_iter().map(PacemakerTimeout::into_proto),
        ));
        proto.set_round(self.round);
        proto
    }
}

impl FromProto for PacemakerTimeoutCertificate {
    type ProtoType = network::proto::PacemakerTimeoutCertificate;

    fn from_proto(mut object: Self::ProtoType) -> failure::Result<Self> {
        let timeouts = object
            .take_timeouts()
            .into_iter()
            .map(PacemakerTimeout::from_proto)
            .collect::<failure::Result<Vec<_>>>()?;
        Ok(PacemakerTimeoutCertificate::new(
            object.get_round(),
            timeouts,
        ))
    }
}

impl TryFrom<network::proto::consensus_prost::PacemakerTimeoutCertificate>
    for PacemakerTimeoutCertificate
{
    type Error = failure::Error;

    fn try_from(
        proto: network::proto::consensus_prost::PacemakerTimeoutCertificate,
    ) -> failure::Result<Self> {
        let timeouts = proto
            .timeouts
            .into_iter()
            .map(PacemakerTimeout::try_from)
            .collect::<failure::Result<Vec<_>>>()?;
        Ok(PacemakerTimeoutCertificate::new(proto.round, timeouts))
    }
}

impl From<PacemakerTimeoutCertificate>
    for network::proto::consensus_prost::PacemakerTimeoutCertificate
{
    fn from(timeout: PacemakerTimeoutCertificate) -> Self {
        Self {
            round: timeout.round,
            timeouts: timeout.timeouts.into_iter().map(Into::into).collect(),
        }
    }
}
<|endoftext|>