<commit_before>#![warn(clippy::all)]

#[macro_use]
extern crate serenity;

use std::io;
use stalch::{run_with_state, InOuter, State, Result as StalchResult};

use std::env;
use std::io::Read;
use std::result::Result as StdResult;
use typemap::Key;

use rand::Rng;
use rand::thread_rng;

use serenity::prelude::*;
use serenity::model::*;
use serenity::Result;
use serenity::utils;

use serenity::framework::StandardFramework;

const PREFIX: &str = "]";
#[allow(clippy::unreadable_literal)]
const WESTMANN: UserId = UserId(229154015626264577);
#[allow(clippy::unreadable_literal)]
const FALCH: UserId = UserId(165877785544491008);
#[allow(clippy::unreadable_literal)]
const MEMES: ChannelId = ChannelId(306454829738491904);
#[allow(clippy::unreadable_literal)]
const FALCHATS: GuildId = GuildId(189120762659995648);

command!(info(_ctx, msg, _args) {
    msg.channel_id.send_message(|cm| {
        cm.embed(|e| {
            e.title("falchbot")
             .colour(utils::Colour::blue())
             .description("(c) LFalch.com 2018")
             .footer(|f| f.text(serenity::constants::USER_AGENT))
        })
    }).unwrap();
});

command!(setgame(ctx, msg, args) {
    if msg.author.id == FALCH {
        ctx.set_game(Game::playing(&args.join(" ")));
    } else {
        msg.reply("Unauthorised")?;
    }
});

command!(seticon(_ctx, msg, args) {
    let s = args.join("/");

    if msg.author.id == FALCH {
        let img = {
            let client = hyper::Client::new();
            let mut resp = client.get(&format!("http://dev.lfalch.com/{}.png", s)).send()?;
            if !resp.status.is_success() {
                msg.reply("No success")?;
                return Ok(());
            }

            let mut v = Vec::new();

            resp.read_to_end(&mut v)?;

            let b64 = base64::encode(&v);
            let ext = "png";

            format!("data:image/{};base64,{}", ext, b64)
        };

        FALCHATS.edit(|e| e.icon(Some(&img)))?;
    } else {
        msg.reply("Unauthorised")?;
    }
});

command!(rpn(_ctx, msg, args) {
    match calculate(&*args) {
        Ok(r) => msg.reply(&format!("Result: {}", r)),
        Err(e) => msg.reply(&format!("Error: {:?}", e))
    }?;
});

command!(stalch(_ctx, msg, args) {
    match stalch_run(&(args.join(" ") + "\n")) {
        Ok((r, s)) => {
            if r.is_empty() {
                msg.reply(&format!("Stack:\n```\n{}\n```", s))
            } else {
                msg.reply(&format!("Output:\n```\n{}\n```", r))
            }
        }
        Err(e) => msg.reply(&format!("Error: {:?}", e))
    }?;
});

command!(pdgqz(ctx, msg, _args) {
    let mut pdqz = ctx.data.lock();
    let pdqz = pdqz.get_mut::<PdgqzDisalloweds>().unwrap();

    if let Some(i) = pdqz.iter().position(|ch| ch == &msg.channel_id) {
        pdqz.remove(i);
    } else {
        pdqz.push(msg.channel_id);
    }
});

command!(seximal(_ctx, msg, args) {
    let s = args.join("");
    match seximal::to_seximal_words(&s) {
        Ok(ref s) => msg.reply(s),
        Err(_) => msg.reply("Malformed number")
    }?;
});

const CSGO_MSGS: [&str; 6] = [
    "Vi varmer op med en comp!",
    "Jeg er på!",
    "Jeg er mere til Call of Duty ..",
    "Сука блядь!",
    "-skyder en bot for at få dens Bizon-",
    "Mongoskrald!"
];

const BEARTOOTH: [&str; 3] = [
    "I’m not useless! I’m just the king of excuses!",
    "One life and one decision! Make sure it ends with you still living!",
    "Lorteskat på T-shirts."
];

const RESPONSES: [&str; 4] = [
    "Undskyld, kan ikke snakke lige nu :(",
    "Hey, kan jeg ringe igen senere?",
    "Hva' så, din noob!? :P",
    "Ad, hvem er du?"
];

const REDALERT: [&str; 4] = [
    "Your base is under a salt!",
    "Det gamle lortespil?",
    "Jeg er mere til CSGO.",
    "\"Mine depleted\" ..."
];

struct PdgqzDisalloweds;

impl Key for PdgqzDisalloweds {
    type Value = Vec<ChannelId>;
}

struct BotUser;

impl Key for BotUser {
    type Value = String;
}

#[derive(Default)]
struct Handler;

fn main() {
    println!("{} in {}", WESTMANN, MEMES);

    let token = env::var("DISCORD_TOKEN")
        .expect("Expected a token in the environment");
    let mut client = Client::new(&token, Handler::default());

    client.with_framework(StandardFramework::new()
        .configure(|c| c.prefix(PREFIX))
        .command("ping", |c| c.exec_str("Pong!"))
        .on("info", info)
        .on("setgame", setgame)
        .on("rpn", rpn)
        .on("stalch", stalch)
        .on("pdgqz", pdgqz)
        .on("seximal", seximal)
        .on("seticon", seticon)
    );

    {
        let mut data = client.data.lock();
        data.insert::<BotUser>(String::default());
        data.insert::<PdgqzDisalloweds>(Vec::new());
    }

    if let Err(why) = client.start() {
        println!("Client error: {:?}", why);
    }
}

macro_rules! joke {
    ($s:expr; $($trigger:expr),+; $bl:block) => (
        if $($s.contains($trigger))||* $bl
    );
    ($s:expr, $channel_id:expr; $($trigger:expr),+;; $joke:expr) => (
        joke!($s; $($trigger),*; {
            $channel_id.say($joke).unwrap();
        })
    );
    ($s:expr, $channel_id:expr; $($trigger:expr),+; $jokes:expr) => (
        joke!($s; $($trigger),*; {
            send_random($channel_id, &$jokes).unwrap();
        })
    );
}

impl EventHandler for Handler {
    fn on_ready(&self, ctx: Context, ready: Ready) {
        println!("{} is connected!", ready.user.name);
        println!("Guilds:");
        for name in ready.guilds.iter().map(|g| g.id().get().unwrap().name) {
            println!("    {}", name);
        }
        {
            let mut data = ctx.data.lock();
            *data.get_mut::<BotUser>().unwrap() = ready.user.tag();
        }
    }

    fn on_message(&self, ctx: Context, msg: Message) {
        if msg.author.bot {
            return
        }
        {
            if ctx.data.lock().get::<PdgqzDisalloweds>().unwrap().contains(&msg.channel_id) {
                let filter = |c: char| {
                    let c = c.to_lowercase().next().unwrap();
                     c == 'p' || c == 'd' || c == 'g' || c == 'q' || c == 'z'
                };
                if msg.content.chars().any(filter) {
                    let s = msg.content.chars().filter(|c| !filter(*c)).collect::<String>();
                    if !s.is_empty() {
                        msg.channel_id.say(s).unwrap();
                    }
                }
            }
        }
        if msg.channel_id == MEMES && msg.author.id == WESTMANN && msg.attachments.iter().any(|a| a.width.is_some()) {
            msg.channel_id.say("Den er gammel!").unwrap();
        }
        let s: String = msg.content.chars()
        .filter(|c| c.is_alphanumeric())
        .flat_map(|c|c.to_lowercase())
        .collect();

        joke!(s, msg.channel_id; "css", "source";; "Hvor er mine skins!?");
        joke!(s, msg.channel_id; "csgo", "counterstrike", "globaloffensive"; CSGO_MSGS);
        joke!(s, msg.channel_id; "mc", "minecraft";; "MINECRAFT!");
        joke!(s, msg.channel_id; "beartooth"; BEARTOOTH);
        joke!(s, msg.channel_id; "rep";; "Rep mig!");
        joke!(s, msg.channel_id; "ftl";; "Zoltan shield OP");
        joke!(s, msg.channel_id; "bindingofisaac";; "Mom OP");
        joke!(s, msg.channel_id; "meme";; "krydrede migmig'er");
        joke!(s, msg.channel_id; "gunsoficarus";; "Spillere online: 85");
        joke!(s, msg.channel_id; "doom";; "Rip and tear!");
        joke!(s, msg.channel_id; "dyinglight";; "Det dér Left 4 Dead-spil?");
        joke!(s, msg.channel_id; "report";; "ReviewBrah");
        joke!(s; "english"; {
            msg.channel_id.send_message(|cm| {
                cm.embed(|e| {
                    e.image("http://dev.lfalch.com/english.jpg")
                })
            }).unwrap();
        });
        joke!(s, msg.channel_id; "warthunder", "thunder", "tankspil";; "Jeg elsker World of Tanks!");
        joke!(s, msg.channel_id; "ra3", "redalert"; REDALERT);
        joke!(s, msg.channel_id; "rusland", "russia", "росси", "russisk",
        "russian", "русск", "russer";; "Communism is the ultimate goal of socialism.");

        let user = {
            ctx.data.lock().get::<BotUser>().unwrap().clone()
        };
        if msg.mentions.iter().map(|u| u.tag()).any(|u| u == user) {
            send_random(msg.channel_id, &RESPONSES).unwrap();
        }
    }
}

fn send_random(chl: ChannelId, list: &[&str]) -> Result<Message> {
    let i = thread_rng().gen_range(0, list.len());
    chl.say(list[i])
}

#[derive(Debug, Copy, Clone)]
pub enum RpnError<'a> {
    StackTooSmall,
    UnknownOperator(&'a str)
}

use crate::RpnError::*;

pub fn calculate<'a, T: IntoIterator<Item=&'a String>>(operations: T) -> StdResult<f64, RpnError<'a>> {
    let mut stack = Vec::new();

    for operation in operations {
        if let Ok(d) = operation.parse::<f64>() {
            stack.push(d)
        }else{
            calc(operation, &mut stack)?
        }
    }

    stack.pop().ok_or(StackTooSmall)
}

fn calc<'a>(op: &'a str, stack: &mut Vec<f64>) -> StdResult<(), RpnError<'a>>{
    let res = match (stack.pop(), stack.pop()){
        (Some(op1), Some(op2)) => match op{
            "+"|"add" => op2 + op1,
            "-"|"sub" => op2 - op1,
            "/"|"div" => op2 / op1,
            "*"|"mul" => op2 * op1,
            "^"|"pow" => op2.powf(op1),
            "log" => op2.log(op1),
            "hypot" => op2.hypot(op1),
            "%"|"rem" => op2 % op1,
            "|"|"or" => (op2 as i64 | op1 as i64) as f64,
            "&"|"and" => (op2 as i64 & op1 as i64) as f64,
            "xor" => (op2  as i64 ^ op1 as i64) as f64,
            _ => return Err(UnknownOperator(op))
        },
        _ => return Err(StackTooSmall)
    };
    stack.push(res);
    Ok(())
}

fn stalch_run(s: &str) -> StalchResult<(String, String)> {
    let mut state = State::new();
    let mut io = InOuter::new(Vec::new(), io::repeat(b'\n'));

    run_with_state(s.as_bytes(), &mut state, &mut io)?;

    let (output, _) = io.extract();

    let s = String::from_utf8(output).map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;

    Ok((s, format!("{:?}", state.stack())))
}
<commit_msg>Make some jokes less anoying<commit_after>#![warn(clippy::all)]

#[macro_use]
extern crate serenity;

use std::io;
use stalch::{run_with_state, InOuter, State, Result as StalchResult};

use std::env;
use std::io::Read;
use std::result::Result as StdResult;
use typemap::Key;

use rand::Rng;
use rand::thread_rng;

use serenity::prelude::*;
use serenity::model::*;
use serenity::Result;
use serenity::utils;

use serenity::framework::StandardFramework;

const PREFIX: &str = "]";
#[allow(clippy::unreadable_literal)]
const WESTMANN: UserId = UserId(229154015626264577);
#[allow(clippy::unreadable_literal)]
const FALCH: UserId = UserId(165877785544491008);
#[allow(clippy::unreadable_literal)]
const MEMES: ChannelId = ChannelId(306454829738491904);
#[allow(clippy::unreadable_literal)]
const FALCHATS: GuildId = GuildId(189120762659995648);

command!(info(_ctx, msg, _args) {
    msg.channel_id.send_message(|cm| {
        cm.embed(|e| {
            e.title("falchbot")
             .colour(utils::Colour::blue())
             .description("(c) LFalch.com 2018")
             .footer(|f| f.text(serenity::constants::USER_AGENT))
        })
    }).unwrap();
});

command!(setgame(ctx, msg, args) {
    if msg.author.id == FALCH {
        ctx.set_game(Game::playing(&args.join(" ")));
    } else {
        msg.reply("Unauthorised")?;
    }
});

command!(seticon(_ctx, msg, args) {
    let s = args.join("/");

    if msg.author.id == FALCH {
        let img = {
            let client = hyper::Client::new();
            let mut resp = client.get(&format!("http://dev.lfalch.com/{}.png", s)).send()?;
            if !resp.status.is_success() {
                msg.reply("No success")?;
                return Ok(());
            }

            let mut v = Vec::new();

            resp.read_to_end(&mut v)?;

            let b64 = base64::encode(&v);
            let ext = "png";

            format!("data:image/{};base64,{}", ext, b64)
        };

        FALCHATS.edit(|e| e.icon(Some(&img)))?;
    } else {
        msg.reply("Unauthorised")?;
    }
});

command!(rpn(_ctx, msg, args) {
    match calculate(&*args) {
        Ok(r) => msg.reply(&format!("Result: {}", r)),
        Err(e) => msg.reply(&format!("Error: {:?}", e))
    }?;
});

command!(stalch(_ctx, msg, args) {
    match stalch_run(&(args.join(" ") + "\n")) {
        Ok((r, s)) => {
            if r.is_empty() {
                msg.reply(&format!("Stack:\n```\n{}\n```", s))
            } else {
                msg.reply(&format!("Output:\n```\n{}\n```", r))
            }
        }
        Err(e) => msg.reply(&format!("Error: {:?}", e))
    }?;
});

command!(pdgqz(ctx, msg, _args) {
    let mut pdqz = ctx.data.lock();
    let pdqz = pdqz.get_mut::<PdgqzDisalloweds>().unwrap();

    if let Some(i) = pdqz.iter().position(|ch| ch == &msg.channel_id) {
        pdqz.remove(i);
    } else {
        pdqz.push(msg.channel_id);
    }
});

command!(seximal(_ctx, msg, args) {
    let s = args.join("");
    match seximal::to_seximal_words(&s) {
        Ok(ref s) => msg.reply(s),
        Err(_) => msg.reply("Malformed number")
    }?;
});

const CSGO_MSGS: [&str; 6] = [
    "Vi varmer op med en comp!",
    "Jeg er på!",
    "Jeg er mere til Call of Duty ..",
    "Сука блядь!",
    "-skyder en bot for at få dens Bizon-",
    "Mongoskrald!"
];

const BEARTOOTH: [&str; 3] = [
    "I’m not useless! I’m just the king of excuses!",
    "One life and one decision! Make sure it ends with you still living!",
    "Lorteskat på T-shirts."
];

const RESPONSES: [&str; 4] = [
    "Undskyld, kan ikke snakke lige nu :(",
    "Hey, kan jeg ringe igen senere?",
    "Hva' så, din noob!? :P",
    "Ad, hvem er du?"
];

const REDALERT: [&str; 4] = [
    "Your base is under a salt!",
    "Det gamle lortespil?",
    "Jeg er mere til CSGO.",
    "\"Mine depleted\" ..."
];

struct PdgqzDisalloweds;

impl Key for PdgqzDisalloweds {
    type Value = Vec<ChannelId>;
}

struct BotUser;

impl Key for BotUser {
    type Value = String;
}

#[derive(Default)]
struct Handler;

fn main() {
    println!("{} in {}", WESTMANN, MEMES);

    let token = env::var("DISCORD_TOKEN")
        .expect("Expected a token in the environment");
    let mut client = Client::new(&token, Handler::default());

    client.with_framework(StandardFramework::new()
        .configure(|c| c.prefix(PREFIX))
        .command("ping", |c| c.exec_str("Pong!"))
        .on("info", info)
        .on("setgame", setgame)
        .on("rpn", rpn)
        .on("stalch", stalch)
        .on("pdgqz", pdgqz)
        .on("seximal", seximal)
        .on("seticon", seticon)
    );

    {
        let mut data = client.data.lock();
        data.insert::<BotUser>(String::default());
        data.insert::<PdgqzDisalloweds>(Vec::new());
    }

    if let Err(why) = client.start() {
        println!("Client error: {:?}", why);
    }
}

macro_rules! joke {
    ($s:expr; $($trigger:expr),+; $bl:block) => (
        if $($s.contains($trigger))||* $bl
    );
    ($s:expr, $channel_id:expr; $($trigger:expr),+;; $joke:expr) => (
        joke!($s; $($trigger),*; {
            $channel_id.say($joke).unwrap();
        })
    );
    ($s:expr, $channel_id:expr; $($trigger:expr),+; $jokes:expr) => (
        joke!($s; $($trigger),*; {
            send_random($channel_id, &$jokes).unwrap();
        })
    );
}

impl EventHandler for Handler {
    fn on_ready(&self, ctx: Context, ready: Ready) {
        println!("{} is connected!", ready.user.name);
        println!("Guilds:");
        for name in ready.guilds.iter().map(|g| g.id().get().unwrap().name) {
            println!("    {}", name);
        }
        {
            let mut data = ctx.data.lock();
            *data.get_mut::<BotUser>().unwrap() = ready.user.tag();
        }
    }

    fn on_message(&self, ctx: Context, msg: Message) {
        if msg.author.bot {
            return
        }
        {
            if ctx.data.lock().get::<PdgqzDisalloweds>().unwrap().contains(&msg.channel_id) {
                let filter = |c: char| {
                    let c = c.to_lowercase().next().unwrap();
                     c == 'p' || c == 'd' || c == 'g' || c == 'q' || c == 'z'
                };
                if msg.content.chars().any(filter) {
                    let s = msg.content.chars().filter(|c| !filter(*c)).collect::<String>();
                    if !s.is_empty() {
                        msg.channel_id.say(s).unwrap();
                    }
                }
            }
        }
        if msg.channel_id == MEMES && msg.author.id == WESTMANN && msg.attachments.iter().any(|a| a.width.is_some()) {
            msg.channel_id.say("Den er gammel!").unwrap();
        }
        let s: String = msg.content.chars()
        .filter(|c| c.is_alphanumeric())
        .flat_map(|c|c.to_lowercase())
        .collect();

        joke!(s, msg.channel_id; "css", "source";; "Hvor er mine skins!?");
        joke!(s, msg.channel_id; "csgo", "counterstrike", "globaloffensive"; CSGO_MSGS);
        joke!(s, msg.channel_id; "minecraft";; "MINECRAFT!");
        joke!(s, msg.channel_id; "beartooth"; BEARTOOTH);
        joke!(s, msg.channel_id; "rep";; "Rep mig!");
        joke!(s, msg.channel_id; "ftl";; "Zoltan shield OP");
        joke!(s, msg.channel_id; "bindingofisaac";; "Mom OP");
        joke!(s, msg.channel_id; "meme";; "krydrede migmig'er");
        joke!(s, msg.channel_id; "gunsoficarus";; "Spillere online: 85");
        joke!(s, msg.channel_id; "doom";; "Rip and tear!");
        joke!(s, msg.channel_id; "dyinglight";; "Det dér Left 4 Dead-spil?");
        joke!(s, msg.channel_id; "report";; "ReviewBrah");
        joke!(s; "english"; {
            msg.channel_id.send_message(|cm| {
                cm.embed(|e| {
                    e.image("http://dev.lfalch.com/english.jpg")
                })
            }).unwrap();
        });
        joke!(s, msg.channel_id; "warthunder", "thunder", "tankspil";; "Jeg elsker World of Tanks!");
        joke!(s, msg.channel_id; "ra3", "redalert"; REDALERT);
        joke!(s, msg.channel_id; "rusland", "russia", "росси", "russisk",
        "russian", "русск", "russer";; "Союз нерушимый республик свободных!");

        let user = {
            ctx.data.lock().get::<BotUser>().unwrap().clone()
        };
        if msg.mentions.iter().map(|u| u.tag()).any(|u| u == user) {
            send_random(msg.channel_id, &RESPONSES).unwrap();
        }
    }
}

fn send_random(chl: ChannelId, list: &[&str]) -> Result<Message> {
    let i = thread_rng().gen_range(0, list.len());
    chl.say(list[i])
}

#[derive(Debug, Copy, Clone)]
pub enum RpnError<'a> {
    StackTooSmall,
    UnknownOperator(&'a str)
}

use crate::RpnError::*;

pub fn calculate<'a, T: IntoIterator<Item=&'a String>>(operations: T) -> StdResult<f64, RpnError<'a>> {
    let mut stack = Vec::new();

    for operation in operations {
        if let Ok(d) = operation.parse::<f64>() {
            stack.push(d)
        }else{
            calc(operation, &mut stack)?
        }
    }

    stack.pop().ok_or(StackTooSmall)
}

fn calc<'a>(op: &'a str, stack: &mut Vec<f64>) -> StdResult<(), RpnError<'a>>{
    let res = match (stack.pop(), stack.pop()){
        (Some(op1), Some(op2)) => match op{
            "+"|"add" => op2 + op1,
            "-"|"sub" => op2 - op1,
            "/"|"div" => op2 / op1,
            "*"|"mul" => op2 * op1,
            "^"|"pow" => op2.powf(op1),
            "log" => op2.log(op1),
            "hypot" => op2.hypot(op1),
            "%"|"rem" => op2 % op1,
            "|"|"or" => (op2 as i64 | op1 as i64) as f64,
            "&"|"and" => (op2 as i64 & op1 as i64) as f64,
            "xor" => (op2  as i64 ^ op1 as i64) as f64,
            _ => return Err(UnknownOperator(op))
        },
        _ => return Err(StackTooSmall)
    };
    stack.push(res);
    Ok(())
}

fn stalch_run(s: &str) -> StalchResult<(String, String)> {
    let mut state = State::new();
    let mut io = InOuter::new(Vec::new(), io::repeat(b'\n'));

    run_with_state(s.as_bytes(), &mut state, &mut io)?;

    let (output, _) = io.extract();

    let s = String::from_utf8(output).map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;

    Ok((s, format!("{:?}", state.stack())))
}
<|endoftext|>


<commit_before>
use std::fs;

fn main(){

    let config_dir = fs::read_dir("./configs/").unwrap();
    let configs: u8 = 0;

    for f in config_dir{
        configs = 1 + configs;
    }

    println!("There are {0} in the config folder.", configs);

}
<commit_msg>Magic<commit_after>
use std::fs;

fn main(){

    let config_dir = fs::read_dir("./configs/").unwrap();
    let configs: u8 = 0;

    for f in config_dir{
        configs = 1 + configs;
    }

    println!("There are {0} in the config folder.", configs);

    //ww
}
<|endoftext|>


<commit_before>extern crate rand;

use std::io;
use rand::Rng;

fn main() {
        println!("Guess the number!");

        let secret_number = rand::thread_rng().gen_range(1, 101);

        println!("The secret number is: {}", secret_number);

        println!("Please input your guess.");

        let mut guess = String::new();

        io::stdin().read_line(&mut guess)
            .ok()
            .expect("Failed to read line");

        println!("You guessed: {}", guess);
}
<commit_msg>Convert `guess` from `String` into `u32`<commit_after>extern crate rand;

use std::io;
use rand::Rng;

fn main() {
        println!("Guess the number!");

        let secret_number = rand::thread_rng().gen_range(1, 101);

        println!("The secret number is: {}", secret_number);

        println!("Please input your guess.");

        let mut guess = String::new();

        io::stdin().read_line(&mut guess)
            .ok()
            .expect("Failed to read line");

        let guess: u32 = guess.trim().parse()
            .ok()
            .expect("Please type a number!");

        println!("You guessed: {}", guess);
}
<|endoftext|>


<commit_before>extern crate rust_guessing_game;

use std::io;
use std::rand;

use rust_guessing_game::my_funcs;

#[cfg(not(test))]
fn main() {
    println!("Guess the magic number!");
    let magic_number = ( rand::random::<uint>() % 100u ) + 1u;
    loop {
        let input = io::stdin().read_line().ok().expect("That was bad input");
        let input_optoin_uint: Option<uint> = input.parse();
        let input_uint = match input_optoin_uint {
            Some(num) => num,
            None      => {
                println!("Please input a number");
                continue;
            }
        };
        match my_funcs::compare(input_uint, magic_number) {
            Less    => println!("Guess higher."),
            Greater => println!("Guess lower."),
            Equal   => {
                println!("You win!");
                return
            },
        }
    }
}
<commit_msg>Include ordering<commit_after>extern crate rust_guessing_game;

use std::io;
use std::rand;
use std::cmp::Ordering;

use rust_guessing_game::my_funcs;

#[cfg(not(test))]
fn main() {
    println!("Guess the magic number!");
    let magic_number = ( rand::random::<uint>() % 100u ) + 1u;
    loop {
        let input = io::stdin().read_line().ok().expect("That was bad input");
        let input_optoin_uint: Option<uint> = input.parse();
        let input_uint = match input_optoin_uint {
            Some(num) => num,
            None      => {
                println!("Please input a number");
                continue;
            }
        };
        match my_funcs::compare(input_uint, magic_number) {
            Ordering::Less    => println!("Guess higher."),
            Ordering::Greater => println!("Guess lower."),
            Ordering::Equal   => {
                println!("You win!");
                return
            },
        }
    }
}
<|endoftext|>


<commit_before>#![feature(collections)]
#![feature(convert)]

//modules

mod config;
mod word;

//extern crates

extern crate rand;
extern crate rustc_serialize;
extern crate regex;
extern crate unicode_segmentation;

//use

use unicode_segmentation::UnicodeSegmentation;
use config::*;
use word::*;
use std::io::prelude::*;
//use rustc_serialize::*;    //commented out as it is only used to emit test configs
use std::fs::File;
use rand::distributions::Weighted;

//static variables

static CONFIG_FILE_NAME: &'static str = "main_config.json";

//functions

fn main() {
    let config: WordGeneratorConfig = load_config(&CONFIG_FILE_NAME);

    //comment other code and uncomment these to emit a new test config
    //let mut file = File::create(&CONFIG_FILE_NAME).unwrap();

    /*match file.write(json::encode(&config).unwrap().as_bytes()) {
        Ok(_) => (),
        Err(err) => panic!("Error writing test config: {}", err),
    }*/

    let mut first_syllable_list : Vec<Weighted<String>> = Vec::new();
    let mut last_syllable_list : Vec<Weighted<String>> = Vec::new();
    let mut normal_syllable_list : Vec<Weighted<String>> = Vec::new();

    //In-memory, syllables are stored as 'first-only', 'last only', and 'rest of the word' syllable lists.
    //Aside from the impracticality of iterating and manipulating the config data directly every time I
    //want to pick a syllable, I chose this structure as it made implementing syllable construction
    //straightforward while allowing syllables to be constrained to first or last positions. This may end
    //up getting removed later.

    for syllable in &config.syllables {
        let syllable_weighted : Weighted<String> = Weighted{
            weight: syllable.weight as u32,
            item: syllable.string.clone()
        };
        if !(syllable.only_first_syllable || syllable.only_last_syllable) {
            normal_syllable_list.push(syllable_weighted.clone());
            first_syllable_list.push(syllable_weighted.clone());
            last_syllable_list.push(syllable_weighted.clone());
        }
        if syllable.only_first_syllable {
            first_syllable_list.push(syllable_weighted.clone());
        }
        if syllable.only_last_syllable {
            last_syllable_list.push(syllable_weighted.clone());
        }

    }

    //transform_graphemes is used to convert Graphemes to Weighted<String>s. This is done because
    let grapheme_groups : Vec<(String, Vec<Weighted<String>>)> = transform_graphemes(&config.graphemes);

    let word_factory : WordFactory = WordFactory {
        first_syllable_list : first_syllable_list,
        normal_syllable_list : normal_syllable_list,
        last_syllable_list : last_syllable_list,
        graphemes : grapheme_groups,
        generate_settings : config.generate_settings.clone(),
        rewrites : config.rewrites.clone(),
        rejects : config.rejects.clone(),
    };

    write_list_simple(&generate_word_list(&config, &word_factory), &config);
}

fn write_list_simple(word_list: &Vec<Word>, config : &WordGeneratorConfig) {
    let mut file = File::create(&config.output_settings.output_file).unwrap();

    for word in word_list {
        let mut result : String = format!("{}{}", "Word: ", get_word_graphemes(&word));

        if config.output_settings.show_syllable_strings {
            result = format!("{} ({} syllable(s) {})", result, &word.syllable_count, get_word_syllables(&word));
        }

        //note: we are specifically continue-ing out of this loop in a sub-if to implement mark vs drop behavior
        if word.syllable_rejects.len() > 0 || word.grapheme_rejects.len() > 0 {
            if config.output_settings.only_mark_rejects {
                result = format!("{}{}", result, format_word_rejects(&word));
            } else {
                continue;
            }
        }

        if config.output_settings.show_word_rewrites {
            let mut show_no_rewrites_message : bool = true;
            if config.output_settings.show_word_rewrites && config.output_settings.show_syllable_strings && word.syllable_rewrite_history.len() > 0 {
                result = format!("{}\n-Syllable rewrites:\n{}", result, format_transforms(&word.syllables, &word.syllable_rewrite_history));
                show_no_rewrites_message = false;
            }
            if config.output_settings.show_word_rewrites && word.grapheme_rewrite_history.len() > 0 {
                result = format!("{}\n-Grapheme rewrites:\n{}", result, format_transforms(&word.graphemes, &word.grapheme_rewrite_history));
                show_no_rewrites_message = false;
            }
            if word.syllable_rewrite_history.len() > 0 || word.grapheme_rewrite_history.len() > 0 {
                result = format!("{}\n", result);
            } else if show_no_rewrites_message { //please note, will not put no rewrites applied if syllable display is off and there are applied syllable rewrites - fix later
                result = format!("{} (No rewrites applied)", result);
            }
        }
        result = format!("{}\n", result);
        match file.write(result.as_bytes()) {
                Err(error) => panic!("error {} writing to file", error),
                Ok(_) => (),
        };
    }
}

fn format_transforms(original : &String, rewrite_history : &Vec<(Rewrite, String)>) -> String {
    let mut result : String = String::from_str("---------\n");
    let mut current_previous_word : &String = &original.clone();
    for rewrite in rewrite_history {
        result = format!("-{}\n", format_individual_transform(&rewrite, &current_previous_word));
        current_previous_word = &rewrite.1;
    }
    format!("{}-final: {}\n---------", result, current_previous_word)
}
fn format_individual_transform(transform : &(Rewrite, String), previous : &String) -> String {
    format!("{} --> {} ({} --> {})", previous, transform.1, transform.0.pattern, transform.0.replace)
}

//ultimate goal is to emit formatted strings like this:
//qwe: due to syllable rejects []
//qwe: due to grapheme rejects []
//qwe: due to syllable rejects [] and grapheme rejects []
fn format_word_rejects(word : &Word) -> String {
    if word.syllable_rejects.len() == 0 && word.grapheme_rejects.len() == 0 { return String::from_str(""); }
    let mut result : String = String::from_str(" (rejected due to ");
    match word.syllable_rejects.len() {
        0 => (),
        1 => {
            result.push_str("syllable reject ");
            result.push_str(&word.syllable_rejects[0]);

        },
        2 => {
            result.push_str("syllable rejects ");
            result.push_str(&word.syllable_rejects[0]);
            result.push_str("and ");
            result.push_str(&word.syllable_rejects[1]);
        },
        _ => {
            result.push_str("syllable rejects ");

            //right now, rust has no easy way to trim arbitrary numbers of characters off the end of a string - so i have to count manually and stop adding commas at the last reject entry, otherwise there will be an errant ", " added to the end
            let mut count : usize = 0;
            let length = word.syllable_rejects.len();
            for reject in &word.syllable_rejects {
                result.push_str(&reject);
                if count < length - 1 {
                    result.push_str(", ");
                }

                count = count + 1;
            }

        },
    }
    if word.syllable_rejects.len() > 0 && word.grapheme_rejects.len() > 0 {
        result.push_str(", and due to ");
    }
    match word.grapheme_rejects.len() {
        0 => (),
        1 => {
            result.push_str("grapheme reject ");
            result.push_str(&word.grapheme_rejects[0]);

        },
        2 => {
            result.push_str("grapheme rejects ");
            result.push_str(&word.grapheme_rejects[0]);
            result.push_str("and ");
            result.push_str(&word.grapheme_rejects[1]);
        },
        _ => {
            result.push_str("grapheme rejects ");

            //right now, rust has no easy way to trim arbitrary numbers of characters off the end of a string - so i have to count manually and stop adding commas at the last reject entry, otherwise there will be an errant ", " added to the end
            let mut count : usize = 0;
            let length = word.grapheme_rejects.len();
            for reject in &word.grapheme_rejects {
                result.push_str(&reject);
                if count < length - 1 {
                    result.push_str(", ");
                }

                count = count + 1;
            }
        },
    }
    result.push_str(")");
    result
}

fn generate_word_list(config : &WordGeneratorConfig, word_factory : &WordFactory) -> Vec<Word> {
    let mut word_list : Vec<Word> = Vec::new();

    while word_list.iter().filter(|word| word.syllable_rejects.len() == 0 && word.grapheme_rejects.len() == 0).count() < config.output_settings.word_count {

        let mut word : Word = Word {
            syllables : String::new(),
            graphemes : String::new(),
            syllable_rewrite_history : Vec::new(),
            grapheme_rewrite_history : Vec::new(),
            syllable_rejects : Vec::new(),
            grapheme_rejects : Vec::new(),
            syllable_count : 0
        };

        word_factory.generate_syllables(&mut word);

        //at first glance this doesnt look like it's doing much - marking rejects operate on the final
        //word string so rewriting before or after will make a difference
        if config.generate_settings.rewrites_before_rejects {
            word_factory.rewrite_syllables(&mut word);
            word_factory.mark_syllable_rejects(&mut word);
        } else {
            word_factory.mark_syllable_rejects(&mut word);
            word_factory.rewrite_syllables(&mut word);
        };

        word_factory.generate_graphemes(&mut word);

        if config.generate_settings.rewrites_before_rejects {
            word_factory.rewrite_graphemes(&mut word);
            word_factory.mark_grapheme_rejects(&mut word);
        } else {
            word_factory.mark_grapheme_rejects(&mut word);
            word_factory.rewrite_graphemes(&mut word);
        };
        word_list.push(word);
    }
    word_list
}

//unwraps a list of GraphemeGroups into a tuple list of String and Vec<Weighted<String>>
//Stored as a separate structure because JSON data would not be stored as desired for config otherwise
fn transform_graphemes(graphemes : &Vec<GraphemeGroup>) -> Vec<(String, Vec<Weighted<String>>)> {

    let mut grapheme_groups : Vec<(String, Vec<Weighted<String>>)> = Vec::new();

    for group in graphemes {
        let mut graphemes_converted : Vec<Weighted<String>> = Vec::new();

        graphemes_converted.extend(
            group.graphemes.iter().map(
                |g: &Grapheme| Weighted{weight: g.weight as u32, item: g.string.clone() }
                )
            );
        grapheme_groups.push((group.name.clone(), graphemes_converted));
    }
    grapheme_groups
}
<commit_msg>renamed write_list_simple function in preparation for refactor<commit_after>#![feature(collections)]
#![feature(convert)]

//modules

mod config;
mod word;

//extern crates

extern crate rand;
extern crate rustc_serialize;
extern crate regex;
extern crate unicode_segmentation;

//use

use unicode_segmentation::UnicodeSegmentation;
use config::*;
use word::*;
use std::io::prelude::*;
//use rustc_serialize::*;    //commented out as it is only used to emit test configs
use std::fs::File;
use rand::distributions::Weighted;

//static variables

static CONFIG_FILE_NAME: &'static str = "main_config.json";

//functions

fn main() {
    let config: WordGeneratorConfig = load_config(&CONFIG_FILE_NAME);

    //comment other code and uncomment these to emit a new test config
    //let mut file = File::create(&CONFIG_FILE_NAME).unwrap();

    /*match file.write(json::encode(&config).unwrap().as_bytes()) {
        Ok(_) => (),
        Err(err) => panic!("Error writing test config: {}", err),
    }*/

    let mut first_syllable_list : Vec<Weighted<String>> = Vec::new();
    let mut last_syllable_list : Vec<Weighted<String>> = Vec::new();
    let mut normal_syllable_list : Vec<Weighted<String>> = Vec::new();

    //In-memory, syllables are stored as 'first-only', 'last only', and 'rest of the word' syllable lists.
    //Aside from the impracticality of iterating and manipulating the config data directly every time I
    //want to pick a syllable, I chose this structure as it made implementing syllable construction
    //straightforward while allowing syllables to be constrained to first or last positions. This may end
    //up getting removed later.

    for syllable in &config.syllables {
        let syllable_weighted : Weighted<String> = Weighted{
            weight: syllable.weight as u32,
            item: syllable.string.clone()
        };
        if !(syllable.only_first_syllable || syllable.only_last_syllable) {
            normal_syllable_list.push(syllable_weighted.clone());
            first_syllable_list.push(syllable_weighted.clone());
            last_syllable_list.push(syllable_weighted.clone());
        }
        if syllable.only_first_syllable {
            first_syllable_list.push(syllable_weighted.clone());
        }
        if syllable.only_last_syllable {
            last_syllable_list.push(syllable_weighted.clone());
        }

    }

    //transform_graphemes is used to convert Graphemes to Weighted<String>s. This is done because
    let grapheme_groups : Vec<(String, Vec<Weighted<String>>)> = transform_graphemes(&config.graphemes);

    let word_factory : WordFactory = WordFactory {
        first_syllable_list : first_syllable_list,
        normal_syllable_list : normal_syllable_list,
        last_syllable_list : last_syllable_list,
        graphemes : grapheme_groups,
        generate_settings : config.generate_settings.clone(),
        rewrites : config.rewrites.clone(),
        rejects : config.rejects.clone(),
    };

    write_list(&generate_word_list(&config, &word_factory), &config);
}

fn write_list(word_list: &Vec<Word>, config : &WordGeneratorConfig) {
    let mut file = File::create(&config.output_settings.output_file).unwrap();

    for word in word_list {
        let mut result : String = format!("{}{}", "Word: ", get_word_graphemes(&word));

        if config.output_settings.show_syllable_strings {
            result = format!("{} ({} syllable(s) {})", result, &word.syllable_count, get_word_syllables(&word));
        }

        //note: we are specifically continue-ing out of this loop in a sub-if to implement mark vs drop behavior
        if word.syllable_rejects.len() > 0 || word.grapheme_rejects.len() > 0 {
            if config.output_settings.only_mark_rejects {
                result = format!("{}{}", result, format_word_rejects(&word));
            } else {
                continue;
            }
        }

        if config.output_settings.show_word_rewrites {
            let mut show_no_rewrites_message : bool = true;
            if config.output_settings.show_word_rewrites && config.output_settings.show_syllable_strings && word.syllable_rewrite_history.len() > 0 {
                result = format!("{}\n-Syllable rewrites:\n{}", result, format_transforms(&word.syllables, &word.syllable_rewrite_history));
                show_no_rewrites_message = false;
            }
            if config.output_settings.show_word_rewrites && word.grapheme_rewrite_history.len() > 0 {
                result = format!("{}\n-Grapheme rewrites:\n{}", result, format_transforms(&word.graphemes, &word.grapheme_rewrite_history));
                show_no_rewrites_message = false;
            }
            if word.syllable_rewrite_history.len() > 0 || word.grapheme_rewrite_history.len() > 0 {
                result = format!("{}\n", result);
            } else if show_no_rewrites_message { //please note, will not put no rewrites applied if syllable display is off and there are applied syllable rewrites - fix later
                result = format!("{} (No rewrites applied)", result);
            }
        }
        result = format!("{}\n", result);
        match file.write(result.as_bytes()) {
                Err(error) => panic!("error {} writing to file", error),
                Ok(_) => (),
        };
    }
}

fn format_transforms(original : &String, rewrite_history : &Vec<(Rewrite, String)>) -> String {
    let mut result : String = String::from_str("---------\n");
    let mut current_previous_word : &String = &original.clone();
    for rewrite in rewrite_history {
        result = format!("-{}\n", format_individual_transform(&rewrite, &current_previous_word));
        current_previous_word = &rewrite.1;
    }
    format!("{}-final: {}\n---------", result, current_previous_word)
}
fn format_individual_transform(transform : &(Rewrite, String), previous : &String) -> String {
    format!("{} --> {} ({} --> {})", previous, transform.1, transform.0.pattern, transform.0.replace)
}

//ultimate goal is to emit formatted strings like this:
//qwe: due to syllable rejects []
//qwe: due to grapheme rejects []
//qwe: due to syllable rejects [] and grapheme rejects []
fn format_word_rejects(word : &Word) -> String {
    if word.syllable_rejects.len() == 0 && word.grapheme_rejects.len() == 0 { return String::from_str(""); }
    let mut result : String = String::from_str(" (rejected due to ");
    match word.syllable_rejects.len() {
        0 => (),
        1 => {
            result.push_str("syllable reject ");
            result.push_str(&word.syllable_rejects[0]);

        },
        2 => {
            result.push_str("syllable rejects ");
            result.push_str(&word.syllable_rejects[0]);
            result.push_str("and ");
            result.push_str(&word.syllable_rejects[1]);
        },
        _ => {
            result.push_str("syllable rejects ");

            //right now, rust has no easy way to trim arbitrary numbers of characters off the end of a string - so i have to count manually and stop adding commas at the last reject entry, otherwise there will be an errant ", " added to the end
            let mut count : usize = 0;
            let length = word.syllable_rejects.len();
            for reject in &word.syllable_rejects {
                result.push_str(&reject);
                if count < length - 1 {
                    result.push_str(", ");
                }

                count = count + 1;
            }

        },
    }
    if word.syllable_rejects.len() > 0 && word.grapheme_rejects.len() > 0 {
        result.push_str(", and due to ");
    }
    match word.grapheme_rejects.len() {
        0 => (),
        1 => {
            result.push_str("grapheme reject ");
            result.push_str(&word.grapheme_rejects[0]);

        },
        2 => {
            result.push_str("grapheme rejects ");
            result.push_str(&word.grapheme_rejects[0]);
            result.push_str("and ");
            result.push_str(&word.grapheme_rejects[1]);
        },
        _ => {
            result.push_str("grapheme rejects ");

            //right now, rust has no easy way to trim arbitrary numbers of characters off the end of a string - so i have to count manually and stop adding commas at the last reject entry, otherwise there will be an errant ", " added to the end
            let mut count : usize = 0;
            let length = word.grapheme_rejects.len();
            for reject in &word.grapheme_rejects {
                result.push_str(&reject);
                if count < length - 1 {
                    result.push_str(", ");
                }

                count = count + 1;
            }
        },
    }
    result.push_str(")");
    result
}

fn generate_word_list(config : &WordGeneratorConfig, word_factory : &WordFactory) -> Vec<Word> {
    let mut word_list : Vec<Word> = Vec::new();

    while word_list.iter().filter(|word| word.syllable_rejects.len() == 0 && word.grapheme_rejects.len() == 0).count() < config.output_settings.word_count {

        let mut word : Word = Word {
            syllables : String::new(),
            graphemes : String::new(),
            syllable_rewrite_history : Vec::new(),
            grapheme_rewrite_history : Vec::new(),
            syllable_rejects : Vec::new(),
            grapheme_rejects : Vec::new(),
            syllable_count : 0
        };

        word_factory.generate_syllables(&mut word);

        //at first glance this doesnt look like it's doing much - marking rejects operate on the final
        //word string so rewriting before or after will make a difference
        if config.generate_settings.rewrites_before_rejects {
            word_factory.rewrite_syllables(&mut word);
            word_factory.mark_syllable_rejects(&mut word);
        } else {
            word_factory.mark_syllable_rejects(&mut word);
            word_factory.rewrite_syllables(&mut word);
        };

        word_factory.generate_graphemes(&mut word);

        if config.generate_settings.rewrites_before_rejects {
            word_factory.rewrite_graphemes(&mut word);
            word_factory.mark_grapheme_rejects(&mut word);
        } else {
            word_factory.mark_grapheme_rejects(&mut word);
            word_factory.rewrite_graphemes(&mut word);
        };
        word_list.push(word);
    }
    word_list
}

//unwraps a list of GraphemeGroups into a tuple list of String and Vec<Weighted<String>>
//Stored as a separate structure because JSON data would not be stored as desired for config otherwise
fn transform_graphemes(graphemes : &Vec<GraphemeGroup>) -> Vec<(String, Vec<Weighted<String>>)> {

    let mut grapheme_groups : Vec<(String, Vec<Weighted<String>>)> = Vec::new();

    for group in graphemes {
        let mut graphemes_converted : Vec<Weighted<String>> = Vec::new();

        graphemes_converted.extend(
            group.graphemes.iter().map(
                |g: &Grapheme| Weighted{weight: g.weight as u32, item: g.string.clone() }
                )
            );
        grapheme_groups.push((group.name.clone(), graphemes_converted));
    }
    grapheme_groups
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

extern crate regex;
use regex::Regex;

use std::io;
use std::io::Write;

use std::collections::HashMap;

mod expression;

type Expression = expression::Expression;

use expression::eval::eval_postfix_expr;
use expression::parse::parse_input;

fn strip_white_space(input: &String) -> String {
    input.split_whitespace().collect::<Vec<&str>>().join("")
}

fn main() {
    let numeric_regex: Regex = Regex::new(r"\d+\.\d+|\d+").unwrap();
    let function_regex: Regex = Regex::new(r"\w{2,}").unwrap();
    println!("Welcome to Rust-Calculus!");
    println!("To evaluate an expression, simply type one in and hit RETURN.");
    println!("To set a variable, simply type VAR_NAME=EXPRESSION and hit RETURN.");
    println!("Valid commands are: sym_int, int, sym_def, and def.");
    println!("Type 'quit' to exit.");
    let mut input = String::new();
    let stdin = io::stdin();
    let mut stdout = io::stdout();
    let mut variables: HashMap<String, f64> = HashMap::new();
    let mut var_expr: bool;
    loop {
        input.clear();
        print!(">>>> ");
        stdout.flush().ok();
        if let Err(x) = stdin.read_line(&mut input) {
            println!("There was a problem reading stdin: {:?}", x);
            print!("Exiting...");;
            break;
        }
        input = strip_white_space(&input).to_lowercase();
        if input == "quit" {
            println!("Exiting...");
            break;
        }
        let (var, expr) = parse_input(&input, &numeric_regex, &function_regex);
        if var.len() > 0 {
            var_expr = true;
            if !variables.contains_key(&var) {
                variables.insert(var.clone(), 0.0);
            }
        } else {
            var_expr = false;
        }
        if expr.is_ok() {
            let my_expression = expr.unwrap();
            let result = eval_postfix_expr(&my_expression, &variables);
            if var_expr {
                variables.insert(var.clone(), result);
                println!("{} = {}", &var, &result);
            } else {
                println!("{}", &result);
            }
        } else {
            println!("Encountered an error while parsing: {:?}",
                     expr.unwrap_err());
            println!("Try Again...(type 'quit' to exit)");
            continue;
        }
    }
}
<commit_msg>Made teh function regex more explicit<commit_after>#![allow(dead_code)]

extern crate regex;
use regex::Regex;

use std::io;
use std::io::Write;

use std::collections::HashMap;

mod expression;

type Expression = expression::Expression;

use expression::eval::eval_postfix_expr;
use expression::parse::parse_input;

fn strip_white_space(input: &String) -> String {
    input.split_whitespace().collect::<Vec<&str>>().join("")
}

fn main() {
    let numeric_regex: Regex = Regex::new(r"\d+\.\d+|\d+").unwrap();
    let function_regex: Regex = Regex::new(r"[a-zA-Z]{2,}").unwrap();
    println!("Welcome to Rust-Calculus!");
    println!("To evaluate an expression, simply type one in and hit RETURN.");
    println!("To set a variable, simply type VAR_NAME=EXPRESSION and hit RETURN.");
    println!("Valid commands are: sym_int, int, sym_def, and def.");
    println!("Type 'quit' to exit.");
    let mut input = String::new();
    let stdin = io::stdin();
    let mut stdout = io::stdout();
    let mut variables: HashMap<String, f64> = HashMap::new();
    let mut var_expr: bool;
    loop {
        input.clear();
        print!(">>>> ");
        stdout.flush().ok();
        if let Err(x) = stdin.read_line(&mut input) {
            println!("There was a problem reading stdin: {:?}", x);
            print!("Exiting...");;
            break;
        }
        input = strip_white_space(&input).to_lowercase();
        if input == "quit" {
            println!("Exiting...");
            break;
        }
        let (var, expr) = parse_input(&input, &numeric_regex, &function_regex);
        if var.len() > 0 {
            var_expr = true;
            if !variables.contains_key(&var) {
                variables.insert(var.clone(), 0.0);
            }
        } else {
            var_expr = false;
        }
        if expr.is_ok() {
            let my_expression = expr.unwrap();
            let result = eval_postfix_expr(&my_expression, &variables);
            if var_expr {
                variables.insert(var.clone(), result);
                println!("{} = {}", &var, &result);
            } else {
                println!("{}", &result);
            }
        } else {
            println!("Encountered an error while parsing: {:?}",
                     expr.unwrap_err());
            println!("Try Again...(type 'quit' to exit)");
            continue;
        }
    }
}
<|endoftext|>


<commit_before>use std::char;
use std::collections::BTreeSet;

const NSQRT: usize = 3;
const N: usize = NSQRT * NSQRT;
const NSQ: usize = N*N;

/// Return the 0-based row index of `cell`.
fn row(cell: usize) -> usize {
    cell / N
}

/// Return the 0-based row index of `cell`.
fn col(cell: usize) -> usize {
    cell % N
}

/// Return the 0-based index of the upper-left cell of `cell`'s group.
fn group(cell: usize) -> usize {
    let r = row(cell);
    let c = col(cell);
    (N * (r - r % NSQRT)) + (c - c % NSQRT)
}

fn neighbors(cell: usize) -> BTreeSet<usize> {
    let mut all_neighbors: BTreeSet<usize> = BTreeSet::new();

    // Neighbors on row
    for col in 0..N {
        all_neighbors.insert((N * row(cell)) + col);
    }

    // Neighbors on column
    for row in 0..N {
        all_neighbors.insert((N * row) + col(cell));
    }

    // Neighbors in group
    let leader = group(cell);
    for r in row(leader) .. row(leader) + NSQRT {
        for c in col(leader) .. col(leader) + NSQRT {
            all_neighbors.insert(N * r + c);
        }
    }

    all_neighbors.remove(&cell);
    return all_neighbors;
}

#[derive(Debug)]
struct SudokuBoard(Vec<u8>);

impl SudokuBoard {
    fn from_str(digits: &str) -> Self {
        let mut v = Vec::with_capacity(NSQ);
        for d in digits.chars() {
            match d {
                '.' => { v.push(0); }
                '1' ... '9' => {
                    let n = d.to_digit(10).unwrap() as u8;
                    v.push(n);
                }
                _ => { panic!("invalid digit ({:?}) in string", d); }
            }
        }
        SudokuBoard(v)
    }

    fn to_str(&self) -> String {
        let mut s = String::with_capacity(N + NSQ);
        let mut i = 0;
        for n in self.0.iter() {
            if i % N == 0 {
                s.push('\n');
            }
            if *n == 0 {
                s.push('.');
            } else {
                s.push(char::from_digit(*n as u32, 10).unwrap());
            }
            i += 1;
        }
        s
    }

    fn is_solved(&self, cell: usize) -> bool {
        self.0[cell] != 0
    }

    fn candidates(&self, cell: usize) -> BTreeSet<u8> {
        let mut non_candidates = BTreeSet::new();
        for n in neighbors(cell) {
            let x = self.0[n];
            if x != 0 {
                non_candidates.insert(x);
            }
        }
        let mut candidates: BTreeSet<u8> = (1_u8 .. (N+1) as u8).collect();
        for nc in non_candidates {
            candidates.remove(&nc);
        }
        candidates
    }

    fn solve(&mut self, cell: usize) -> bool {
        if cell >= NSQ {
            return true;
        }

        if self.is_solved(cell) {
            return self.solve(cell + 1);
        }

        for c in self.candidates(cell) {
            self.0[cell] = c;
            if self.solve(cell + 1) {
                return true;
            } else {
                self.0[cell] = 0;
            }
        }
        return false;
    }
}

fn main() {
    let mut sb = SudokuBoard::from_str(".94...13..............76..2.8..1.....32.........2...6.....5.4.......8..7..63.4..8");
    println!("{}", sb.to_str());
    sb.solve(0);
    println!("{}", sb.to_str());
}

#[test]
fn test_row_col() {
    assert_eq!(row(11), 1);
    assert_eq!(col(11), 2);
}

#[test]
fn test_group() {
    assert_eq!(group(0), 0);
    assert_eq!(group(1), 0);
    assert_eq!(group(2), 0);
    assert_eq!(group(9), 0);
    assert_eq!(group(10), 0);
    assert_eq!(group(11), 0);
    assert_eq!(group(18), 0);
    assert_eq!(group(19), 0);
    assert_eq!(group(20), 0);
    assert_eq!(group(60), 60);
    assert_eq!(group(61), 60);
    assert_eq!(group(62), 60);
    assert_eq!(group(69), 60);
    assert_eq!(group(70), 60);
    assert_eq!(group(71), 60);
    assert_eq!(group(78), 60);
    assert_eq!(group(79), 60);
    assert_eq!(group(80), 60);
}

#[test]
fn test_is_solved() {
    let sb = SudokuBoard(vec![0, 1]);
    assert!(!sb.is_solved(0));
    assert!(sb.is_solved(1));
}

#[test]
fn test_neighbors() {
    assert!(!neighbors(0).contains(&0));
    // Neighbors of 0 on the same row
    assert!(neighbors(0).contains(&1));
    assert!(neighbors(0).contains(&2));
    assert!(neighbors(0).contains(&3));
    assert!(neighbors(0).contains(&4));
    assert!(neighbors(0).contains(&5));
    assert!(neighbors(0).contains(&6));
    assert!(neighbors(0).contains(&7));
    assert!(neighbors(0).contains(&8));
    // Neighbors of 0 on the same col
    assert!(neighbors(0).contains(&9));
    assert!(neighbors(0).contains(&18));
    assert!(neighbors(0).contains(&27));
    assert!(neighbors(0).contains(&36));
    assert!(neighbors(0).contains(&45));
    assert!(neighbors(0).contains(&54));
    assert!(neighbors(0).contains(&63));
    assert!(neighbors(0).contains(&72));
    // Neighbors of 0 in the same group
    assert!(neighbors(0).contains(&1));
    assert!(neighbors(0).contains(&2));
    assert!(neighbors(0).contains(&9));
    assert!(neighbors(0).contains(&10));
    assert!(neighbors(0).contains(&11));
    assert!(neighbors(0).contains(&18));
    assert!(neighbors(0).contains(&19));
    assert!(neighbors(0).contains(&20));
}

#[test]
fn test_candidates() {
    let sb = SudokuBoard::from_str(".2......34..........6...................................................5........");
    assert!(!sb.candidates(0).contains(&2));
    assert!(!sb.candidates(0).contains(&3));
    assert!(!sb.candidates(0).contains(&4));
    assert!(!sb.candidates(0).contains(&5));
    assert!(!sb.candidates(0).contains(&6));
    assert!(sb.candidates(0).contains(&1));
    assert!(sb.candidates(0).contains(&7));
    assert!(sb.candidates(0).contains(&8));
    assert!(sb.candidates(0).contains(&9));
}
<commit_msg>Add more doc-comments<commit_after>use std::char;
use std::collections::BTreeSet;

const NSQRT: usize = 3;
const N: usize = NSQRT * NSQRT;
const NSQ: usize = N*N;

/// Return the 0-based row index of `cell`.
fn row(cell: usize) -> usize {
    cell / N
}

/// Return the 0-based row index of `cell`.
fn col(cell: usize) -> usize {
    cell % N
}

/// Return the 0-based index of the upper-left cell of `cell`'s group.
fn group(cell: usize) -> usize {
    let r = row(cell);
    let c = col(cell);
    (N * (r - r % NSQRT)) + (c - c % NSQRT)
}

/// Return the neighbors of `cell`:
/// - The cells on the same row;
/// - The cells on the same column;
/// - The same in the same group.
/// Note: `cell` is not a neighbor of itself.
fn neighbors(cell: usize) -> BTreeSet<usize> {
    let mut all_neighbors: BTreeSet<usize> = BTreeSet::new();

    // Neighbors on row
    for col in 0..N {
        all_neighbors.insert((N * row(cell)) + col);
    }

    // Neighbors on column
    for row in 0..N {
        all_neighbors.insert((N * row) + col(cell));
    }

    // Neighbors in group
    let leader = group(cell);
    for r in row(leader) .. row(leader) + NSQRT {
        for c in col(leader) .. col(leader) + NSQRT {
            all_neighbors.insert(N * r + c);
        }
    }

    all_neighbors.remove(&cell);
    return all_neighbors;
}

/// A sudoku board is represented by a vector of bytes.
#[derive(Debug)]
struct SudokuBoard(Vec<u8>);

impl SudokuBoard {
    /// Create a new sudoku board from a string.
    /// A non-zero digit stands for itself,
    /// a dot stands for a blank cell,
    /// anything else is an error.
    // TODO(vfoley): more error handling (length check)
    fn from_str(digits: &str) -> Self {
        let mut v = Vec::with_capacity(NSQ);
        for d in digits.chars() {
            match d {
                '.' => { v.push(0); }
                '1' ... '9' => {
                    let n = d.to_digit(10).unwrap() as u8;
                    v.push(n);
                }
                _ => { panic!("invalid digit ({:?}) in string", d); }
            }
        }
        SudokuBoard(v)
    }

    /// Convert a sudoku board to a rough string representation.
    fn to_str(&self) -> String {
        let mut s = String::with_capacity(N + NSQ);
        let mut i = 0;
        for n in self.0.iter() {
            if i % N == 0 {
                s.push('\n');
            }
            if *n == 0 {
                s.push('.');
            } else {
                s.push(char::from_digit(*n as u32, 10).unwrap());
            }
            i += 1;
        }
        s
    }

    /// A cell is solved if its content is non-zero.
    fn is_solved(&self, cell: usize) -> bool {
        self.0[cell] != 0
    }

    /// Return the list of candidates for a cell.
    /// The candidates are the digits from 1 to NSQ
    /// that are *not* solved in any of `cell`'s neighbors.
    fn candidates(&self, cell: usize) -> BTreeSet<u8> {
        let mut non_candidates = BTreeSet::new();
        for n in neighbors(cell) {
            let x = self.0[n];
            if x != 0 {
                non_candidates.insert(x);
            }
        }
        let mut candidates: BTreeSet<u8> = (1_u8 .. (N+1) as u8).collect();
        for nc in non_candidates {
            candidates.remove(&nc);
        }
        candidates
    }

    /// Solve a sudoku board by backtracking.
    /// Return true if the board is solved, false otherwise.
    fn solve(&mut self, cell: usize) -> bool {
        if cell >= NSQ {
            return true;
        }

        if self.is_solved(cell) {
            return self.solve(cell + 1);
        }

        for c in self.candidates(cell) {
            self.0[cell] = c;
            if self.solve(cell + 1) {
                return true;
            } else {
                self.0[cell] = 0;
            }
        }
        return false;
    }
}

fn main() {
    let mut sb = SudokuBoard::from_str(".94...13..............76..2.8..1.....32.........2...6.....5.4.......8..7..63.4..8");
    println!("{}", sb.to_str());
    sb.solve(0);
    println!("{}", sb.to_str());
}

#[test]
fn test_row_col() {
    assert_eq!(row(11), 1);
    assert_eq!(col(11), 2);
}

#[test]
fn test_group() {
    assert_eq!(group(0), 0);
    assert_eq!(group(1), 0);
    assert_eq!(group(2), 0);
    assert_eq!(group(9), 0);
    assert_eq!(group(10), 0);
    assert_eq!(group(11), 0);
    assert_eq!(group(18), 0);
    assert_eq!(group(19), 0);
    assert_eq!(group(20), 0);
    assert_eq!(group(60), 60);
    assert_eq!(group(61), 60);
    assert_eq!(group(62), 60);
    assert_eq!(group(69), 60);
    assert_eq!(group(70), 60);
    assert_eq!(group(71), 60);
    assert_eq!(group(78), 60);
    assert_eq!(group(79), 60);
    assert_eq!(group(80), 60);
}

#[test]
fn test_is_solved() {
    let sb = SudokuBoard(vec![0, 1]);
    assert!(!sb.is_solved(0));
    assert!(sb.is_solved(1));
}

#[test]
fn test_neighbors() {
    assert!(!neighbors(0).contains(&0));
    // Neighbors of 0 on the same row
    assert!(neighbors(0).contains(&1));
    assert!(neighbors(0).contains(&2));
    assert!(neighbors(0).contains(&3));
    assert!(neighbors(0).contains(&4));
    assert!(neighbors(0).contains(&5));
    assert!(neighbors(0).contains(&6));
    assert!(neighbors(0).contains(&7));
    assert!(neighbors(0).contains(&8));
    // Neighbors of 0 on the same col
    assert!(neighbors(0).contains(&9));
    assert!(neighbors(0).contains(&18));
    assert!(neighbors(0).contains(&27));
    assert!(neighbors(0).contains(&36));
    assert!(neighbors(0).contains(&45));
    assert!(neighbors(0).contains(&54));
    assert!(neighbors(0).contains(&63));
    assert!(neighbors(0).contains(&72));
    // Neighbors of 0 in the same group
    assert!(neighbors(0).contains(&1));
    assert!(neighbors(0).contains(&2));
    assert!(neighbors(0).contains(&9));
    assert!(neighbors(0).contains(&10));
    assert!(neighbors(0).contains(&11));
    assert!(neighbors(0).contains(&18));
    assert!(neighbors(0).contains(&19));
    assert!(neighbors(0).contains(&20));
}

#[test]
fn test_candidates() {
    let sb = SudokuBoard::from_str(".2......34..........6...................................................5........");
    assert!(!sb.candidates(0).contains(&2));
    assert!(!sb.candidates(0).contains(&3));
    assert!(!sb.candidates(0).contains(&4));
    assert!(!sb.candidates(0).contains(&5));
    assert!(!sb.candidates(0).contains(&6));
    assert!(sb.candidates(0).contains(&1));
    assert!(sb.candidates(0).contains(&7));
    assert!(sb.candidates(0).contains(&8));
    assert!(sb.candidates(0).contains(&9));
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::{Read, Stdin, Result};

#[derive(Debug)]
enum Instruction {
    MoveLeft(usize),
    MoveRight(usize),
    Inc(u8),
    Dec(u8),
    Input,
    Output,
    LoopEntry(usize),
    LoopExit(usize),
}

use Instruction::*;

#[derive(Debug)]
struct Program {
    instructions: Vec<Instruction>
}

impl Program {
    pub fn new(text: String) -> Program
    {
        // "lex" token stream - aka skip whitespace
        let token = text.chars().filter(move |c| {
            *c == '>' || *c == '<' || *c == '+' || *c == '-' ||
            *c == '.' || *c == ',' || *c == '[' || *c == ']'
        }).collect::<Vec<_>>();
        Program {
            instructions : token.iter().enumerate().map(|(idx, &c)| {
                match c {
                    '>' => MoveLeft(1),
                    '<' => MoveRight(1),
                    '+' => Inc(1),
                    '-' => Dec(1),
                    '.' => Output,
                    ',' => Input,
                    '[' => {
                        let mut bracket_nesting = 1;
                        let mut pc = idx + 1;

                        while (bracket_nesting > 0) && (pc < token.len()) {
                            match token[pc] {
                                '[' => bracket_nesting += 1,
                                ']' => bracket_nesting -= 1,
                                _ => (),
                            };
                            pc += 1;
                        }
                        if 0 == bracket_nesting {
                            pc -= 1;
                        }
                        else {
                            panic!("unmachted '[' at pc={:}", idx);
                        }
                        LoopEntry(pc)
                    },
                    ']' => {
                        let mut bracket_nesting = 1;
                        let mut pc = idx;

                        while (bracket_nesting > 0) && (pc > 0) {
                            pc -= 1;
                            match token[pc] {
                                '[' => bracket_nesting -= 1,
                                ']' => bracket_nesting += 1,
                                _ => (),
                            };
                        }
                        if 0 != bracket_nesting {
                            panic!("unmachted ']' at pc={:}", idx);
                        }
                        LoopExit(pc)
                    },
                    c => panic!("Unknown instruction {:?} at pc={:}", c, idx),
                }
            }).collect::<Vec<_>>()
        }
    }
    pub fn interp(&self) {
        let mut memory = vec![0u8; 30000];

        let mut pc:usize = 0;
        let mut dataptr:usize = 0;
        let mut stdin = std::io::stdin();

        fn get_char(stdin: &mut Stdin) -> u8 {
            let mut buf = [0u8; 1];
            match stdin.read(&mut buf) {
                Err(_) => panic!("Cannot read from stdin"),
                Ok(_) => buf[0]
            }
        }

        while pc < self.instructions.len() {
            match self.instructions[pc] {
                MoveLeft(1usize) => dataptr += 1,
                MoveRight(1usize) => dataptr -= 1,
                Inc(1u8) => memory[dataptr] = memory[dataptr].wrapping_add(1),
                Dec(1u8) => memory[dataptr] = memory[dataptr].wrapping_sub(1),
                Output => print!("{:}", memory[dataptr] as char),
                Input => memory[dataptr] = get_char(&mut stdin),
                LoopEntry(target) => if 0 == memory[dataptr] {
                    pc = target;
                },
                LoopExit(target) => if 0 != memory[dataptr] {
                    pc = target;
                },
                ref c => panic!("Unknown instruction {:?} at pc={:}", c, pc),
            }
            pc += 1;
        }
    }
}

fn load_program(fname: String) -> Result<Program> {
    let mut file = File::open(fname)?;
    let mut contents: Vec<u8> = Vec::new();
    file.read_to_end(&mut contents)?;
    let text = String::from_utf8(contents).unwrap();

    Ok(Program::new(text))
}

fn main() {
    match load_program("examples/mandelbrot.bf".to_string()) {
        Ok(p) => {
            //println!("{:?}", p);
            p.interp();
        },
        Err(err) => panic!("Cannot read file because {:?}", err),
    }
}
<commit_msg>prepare for more general instructions<commit_after>use std::fs::File;
use std::io::{Read, Stdin, Result};

#[derive(Debug, Clone, PartialEq)]
enum Instruction {
    MoveLeft(usize),
    MoveRight(usize),
    Inc(u8),
    Dec(u8),
    Input,
    Output,
    LoopEntry(usize),
    LoopExit(usize),
}

use Instruction::*;

#[derive(Debug)]
struct Program {
    instructions: Vec<Instruction>
}

impl Program {
    pub fn new(text: String) -> Program
    {
        // "lex" token stream - aka skip whitespace
        let token = text.chars().filter(move |c| {
            *c == '>' || *c == '<' || *c == '+' || *c == '-' ||
            *c == '.' || *c == ',' || *c == '[' || *c == ']'
        }).collect::<Vec<_>>();
        Program {
            instructions : token.iter().enumerate().map(|(idx, &c)| {
                match c {
                    '<' => MoveLeft(1),
                    '>' => MoveRight(1),
                    '+' => Inc(1),
                    '-' => Dec(1),
                    '.' => Output,
                    ',' => Input,
                    '[' => {
                        let mut bracket_nesting = 1;
                        let mut pc = idx + 1;

                        while (bracket_nesting > 0) && (pc < token.len()) {
                            match token[pc] {
                                '[' => bracket_nesting += 1,
                                ']' => bracket_nesting -= 1,
                                _ => (),
                            };
                            pc += 1;
                        }
                        if 0 == bracket_nesting {
                            pc -= 1;
                        }
                        else {
                            panic!("unmachted '[' at pc={:}", idx);
                        }
                        LoopEntry(pc)
                    },
                    ']' => {
                        let mut bracket_nesting = 1;
                        let mut pc = idx;

                        while (bracket_nesting > 0) && (pc > 0) {
                            pc -= 1;
                            match token[pc] {
                                '[' => bracket_nesting -= 1,
                                ']' => bracket_nesting += 1,
                                _ => (),
                            };
                        }
                        if 0 != bracket_nesting {
                            panic!("unmachted ']' at pc={:}", idx);
                        }
                        LoopExit(pc)
                    },
                    c => panic!("Unknown instruction {:?} at pc={:}", c, idx),
                }
            }).collect::<Vec<_>>()
        }
    }

    pub fn interp(&self) {
        let mut memory = vec![0u8; 30000];

        let mut pc:usize = 0;
        let mut dataptr:usize = 0;
        let mut stdin = std::io::stdin();

        fn get_char(stdin: &mut Stdin) -> u8 {
            let mut buf = [0u8; 1];
            match stdin.read(&mut buf) {
                Err(_) => panic!("Cannot read from stdin"),
                Ok(_) => buf[0]
            }
        }

        while pc < self.instructions.len() {
            match self.instructions[pc] {
                MoveLeft(offset) => dataptr -= offset,
                MoveRight(offset) => dataptr += offset,
                Inc(increment) => memory[dataptr] = memory[dataptr].wrapping_add(increment),
                Dec(decrement) => memory[dataptr] = memory[dataptr].wrapping_sub(decrement),
                Output => print!("{:}", memory[dataptr] as char),
                Input => memory[dataptr] = get_char(&mut stdin),
                LoopEntry(target) => if 0 == memory[dataptr] {
                    pc = target;
                },
                LoopExit(target) => if 0 != memory[dataptr] {
                    pc = target;
                },
                // ref c => panic!("Unknown instruction {:?} at pc={:}", c, pc),
            }
            pc += 1;
        }
    }
}

fn load_program(fname: String) -> Result<Program> {
    let mut file = File::open(fname)?;
    let mut contents: Vec<u8> = Vec::new();
    file.read_to_end(&mut contents)?;
    let text = String::from_utf8(contents).unwrap();

    Ok(Program::new(text))
}

fn main() {
    match load_program("examples/mandelbrot.bf".to_string()) {
        Ok(ref mut p) => {
            //println!("{:?}", p);
            p.interp();
        },
        Err(err) => panic!("Cannot read file because {:?}", err),
    }
}
<|endoftext|>


<commit_before>#![allow(unstable, dead_code)]

extern crate libc;

mod args;
mod ansi;
mod matching;
mod screen;

use std::os;
use std::io;
use std::cmp::min;
use screen::Screen;
use screen::Key::*;

fn main() {
  let args = match args::parse_args() {
    Some(args) => args,
    None => {
      os::set_exit_status(1);
      return;
    },
  };

  if args.help { return; }

  let mut screen = Screen::open_screen();
  let mut index = 0;

  let choices = read_choices();
  let visible_choices = min(20, screen.height - 1);

  let mut search = args.initial_search.clone();
  let start_line = screen.height - visible_choices - 1;
  loop {
    screen.blank_screen(start_line);
    screen.move_cursor(start_line, 0);
    let matches = matching::compute_matches(&choices, search.as_slice());
    let mut i = 1;
    screen.write(format!("> {} ({} choices)\n", search.as_slice(), choices.len()).as_slice());
    for choice in matches.iter() {
      if i == index + 1 {
        screen.write_inverted(choice.as_slice());
      } else {
        screen.write(choice.as_slice());
      }
      if i >= visible_choices as usize {
        break;
      } else {
        screen.write("\n");
      }
      i += 1;
    }

    screen.move_cursor(start_line, 2 + search.len() as u16);

    match screen.tty.getchar() {
      Char(x) => search.push(x),
      Backspace => { search.pop(); }
      Control('h') => { search.pop(); }
      Control('u') => { search.clear(); }
      Control('c') => { return; }
      Control('n') => { index += 1; }
      Control('p') => { index -= 1; }
      Enter => {
        screen.move_cursor(start_line + visible_choices, 0);
        screen.write("\n");
        println!("{}", matches[index]);
        break;
      }
      _ => panic!("Unexpected input"),
    }
  }
}

fn read_choices() -> Vec<String> {
  let mut stdin = io::stdio::stdin();
  let mut lines = Vec::new();

  loop {
    match stdin.read_line() {
      Ok(x) => lines.push(String::from_str(x.as_slice().trim())),
      Err(_) => break,
    }
  }

  lines
}
<commit_msg>Read stdin fully before initializing screen<commit_after>#![allow(unstable, dead_code)]

extern crate libc;

mod args;
mod ansi;
mod matching;
mod screen;

use std::os;
use std::io;
use std::cmp::min;
use screen::Screen;
use screen::Key::*;

fn main() {
  let args = match args::parse_args() {
    Some(args) => args,
    None => {
      os::set_exit_status(1);
      return;
    },
  };

  if args.help { return; }

  let choices = read_choices();

  let mut screen = Screen::open_screen();
  let mut index = 0;

  let visible_choices = min(20, screen.height - 1);

  let mut search = args.initial_search.clone();
  let start_line = screen.height - visible_choices - 1;
  loop {
    screen.blank_screen(start_line);
    screen.move_cursor(start_line, 0);
    let matches = matching::compute_matches(&choices, search.as_slice());
    let mut i = 1;
    screen.write(format!("> {} ({} choices)\n", search.as_slice(), choices.len()).as_slice());
    for choice in matches.iter() {
      if i == index + 1 {
        screen.write_inverted(choice.as_slice());
      } else {
        screen.write(choice.as_slice());
      }
      if i >= visible_choices as usize {
        break;
      } else {
        screen.write("\n");
      }
      i += 1;
    }

    screen.move_cursor(start_line, 2 + search.len() as u16);

    match screen.tty.getchar() {
      Char(x) => search.push(x),
      Backspace => { search.pop(); }
      Control('h') => { search.pop(); }
      Control('u') => { search.clear(); }
      Control('c') => { return; }
      Control('n') => { index += 1; }
      Control('p') => { index -= 1; }
      Enter => {
        screen.move_cursor(start_line + visible_choices, 0);
        screen.write("\n");
        println!("{}", matches[index]);
        break;
      }
      _ => panic!("Unexpected input"),
    }
  }
}

fn read_choices() -> Vec<String> {
  let mut stdin = io::stdio::stdin();
  let mut lines = Vec::new();

  loop {
    match stdin.read_line() {
      Ok(x) => lines.push(String::from_str(x.as_slice().trim())),
      Err(_) => break,
    }
  }

  lines
}
<|endoftext|>


<commit_before>#![warn(clippy::pedantic)]
#![allow(
    clippy::cast_possible_truncation,
    clippy::cast_possible_wrap,
    clippy::cast_sign_loss,
    clippy::enum_glob_use,
    clippy::module_name_repetitions,
    clippy::single_match_else,
    clippy::too_many_arguments,
    clippy::too_many_lines,
    clippy::unused_async,
    clippy::wildcard_imports
)]

#[macro_use]
mod macros;

mod agents;
mod bridges;
mod config;
mod crypto;
mod email_address;
mod error;
mod handlers;
mod metrics;
mod router;
mod utils;
mod validation;
mod web;
mod webfinger;

use crate::agents::{Expiring, ExportKeySet, ImportKeySet, KeySet};
use crate::config::{ConfigBuilder, ConfigRc};
use crate::utils::{pem, BoxError};
use crate::web::Service;
use futures_util::future;
use hyper::{server::Server, service::make_service_fn};
use serde::Deserialize;
use std::collections::HashMap;
use std::fs::File;
use std::io::{BufReader, Write};
use std::{
    net::SocketAddr,
    path::{Path, PathBuf},
    time::SystemTime,
};

/// Defines the program's version, as set by Cargo at compile time.
const VERSION: &str = env!("CARGO_PKG_VERSION");

/// Defines the program's usage string.
///
/// [Docopt](http://docopt.org) parses this and generates a custom argv parser.
const USAGE: &str = r#"
Portier Broker

Usage:
  portier-broker [CONFIG]
  portier-broker [CONFIG] --import-keys FILE [--dry-run]
  portier-broker [CONFIG] --export-keys FILE
  portier-broker --version
  portier-broker --help

Options:
  --version           Print version information and exit
  --help              Print this help message and exit

  --import-keys FILE  Import PEM private keys
  --dry-run           Parse PEM to be imported, but don't apply changes

  --export-keys FILE  Export currently active private keys as PEM
"#;

/// Holds parsed command line parameters.
#[derive(Deserialize)]
#[allow(non_snake_case)]
struct Args {
    arg_CONFIG: Option<PathBuf>,
    flag_import_keys: Option<PathBuf>,
    flag_export_keys: Option<PathBuf>,
    flag_dry_run: bool,
}

/// The `main()` method. Will loop forever to serve HTTP requests.
#[tokio::main]
async fn main() {
    crate::utils::logger::init();

    // We spawn a bunch of background tasks on the Tokio executor. If these panic, we want to exit
    // instead of continuing on without the task.
    let next_panic_hook = std::panic::take_hook();
    std::panic::set_hook(Box::new(move |info| {
        next_panic_hook(info);
        std::process::exit(1);
    }));

    let args: Args = docopt::Docopt::new(USAGE)
        .map(|docopt| docopt.version(Some(VERSION.to_owned())))
        .and_then(|docopt| docopt.deserialize())
        .unwrap_or_else(|e| e.exit());

    let mut builder = ConfigBuilder::new();
    if let Some(ref path) = args.arg_CONFIG {
        builder.update_from_file(path);
    }
    builder.update_from_common_env();
    builder.update_from_broker_env();

    if let Some(ref path) = args.flag_import_keys {
        import_keys(builder, path, args.flag_dry_run).await;
    } else if let Some(ref path) = args.flag_export_keys {
        export_keys(builder, path).await;
    } else {
        start_server(builder).await;
    }
}

async fn start_server(builder: ConfigBuilder) {
    let app = ConfigRc::new(
        builder
            .done()
            .await
            .unwrap_or_else(|err| panic!("failed to build configuration: {}", err)),
    );

    // TODO: Add unix socket support.
    let builder = match listenfd::ListenFd::from_env().take_tcp_listener(0) {
        Ok(Some(tcp_listener)) => {
            let builder = Server::from_tcp(tcp_listener).expect("Socket activation failed");
            log::info!("Listening on the socket received from the service manager");
            builder
        }
        Ok(None) => {
            let ip_addr = app
                .listen_ip
                .parse()
                .expect("Unable to parse listen address");
            let addr = SocketAddr::new(ip_addr, app.listen_port);
            let builder = Server::bind(&addr);
            log::info!("Listening on {}", addr);
            builder
        }
        Err(err) => {
            panic!("Socket activation failed: {}", err);
        }
    };

    #[cfg(unix)]
    sd_notify::notify(true, &[sd_notify::NotifyState::Ready])
        .expect("Failed to signal ready to the service manager");

    let make_service = make_service_fn(|stream| {
        metrics::HTTP_CONNECTIONS.inc();
        let app = ConfigRc::clone(&app);
        future::ok::<_, BoxError>(Service::new(app, stream))
    });
    let server = builder.serve(make_service);

    let (exit_tx, mut exit_rx) = tokio::sync::mpsc::channel(1);
    ctrlc::set_handler(move || {
        exit_tx
            .blocking_send(())
            .expect("Could not send the exit signal")
    })
    .expect("Could not install the exit signal handler");
    let server = server.with_graceful_shutdown(async move {
        exit_rx
            .recv()
            .await
            .expect("Could not wait for the exit signal");
        log::info!("Shutting down");
    });

    server.await.expect("Server error");
    log::info!("Shutdown complete");
}

async fn import_keys(builder: ConfigBuilder, path: &Path, dry_run: bool) {
    if builder.is_keyed_manually() {
        eprintln!("Importing keys, but configuration uses manual keying.");
        eprintln!("Make sure to remove 'keyfiles' and 'keytext' options");
        eprintln!("afterwards, to switch to automatic key rotation.");
    }

    let entries = if path == Path::new("-") {
        pem::parse_key_pairs(BufReader::new(std::io::stdin())).expect("Could not read from stdin")
    } else {
        let file = File::open(path).expect("Could not open file");
        pem::parse_key_pairs(BufReader::new(file)).expect("Could not read from file")
    };

    let mut key_sets = HashMap::new();
    let mut fail = false;
    for (idx, result) in entries.into_iter().enumerate() {
        let idx = idx + 1;
        let entry = match result {
            Ok(entry) => entry,
            Err(err) => {
                eprintln!("#{}: parse error, {}", idx, err);
                fail = true;
                continue;
            }
        };

        let alg = entry.key_pair.signing_alg();
        if !builder.signing_algs.contains(&alg) {
            eprintln!("#{}: ignored, disabled signing algorithm", idx);
            continue;
        }

        let key_set = key_sets.entry(alg).or_insert(KeySet {
            signing_alg: alg,
            current: None,
            next: None,
            previous: None,
        });

        let fp = entry.raw.fingerprint();
        let (purpose, lifespan) = if key_set.current.is_none() {
            let lifespan = builder.keys_ttl;
            key_set.current = Some(Expiring {
                value: entry.raw.encode(),
                expires: SystemTime::now() + lifespan,
            });
            ("current", Some(lifespan))
        } else if key_set.next.is_none() {
            let lifespan = builder.keys_ttl * 2;
            key_set.next = Some(Expiring {
                value: entry.raw.encode(),
                expires: SystemTime::now() + lifespan,
            });
            ("next", Some(lifespan))
        } else if key_set.previous.is_none() {
            key_set.previous = Some(entry.raw.encode());
            ("previous", None)
        } else {
            eprintln!("#{}: too many keys for signing algorithm {}", idx, alg);
            fail = true;
            continue;
        };

        if let Some(lifespan) = lifespan {
            eprintln!(
                "#{}: found {} key, fingerprint: {} (as {}, expires in {:?})",
                idx, alg, fp, purpose, lifespan
            );
        } else {
            eprintln!(
                "#{}: found {} key, fingerprint: {} (as {})",
                idx, alg, fp, purpose
            );
        }
    }
    if fail {
        eprintln!("Aborting because of errors");
        std::process::exit(1);
    }
    if key_sets.is_empty() {
        eprintln!("No private keys found");
        std::process::exit(1);
    }

    eprintln!("NOTE: Expiration times cannot be imported, and were reset");

    if dry_run {
        eprintln!("NOTE: Dry run, not applying changes");
    } else {
        let store = builder
            .into_store()
            .await
            .unwrap_or_else(|err| panic!("Failed to build configuration: {}", err));
        for (alg, key_set) in key_sets {
            store.send(ImportKeySet(key_set)).await;
            eprintln!("Successfully imported {} keys", alg);
        }
    }

    // TODO: This is a little hacky, but we don't have code to shutdown gracefully.
    // (Currently, if a Redis store is simply dropped, the pubsub task panics.)
    std::process::exit(0);
}

async fn export_keys(builder: ConfigBuilder, path: &Path) {
    if builder.is_keyed_manually() {
        eprintln!("Exporting keys, but configuration uses manual keying.");
    }

    let mut writer: Box<dyn Write> = if path == Path::new("-") {
        Box::new(std::io::stdout())
    } else {
        Box::new(File::create(path).expect("Could not create file"))
    };

    let mut num: usize = 0;
    let signing_algs = builder.signing_algs.clone();
    let store = builder
        .into_store()
        .await
        .unwrap_or_else(|err| panic!("Failed to build configuration: {}", err));
    for alg in signing_algs {
        let key_set = store.send(ExportKeySet(alg)).await;
        if let Some(key) = key_set.current {
            writer
                .write_all(key.value.as_bytes())
                .expect("Write failed");
            num += 1;
        }
        if let Some(key) = key_set.next {
            writer
                .write_all(key.value.as_bytes())
                .expect("Write failed");
            num += 1;
        }
        if let Some(key) = key_set.previous {
            writer.write_all(key.as_bytes()).expect("Write failed");
            num += 1;
        }
    }
    if num == 0 {
        eprintln!("No private keys found in the store");
        std::process::exit(1);
    }
    writer.flush().expect("Flush failed");
    drop(writer);
    eprintln!("Exported {} private keys", num);
    eprintln!("NOTE: The output does not contain expiration times");

    // TODO: This is a little hacky, but we don't have code to shutdown gracefully.
    // (Currently, if a Redis store is simply dropped, the pubsub task panics.)
    std::process::exit(0);
}
<commit_msg>Fix clippy lint<commit_after>#![warn(clippy::pedantic)]
#![allow(
    clippy::cast_possible_truncation,
    clippy::cast_possible_wrap,
    clippy::cast_sign_loss,
    clippy::enum_glob_use,
    clippy::module_name_repetitions,
    clippy::single_match_else,
    clippy::too_many_arguments,
    clippy::too_many_lines,
    clippy::unused_async,
    clippy::wildcard_imports
)]

#[macro_use]
mod macros;

mod agents;
mod bridges;
mod config;
mod crypto;
mod email_address;
mod error;
mod handlers;
mod metrics;
mod router;
mod utils;
mod validation;
mod web;
mod webfinger;

use crate::agents::{Expiring, ExportKeySet, ImportKeySet, KeySet};
use crate::config::{ConfigBuilder, ConfigRc};
use crate::utils::{pem, BoxError};
use crate::web::Service;
use futures_util::future;
use hyper::{server::Server, service::make_service_fn};
use serde::Deserialize;
use std::collections::HashMap;
use std::fs::File;
use std::io::{BufReader, Write};
use std::{
    net::SocketAddr,
    path::{Path, PathBuf},
    time::SystemTime,
};

/// Defines the program's version, as set by Cargo at compile time.
const VERSION: &str = env!("CARGO_PKG_VERSION");

/// Defines the program's usage string.
///
/// [Docopt](http://docopt.org) parses this and generates a custom argv parser.
const USAGE: &str = r#"
Portier Broker

Usage:
  portier-broker [CONFIG]
  portier-broker [CONFIG] --import-keys FILE [--dry-run]
  portier-broker [CONFIG] --export-keys FILE
  portier-broker --version
  portier-broker --help

Options:
  --version           Print version information and exit
  --help              Print this help message and exit

  --import-keys FILE  Import PEM private keys
  --dry-run           Parse PEM to be imported, but don't apply changes

  --export-keys FILE  Export currently active private keys as PEM
"#;

/// Holds parsed command line parameters.
#[derive(Deserialize)]
#[allow(non_snake_case)]
struct Args {
    arg_CONFIG: Option<PathBuf>,
    flag_import_keys: Option<PathBuf>,
    flag_export_keys: Option<PathBuf>,
    flag_dry_run: bool,
}

/// The `main()` method. Will loop forever to serve HTTP requests.
#[tokio::main]
async fn main() {
    crate::utils::logger::init();

    // We spawn a bunch of background tasks on the Tokio executor. If these panic, we want to exit
    // instead of continuing on without the task.
    let next_panic_hook = std::panic::take_hook();
    std::panic::set_hook(Box::new(move |info| {
        next_panic_hook(info);
        std::process::exit(1);
    }));

    let args: Args = docopt::Docopt::new(USAGE)
        .map(|docopt| docopt.version(Some(VERSION.to_owned())))
        .and_then(|docopt| docopt.deserialize())
        .unwrap_or_else(|e| e.exit());

    let mut builder = ConfigBuilder::new();
    if let Some(ref path) = args.arg_CONFIG {
        builder.update_from_file(path);
    }
    builder.update_from_common_env();
    builder.update_from_broker_env();

    if let Some(ref path) = args.flag_import_keys {
        import_keys(builder, path, args.flag_dry_run).await;
    } else if let Some(ref path) = args.flag_export_keys {
        export_keys(builder, path).await;
    } else {
        start_server(builder).await;
    }
}

async fn start_server(builder: ConfigBuilder) {
    let app = ConfigRc::new(
        builder
            .done()
            .await
            .unwrap_or_else(|err| panic!("failed to build configuration: {}", err)),
    );

    // TODO: Add unix socket support.
    let builder = match listenfd::ListenFd::from_env().take_tcp_listener(0) {
        Ok(Some(tcp_listener)) => {
            let builder = Server::from_tcp(tcp_listener).expect("Socket activation failed");
            log::info!("Listening on the socket received from the service manager");
            builder
        }
        Ok(None) => {
            let ip_addr = app
                .listen_ip
                .parse()
                .expect("Unable to parse listen address");
            let addr = SocketAddr::new(ip_addr, app.listen_port);
            let builder = Server::bind(&addr);
            log::info!("Listening on {}", addr);
            builder
        }
        Err(err) => {
            panic!("Socket activation failed: {}", err);
        }
    };

    #[cfg(unix)]
    sd_notify::notify(true, &[sd_notify::NotifyState::Ready])
        .expect("Failed to signal ready to the service manager");

    let make_service = make_service_fn(|stream| {
        metrics::HTTP_CONNECTIONS.inc();
        let app = ConfigRc::clone(&app);
        future::ok::<_, BoxError>(Service::new(app, stream))
    });
    let server = builder.serve(make_service);

    let (exit_tx, mut exit_rx) = tokio::sync::mpsc::channel(1);
    ctrlc::set_handler(move || {
        exit_tx
            .blocking_send(())
            .expect("Could not send the exit signal");
    })
    .expect("Could not install the exit signal handler");
    let server = server.with_graceful_shutdown(async move {
        exit_rx
            .recv()
            .await
            .expect("Could not wait for the exit signal");
        log::info!("Shutting down");
    });

    server.await.expect("Server error");
    log::info!("Shutdown complete");
}

async fn import_keys(builder: ConfigBuilder, path: &Path, dry_run: bool) {
    if builder.is_keyed_manually() {
        eprintln!("Importing keys, but configuration uses manual keying.");
        eprintln!("Make sure to remove 'keyfiles' and 'keytext' options");
        eprintln!("afterwards, to switch to automatic key rotation.");
    }

    let entries = if path == Path::new("-") {
        pem::parse_key_pairs(BufReader::new(std::io::stdin())).expect("Could not read from stdin")
    } else {
        let file = File::open(path).expect("Could not open file");
        pem::parse_key_pairs(BufReader::new(file)).expect("Could not read from file")
    };

    let mut key_sets = HashMap::new();
    let mut fail = false;
    for (idx, result) in entries.into_iter().enumerate() {
        let idx = idx + 1;
        let entry = match result {
            Ok(entry) => entry,
            Err(err) => {
                eprintln!("#{}: parse error, {}", idx, err);
                fail = true;
                continue;
            }
        };

        let alg = entry.key_pair.signing_alg();
        if !builder.signing_algs.contains(&alg) {
            eprintln!("#{}: ignored, disabled signing algorithm", idx);
            continue;
        }

        let key_set = key_sets.entry(alg).or_insert(KeySet {
            signing_alg: alg,
            current: None,
            next: None,
            previous: None,
        });

        let fp = entry.raw.fingerprint();
        let (purpose, lifespan) = if key_set.current.is_none() {
            let lifespan = builder.keys_ttl;
            key_set.current = Some(Expiring {
                value: entry.raw.encode(),
                expires: SystemTime::now() + lifespan,
            });
            ("current", Some(lifespan))
        } else if key_set.next.is_none() {
            let lifespan = builder.keys_ttl * 2;
            key_set.next = Some(Expiring {
                value: entry.raw.encode(),
                expires: SystemTime::now() + lifespan,
            });
            ("next", Some(lifespan))
        } else if key_set.previous.is_none() {
            key_set.previous = Some(entry.raw.encode());
            ("previous", None)
        } else {
            eprintln!("#{}: too many keys for signing algorithm {}", idx, alg);
            fail = true;
            continue;
        };

        if let Some(lifespan) = lifespan {
            eprintln!(
                "#{}: found {} key, fingerprint: {} (as {}, expires in {:?})",
                idx, alg, fp, purpose, lifespan
            );
        } else {
            eprintln!(
                "#{}: found {} key, fingerprint: {} (as {})",
                idx, alg, fp, purpose
            );
        }
    }
    if fail {
        eprintln!("Aborting because of errors");
        std::process::exit(1);
    }
    if key_sets.is_empty() {
        eprintln!("No private keys found");
        std::process::exit(1);
    }

    eprintln!("NOTE: Expiration times cannot be imported, and were reset");

    if dry_run {
        eprintln!("NOTE: Dry run, not applying changes");
    } else {
        let store = builder
            .into_store()
            .await
            .unwrap_or_else(|err| panic!("Failed to build configuration: {}", err));
        for (alg, key_set) in key_sets {
            store.send(ImportKeySet(key_set)).await;
            eprintln!("Successfully imported {} keys", alg);
        }
    }

    // TODO: This is a little hacky, but we don't have code to shutdown gracefully.
    // (Currently, if a Redis store is simply dropped, the pubsub task panics.)
    std::process::exit(0);
}

async fn export_keys(builder: ConfigBuilder, path: &Path) {
    if builder.is_keyed_manually() {
        eprintln!("Exporting keys, but configuration uses manual keying.");
    }

    let mut writer: Box<dyn Write> = if path == Path::new("-") {
        Box::new(std::io::stdout())
    } else {
        Box::new(File::create(path).expect("Could not create file"))
    };

    let mut num: usize = 0;
    let signing_algs = builder.signing_algs.clone();
    let store = builder
        .into_store()
        .await
        .unwrap_or_else(|err| panic!("Failed to build configuration: {}", err));
    for alg in signing_algs {
        let key_set = store.send(ExportKeySet(alg)).await;
        if let Some(key) = key_set.current {
            writer
                .write_all(key.value.as_bytes())
                .expect("Write failed");
            num += 1;
        }
        if let Some(key) = key_set.next {
            writer
                .write_all(key.value.as_bytes())
                .expect("Write failed");
            num += 1;
        }
        if let Some(key) = key_set.previous {
            writer.write_all(key.as_bytes()).expect("Write failed");
            num += 1;
        }
    }
    if num == 0 {
        eprintln!("No private keys found in the store");
        std::process::exit(1);
    }
    writer.flush().expect("Flush failed");
    drop(writer);
    eprintln!("Exported {} private keys", num);
    eprintln!("NOTE: The output does not contain expiration times");

    // TODO: This is a little hacky, but we don't have code to shutdown gracefully.
    // (Currently, if a Redis store is simply dropped, the pubsub task panics.)
    std::process::exit(0);
}
<|endoftext|>