<commit_before>extern crate case;
extern crate docopt;
extern crate env_logger;
extern crate git2;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
extern crate xml;
extern crate toml;

use env::Env;
use library::*;

//generated by build.rs
mod gir_version;

mod analysis;
mod codegen;
mod config;
mod env;
mod file_saver;
mod git;
mod gobjects;
mod library;
mod nameutil;
mod parser;
mod traits;
mod version;

#[cfg_attr(test, allow(dead_code))]
fn main() {
    env_logger::init().unwrap_or_else(|e| panic!("{}", e));

    let cfg = match config::Config::new() {
        Ok(c) => c,
        Err(config::Error::CommandLine(e)) => e.exit(),
        Err(e) => {
            println!("{}", e);
            ::std::process::exit(1);
        }
    };

    let mut library = Library::new(&cfg.library_name);
    library.read_file(&cfg.girs_dir, &cfg.library_full_name());
    library.fill_in();
    //show(&library);

    let env = Env{ library: library, config: cfg };
    codegen::generate(&env);
}

#[allow(dead_code)]
fn show(library: &Library) {
    for ns in &library.namespaces {
        println!("Namespace: {}", ns.name);
        print!("\tNames: ");
        for name in ns.index.keys() {
            print!("{}, ", name);
        }
        println!("");

        for typ in &ns.types {
            match *typ {
                Some(Type::Class(ref x)) => println!("\tclass {}", x.name),
                Some(Type::Record(ref x)) => println!("\trecord {}", x.name),
                Some(Type::Union(ref x)) => println!("\tunion {}", x.name),
                Some(Type::Interface(ref x)) => println!("\tinterface {}", x.name),
                Some(Type::Function(ref x)) => println!("\tcallback {}", x.name),
                Some(Type::Bitfield(ref x)) => println!("\tbitfield {}", x.name),
                Some(Type::Enumeration(ref x)) => println!("\tenumeration {}", x.name),
                _ => (),
            }
        }
        for c in &ns.constants {
            println!("\tconst {} = {}", c.name, c.value);
        }
        for f in &ns.functions {
            println!("\tfunction {}", f.name);
        }
    }
}
<commit_msg>Remove dead code<commit_after>extern crate case;
extern crate docopt;
extern crate env_logger;
extern crate git2;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
extern crate xml;
extern crate toml;

use env::Env;
use library::Library;

//generated by build.rs
mod gir_version;

mod analysis;
mod codegen;
mod config;
mod env;
mod file_saver;
mod git;
mod gobjects;
mod library;
mod nameutil;
mod parser;
mod traits;
mod version;

#[cfg_attr(test, allow(dead_code))]
fn main() {
    env_logger::init().unwrap_or_else(|e| panic!("{}", e));

    let cfg = match config::Config::new() {
        Ok(c) => c,
        Err(config::Error::CommandLine(e)) => e.exit(),
        Err(e) => {
            println!("{}", e);
            ::std::process::exit(1);
        }
    };

    let mut library = Library::new(&cfg.library_name);
    library.read_file(&cfg.girs_dir, &cfg.library_full_name());
    library.fill_in();

    let env = Env{ library: library, config: cfg };
    codegen::generate(&env);
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate ecs;

use ecs::{World, BuildData, DataHelper, EntityIter, ModifyData, Process, System};
use ecs::system::{EntityProcess, EntitySystem};
use std::io;

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Location {
    pub row: u32,
    pub column: u32,
    pub occupant: char,
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Position {
    pub x: u32,
    pub y: u32,
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Velocity {
    pub dx: u32,
    pub dy: u32,
}

pub struct MotionProcess;

impl System for MotionProcess {
    type Components = WorldComponents;
    type Services = ();
}

impl EntityProcess for MotionProcess {
    fn process(&mut self,
               entities: EntityIter<WorldComponents>,
               data: &mut DataHelper<WorldComponents, ()>) {
        for e in entities {
            let mut position = data.position[e];
            let velocity = data.velocity[e];

            position.x += velocity.dx;
            position.y += velocity.dy;
            data.position[e] = position;
        }
    }
}

pub struct Command(pub String);

pub struct CommandProcess;

impl System for CommandProcess {
    type Components = WorldComponents;
    type Services = ();
}

impl EntityProcess for CommandProcess {
    fn process(&mut self,
               entities: EntityIter<WorldComponents>,
               data: &mut DataHelper<WorldComponents, ()>) {
        for e in entities {
        }
    }
}

pub struct PrintMessage(pub String);

impl System for PrintMessage {
    type Components = WorldComponents;
    type Services = ();
}

impl Process for PrintMessage {
    fn process(&mut self, _: &mut DataHelper<WorldComponents, ()>) {
        println!("{}", &self.0);
    }
}

components! {
    struct WorldComponents {
        #[hot] command: Command,
        #[hot] position: Position,
        #[hot] velocity: Velocity,
        #[cold] location: Location,
    }
}

systems! {
    struct WorldSystems<WorldComponents, ()> {
        active: {
            motion: EntitySystem<MotionProcess> = EntitySystem::new(
                MotionProcess,
                aspect!(<WorldComponents> all:
                        [position, velocity, location])
            ),
            print_msg: PrintMessage =
                PrintMessage("Hello World".to_string()),
        },
        passive: {}
    }
}

fn main() {
    let mut world = World::<WorldSystems>::new();
    let entity = world.create_entity(|entity: BuildData<WorldComponents>,
                                      data: &mut WorldComponents| {
        data.position.add(&entity, Position { x: 0, y: 0 });
        data.velocity.add(&entity, Velocity { dx: 0, dy: 0 });
    });
    let world_map = world.create_entity(|entity: BuildData<WorldComponents>,
                                      data: &mut WorldComponents| {
        data.location.add(&entity, Location { row: 0, column: 0, occupant: '🌲' });
        data.location.add(&entity, Location { row: 0, column: 1, occupant: '🌲' });
        data.location.add(&entity, Location { row: 0, column: 2, occupant: '🌲' });
        data.location.add(&entity, Location { row: 0, column: 3, occupant: '🌳' });
        data.location.add(&entity, Location { row: 0, column: 4, occupant: '🌲' });
        data.location.add(&entity, Location { row: 0, column: 5, occupant: '🌲' });
        data.location.add(&entity, Location { row: 0, column: 6, occupant: '🌲' });
        data.location.add(&entity, Location { row: 0, column: 7, occupant: '🌲' });
        data.location.add(&entity, Location { row: 0, column: 8, occupant: '🌲' });
        data.location.add(&entity, Location { row: 0, column: 9, occupant: '🌲' });
        data.location.add(&entity, Location { row: 1, column: 0, occupant: '🌲' });
        data.location.add(&entity, Location { row: 1, column: 1, occupant: '⬚' });
        data.location.add(&entity, Location { row: 1, column: 2, occupant: '⬚' });
        data.location.add(&entity, Location { row: 1, column: 3, occupant: '⬚' });
        data.location.add(&entity, Location { row: 1, column: 4, occupant: '⬚' });
        data.location.add(&entity, Location { row: 1, column: 5, occupant: '⬚' });
        data.location.add(&entity, Location { row: 1, column: 6, occupant: '⬚' });
        data.location.add(&entity, Location { row: 1, column: 7, occupant: '⬚' });
        data.location.add(&entity, Location { row: 1, column: 8, occupant: '⬚' });
        data.location.add(&entity, Location { row: 1, column: 9, occupant: '🌲' });
        data.location.add(&entity, Location { row: 2, column: 0, occupant: '🌲' });
        data.location.add(&entity, Location { row: 2, column: 1, occupant: '⬚' });
        data.location.add(&entity, Location { row: 2, column: 2, occupant: '⬚' });
        data.location.add(&entity, Location { row: 2, column: 3, occupant: '⬚' });
        data.location.add(&entity, Location { row: 2, column: 4, occupant: '⬚' });
        data.location.add(&entity, Location { row: 2, column: 5, occupant: '⬚' });
        data.location.add(&entity, Location { row: 2, column: 6, occupant: '⬚' });
        data.location.add(&entity, Location { row: 2, column: 7, occupant: '⬚' });
        data.location.add(&entity, Location { row: 2, column: 8, occupant: '⬚' });
        data.location.add(&entity, Location { row: 2, column: 9, occupant: '🌲' });
        data.location.add(&entity, Location { row: 3, column: 0, occupant: '🌲' });
        data.location.add(&entity, Location { row: 3, column: 1, occupant: '⬚' });
        data.location.add(&entity, Location { row: 3, column: 2, occupant: '⬚' });
        data.location.add(&entity, Location { row: 3, column: 3, occupant: '⬚' });
        data.location.add(&entity, Location { row: 3, column: 4, occupant: '⬚' });
        data.location.add(&entity, Location { row: 3, column: 5, occupant: '⬚' });
        data.location.add(&entity, Location { row: 3, column: 6, occupant: '⬚' });
        data.location.add(&entity, Location { row: 3, column: 7, occupant: '⬚' });
        data.location.add(&entity, Location { row: 3, column: 8, occupant: '⬚' });
        data.location.add(&entity, Location { row: 3, column: 9, occupant: '🌲' });
        data.location.add(&entity, Location { row: 4, column: 0, occupant: '🌲' });
        data.location.add(&entity, Location { row: 4, column: 1, occupant: '🌲' });
        data.location.add(&entity, Location { row: 4, column: 2, occupant: '🌲' });
        data.location.add(&entity, Location { row: 4, column: 3, occupant: '🌲' });
        data.location.add(&entity, Location { row: 4, column: 4, occupant: '🌲' });
        data.location.add(&entity, Location { row: 4, column: 5, occupant: '🌲' });
        data.location.add(&entity, Location { row: 4, column: 6, occupant: '🌲' });
        data.location.add(&entity, Location { row: 4, column: 7, occupant: '🌲' });
        data.location.add(&entity, Location { row: 4, column: 8, occupant: '🌲' });
        data.location.add(&entity, Location { row: 4, column: 9, occupant: '🌲' });
    });

    loop {
        let mut input = String::new();
        if let Ok(_) = io::stdin().read_line(&mut input) {
            world.systems.print_msg.0 = format!("Command: {}", input);
            world.update();
        }
    }
}
<commit_msg>Started to implement render view to display the view at the players location with HUD.<commit_after>#[macro_use]
extern crate ecs;

use ecs::{World, BuildData, DataHelper, EntityIter, ModifyData, Process, System};
use ecs::system::{EntityProcess, EntitySystem};
use std::io;

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Location {
    pub row: i32,
    pub column: i32,
    pub occupant: char,
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Position {
    pub x: i32,
    pub y: i32,
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Velocity {
    pub dx: i32,
    pub dy: i32,
}

pub struct MotionProcess;

impl System for MotionProcess {
    type Components = WorldComponents;
    type Services = ();
}

impl EntityProcess for MotionProcess {
    fn process(&mut self,
               entities: EntityIter<WorldComponents>,
               data: &mut DataHelper<WorldComponents, ()>) {
        for e in entities {
            let mut position = data.position[e];
            let velocity = data.velocity[e];

            position.x += velocity.dx;
            position.y += velocity.dy;
            data.position[e] = position;
        }
    }
}

pub struct Command(pub String);

pub struct CommandProcess;

impl System for CommandProcess {
    type Components = WorldComponents;
    type Services = ();
}

impl EntityProcess for CommandProcess {
    fn process(&mut self,
               entities: EntityIter<WorldComponents>,
               data: &mut DataHelper<WorldComponents, ()>) {
        for e in entities {
        }
    }
}

pub struct RenderView;

impl System for RenderView {
    type Components = WorldComponents;
    type Services = ();
}

impl EntityProcess for RenderView {
    fn process(&mut self,
               entities: EntityIter<WorldComponents>,
               data: &mut DataHelper<WorldComponents, ()>) {
        let view = String::new();
        for e in entities {
        }
        //println!("{}", view);
    }
}

components! {
    struct WorldComponents {
        #[hot] command: Command,
        #[hot] position: Position,
        #[hot] velocity: Velocity,
        #[hot] location: Location,
    }
}

systems! {
    struct WorldSystems<WorldComponents, ()> {
        active: {
            motion: EntitySystem<MotionProcess> = EntitySystem::new(
                MotionProcess,
                aspect!(<WorldComponents> all: [position, velocity])
            ),
            render: EntitySystem<RenderView> = EntitySystem::new(
                RenderView,
                aspect!(<WorldComponents> all: [location])
            ),
        },
        passive: {}
    }
}

fn main() {
    let mut world = World::<WorldSystems>::new();
    let entity = world.create_entity(|entity: BuildData<WorldComponents>,
                                      data: &mut WorldComponents| {
        data.position.add(&entity, Position { x: 0, y: 0 });
        data.velocity.add(&entity, Velocity { dx: 0, dy: 0 });
    });
    let world_map = world.create_entity(|entity: BuildData<WorldComponents>,
                                      data: &mut WorldComponents| {
        data.location.add(&entity, Location { row: 0, column: 0, occupant: '🌲' });
        data.location.add(&entity, Location { row: 0, column: 1, occupant: '🌲' });
        data.location.add(&entity, Location { row: 0, column: 2, occupant: '🌲' });
        data.location.add(&entity, Location { row: 0, column: 3, occupant: '🌳' });
        data.location.add(&entity, Location { row: 0, column: 4, occupant: '🌲' });
        data.location.add(&entity, Location { row: 0, column: 5, occupant: '🌲' });
        data.location.add(&entity, Location { row: 0, column: 6, occupant: '🌲' });
        data.location.add(&entity, Location { row: 0, column: 7, occupant: '🌲' });
        data.location.add(&entity, Location { row: 0, column: 8, occupant: '🌲' });
        data.location.add(&entity, Location { row: 0, column: 9, occupant: '🌲' });
        data.location.add(&entity, Location { row: 1, column: 0, occupant: '🌲' });
        data.location.add(&entity, Location { row: 1, column: 1, occupant: '⬚' });
        data.location.add(&entity, Location { row: 1, column: 2, occupant: '⬚' });
        data.location.add(&entity, Location { row: 1, column: 3, occupant: '⬚' });
        data.location.add(&entity, Location { row: 1, column: 4, occupant: '⬚' });
        data.location.add(&entity, Location { row: 1, column: 5, occupant: '⬚' });
        data.location.add(&entity, Location { row: 1, column: 6, occupant: '⬚' });
        data.location.add(&entity, Location { row: 1, column: 7, occupant: '⬚' });
        data.location.add(&entity, Location { row: 1, column: 8, occupant: '⬚' });
        data.location.add(&entity, Location { row: 1, column: 9, occupant: '🌲' });
        data.location.add(&entity, Location { row: 2, column: 0, occupant: '🌲' });
        data.location.add(&entity, Location { row: 2, column: 1, occupant: '⬚' });
        data.location.add(&entity, Location { row: 2, column: 2, occupant: '⬚' });
        data.location.add(&entity, Location { row: 2, column: 3, occupant: '⬚' });
        data.location.add(&entity, Location { row: 2, column: 4, occupant: '⬚' });
        data.location.add(&entity, Location { row: 2, column: 5, occupant: '⬚' });
        data.location.add(&entity, Location { row: 2, column: 6, occupant: '⬚' });
        data.location.add(&entity, Location { row: 2, column: 7, occupant: '⬚' });
        data.location.add(&entity, Location { row: 2, column: 8, occupant: '⬚' });
        data.location.add(&entity, Location { row: 2, column: 9, occupant: '🌲' });
        data.location.add(&entity, Location { row: 3, column: 0, occupant: '🌲' });
        data.location.add(&entity, Location { row: 3, column: 1, occupant: '⬚' });
        data.location.add(&entity, Location { row: 3, column: 2, occupant: '⬚' });
        data.location.add(&entity, Location { row: 3, column: 3, occupant: '⬚' });
        data.location.add(&entity, Location { row: 3, column: 4, occupant: '⬚' });
        data.location.add(&entity, Location { row: 3, column: 5, occupant: '⬚' });
        data.location.add(&entity, Location { row: 3, column: 6, occupant: '⬚' });
        data.location.add(&entity, Location { row: 3, column: 7, occupant: '⬚' });
        data.location.add(&entity, Location { row: 3, column: 8, occupant: '⬚' });
        data.location.add(&entity, Location { row: 3, column: 9, occupant: '🌲' });
        data.location.add(&entity, Location { row: 4, column: 0, occupant: '🌲' });
        data.location.add(&entity, Location { row: 4, column: 1, occupant: '🌲' });
        data.location.add(&entity, Location { row: 4, column: 2, occupant: '🌲' });
        data.location.add(&entity, Location { row: 4, column: 3, occupant: '🌲' });
        data.location.add(&entity, Location { row: 4, column: 4, occupant: '🌲' });
        data.location.add(&entity, Location { row: 4, column: 5, occupant: '🌲' });
        data.location.add(&entity, Location { row: 4, column: 6, occupant: '🌲' });
        data.location.add(&entity, Location { row: 4, column: 7, occupant: '🌲' });
        data.location.add(&entity, Location { row: 4, column: 8, occupant: '🌲' });
        data.location.add(&entity, Location { row: 4, column: 9, occupant: '🌲' });
    });

    loop {
        let mut input = String::new();
        if let Ok(_) = io::stdin().read_line(&mut input) {
            world.update();
        }
    }
}
<|endoftext|>


<commit_before>#![feature(backtrace)]
#![recursion_limit = "256"]

use std::path::PathBuf;
use std::sync::{Arc, Mutex}; // TODO: async Mutex

use anyhow::Context;
use once_cell::sync::OnceCell;
use structopt::StructOpt;
use tbot;
use tokio;

mod client;
mod data;
mod feed;
mod fetcher;
mod gardener;
mod handlers;
mod messages;

use crate::data::Database;

static BOT_NAME: OnceCell<String> = OnceCell::new();
static BOT_ID: OnceCell<tbot::types::user::Id> = OnceCell::new();

#[derive(Debug, StructOpt)]
#[structopt(about = "A simple Telegram RSS bot.")]
struct Opt {
    /// Telegram bot token
    token: String,
    /// Path to database
    #[structopt(short = "d", long, default_value = "./rssbot.json")]
    database: PathBuf,

    #[structopt(long, default_value = "300")] // 5 minutes
    min_interval: u32,

    #[structopt(long, default_value = "43200")] // 12 hours
    max_interval: u32,
}

macro_rules! handle {
    ($env: expr, $f: expr) => {{
        let env = $env.clone();
        let f = $f;
        move |cmd| {
            let future = f(env.clone(), cmd);
            async {
                if let Err(e) = future.await {
                    dbg!(&e);
                    dbg!(e.backtrace());
                }
            }
        }
    }};
}

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let opt = Opt::from_args();
    let db = Arc::new(Mutex::new(Database::open(opt.database)?));
    let bot = tbot::Bot::new(opt.token);
    let me = bot
        .get_me()
        .call()
        .await
        .context("Initialization failed, check your network and Telegram token")?;

    BOT_NAME.set(me.user.username.clone().unwrap()).unwrap();
    BOT_ID.set(me.user.id).unwrap();

    gardener::start_pruning(bot.clone(), db.clone());
    fetcher::start(bot.clone(), db.clone(), opt.min_interval, opt.max_interval);
    let mut event_loop = bot.event_loop();
    event_loop.username(me.user.username.unwrap());
    event_loop.start(handle!(db, handlers::start));
    event_loop.command("rss", handle!(db, handlers::rss));
    event_loop.command("sub", handle!(db, handlers::sub));
    event_loop.command("unsub", handle!(db, handlers::unsub));
    event_loop.command("export", handle!(db, handlers::export));

    event_loop.polling().start().await.unwrap();
    Ok(())
}
<commit_msg>All `interval` arguments must >= 1<commit_after>#![feature(backtrace)]
#![recursion_limit = "256"]

use std::path::PathBuf;
use std::sync::{Arc, Mutex}; // TODO: async Mutex

use anyhow::Context;
use once_cell::sync::OnceCell;
use structopt::StructOpt;
use tbot;
use tokio;

mod client;
mod data;
mod feed;
mod fetcher;
mod gardener;
mod handlers;
mod messages;

use crate::data::Database;

static BOT_NAME: OnceCell<String> = OnceCell::new();
static BOT_ID: OnceCell<tbot::types::user::Id> = OnceCell::new();

#[derive(Debug, StructOpt)]
#[structopt(about = "A simple Telegram RSS bot.")]
struct Opt {
    /// Telegram bot token
    token: String,
    /// Path to database
    #[structopt(short = "d", long, default_value = "./rssbot.json")]
    database: PathBuf,

    #[structopt(long, default_value = "300", parse(try_from_str = parse_interval))] // 5 minutes
    min_interval: u32,

    #[structopt(long, default_value = "43200", parse(try_from_str = parse_interval))] // 12 hours
    max_interval: u32,
}

fn parse_interval(s: &str) -> Result<u32, String> {
    s.parse::<u32>().map_err(|e| e.to_string()).and_then(|r| {
        if r < 1 {
            Err("must >= 1".into())
        } else {
            Ok(r)
        }
    })
}

macro_rules! handle {
    ($env: expr, $f: expr) => {{
        let env = $env.clone();
        let f = $f;
        move |cmd| {
            let future = f(env.clone(), cmd);
            async {
                if let Err(e) = future.await {
                    dbg!(&e);
                    dbg!(e.backtrace());
                }
            }
        }
    }};
}

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let opt = Opt::from_args();
    let db = Arc::new(Mutex::new(Database::open(opt.database)?));
    let bot = tbot::Bot::new(opt.token);
    let me = bot
        .get_me()
        .call()
        .await
        .context("Initialization failed, check your network and Telegram token")?;

    BOT_NAME.set(me.user.username.clone().unwrap()).unwrap();
    BOT_ID.set(me.user.id).unwrap();

    gardener::start_pruning(bot.clone(), db.clone());
    fetcher::start(bot.clone(), db.clone(), opt.min_interval, opt.max_interval);
    let mut event_loop = bot.event_loop();
    event_loop.username(me.user.username.unwrap());
    event_loop.start(handle!(db, handlers::start));
    event_loop.command("rss", handle!(db, handlers::rss));
    event_loop.command("sub", handle!(db, handlers::sub));
    event_loop.command("unsub", handle!(db, handlers::unsub));
    event_loop.command("export", handle!(db, handlers::export));

    event_loop.polling().start().await.unwrap();
    Ok(())
}
<|endoftext|>


<commit_before>#![feature(plugin, custom_derive, conservative_impl_trait)]
#![plugin(rocket_codegen)]

extern crate rocket;
extern crate bbt;
extern crate rustc_serialize;
extern crate rand;
extern crate rusqlite;
extern crate toml;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate tera;
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_json;

use std::fs::File;
use std::path::{Path, PathBuf};
use std::io::Read;
use std::cmp::Ordering::{Greater, Less};
use std::collections::HashMap;
use std::sync::Mutex;
use rocket::request::{FormItems, FromFormValue, FromForm, Form};
use rocket::response::{NamedFile, Response, Redirect};
use rocket::http::Status;
use rocket::Data;
use rusqlite::Connection;
use tera::{Tera, Context, Value};
use bbt::{Rater, Rating};

mod balls;
mod errors;
mod games;
mod players;
mod statics;
mod ratings;
mod analysis;

const BETA: f64 = 5000.0;
const VERSION: &'static str = env!("CARGO_PKG_VERSION");
const INITIAL_DATE_CAP: &'static str = "now','-90 day";

pub type Res<'a> = Result<Response<'a>, Status>;

#[derive(Debug, RustcDecodable)]
pub struct Config {
    database: String,
    title: String,
    secret: String,
}

fn egg_filter(value: Value, args: HashMap<String, Value>) -> tera::Result<Value> {
    let goals = try_get_value!("egg", "value", i32, value);
    if goals == 0 {
        Ok(Value::String(format!(r#""#, try_get_value!("egg", "person", String, args["person"]))))
    } else {
        Ok(value)
    }
}

lazy_static! {
    pub static ref TERA: Tera = {
        let mut tera = compile_templates!("templates/**/*.html");
        tera.autoescape_on(vec![]);
        tera.register_filter("egg", egg_filter);
        tera
    };
    pub static ref CONFIG: Config = {
        let mut file = match std::fs::File::open("Foosball.toml") {
            Ok(f) => f,
            Err(e) => {
                let code = e.raw_os_error().unwrap_or(1);
                drop(e);
                println!("Couldn't open 'Foosball.toml'. Perhaps you didn't create one.\n\
                          Look at 'Foosball.toml.sample' for an example.");
                std::process::exit(code);
            }
        };

        let mut buf = String::new();
        file.read_to_string(&mut buf).unwrap();

        toml::decode_str(&buf).unwrap()
    };
    pub static ref RATER: Rater = Rater::new(BETA / 6.0);
    pub static ref PLAYERS: Mutex<HashMap<i32, Player>> = Mutex::new(gen_players());
    pub static ref LAST_DATE: Mutex<String> = Mutex::new(INITIAL_DATE_CAP.to_owned());
    // Has to be a `Mutex` because `Connection` isn't `Sync`
    pub static ref DB_CONNECTION: Mutex<Connection> = Mutex::new({
        let exists = match File::open(&CONFIG.database) {
            Ok(_) => true,
            Err(_) => false,
        };
        let conn = Connection::open(&CONFIG.database).unwrap();
        if !exists {
            println!("Database didn't exist... creating one");
            conn.execute_batch(include_str!("ratings.schema")).unwrap();
        }
        conn
    });
}

fn gen_players() -> HashMap<i32, Player> {
    let conn = DB_CONNECTION.lock().unwrap();
    let mut stmt = conn.prepare("SELECT id, name from players").unwrap();
    let mut players = HashMap::new();
    for p in stmt.query_map(&[], |row| (row.get::<_, i32>(0), row.get::<_, String>(1))).unwrap() {
        let (id, name) = p.unwrap();
        players.insert(id, Player::new(name));
    }
    players
}

fn reset_ratings() {
    *PLAYERS.lock().unwrap() = gen_players();
    *LAST_DATE.lock().unwrap() = INITIAL_DATE_CAP.to_owned();
}

fn get_games<'a>() -> Vec<Game> {
    let conn = DB_CONNECTION.lock().unwrap();
    let mut last_date = LAST_DATE.lock().unwrap();
    let mut stmt =
        conn.prepare(&format!("SELECT home_id, away_id, home_score, away_score, dato from games WHERE dato > datetime('{}')", *last_date))
            .unwrap();

    let gs = stmt.query_map(&[], |row| {
            let home_score = row.get::<_, i32>(2);
            let away_score = row.get::<_, i32>(3);
            // FIXME
            *last_date = row.get(4);
            Game {
                home: row.get(0),
                away: row.get(1),
                ace: home_score == 0 || away_score == 0,
                home_win: home_score > away_score,
            }
        })
        .unwrap()
        .map(Result::unwrap);
    gs.collect()
}

#[derive(Debug, Serialize)]
struct PlayedGame {
    home: String,
    away: String,
    home_score: i32,
    away_score: i32,
    ball: String,
    ball_name: String,
    dato: String,
}

#[derive(Debug, Serialize)]
struct Named {
    id: i32,
    name: String
}

#[derive(Debug, Serialize)]
struct Ball {
    id: i32,
    name: String,
    img: String,
}

pub fn create_context(current_page: &str) -> Context {
    let mut c = Context::new();
    c.add("version", &VERSION);
    c.add("league", &CONFIG.title);
    c.add("cur", &current_page);
    c
}

#[derive(Debug, Clone)]
pub struct SerRating(Rating);

impl SerRating {
    fn get_rating(&self) -> f64 {
        self.0.mu() - 3. * self.0.sigma()
    }
}

impl serde::Serialize for SerRating {
    fn serialize<S: serde::Serializer>(&self, serializer: &mut S) -> Result<(), S::Error> {
        let mut state = serializer.serialize_struct("Rating", 2)?;
        serializer.serialize_struct_elt(&mut state, "mu", format!("{:.1}", self.0.mu()))?;
        serializer.serialize_struct_elt(&mut state, "sigma", format!("{:.1}", self.0.sigma()))?;
        serializer.serialize_struct_end(state)
    }
}

#[derive(Debug, Clone, Serialize)]
pub struct Player {
    pub name: String,
    pub rating: SerRating,
    pub kampe: u32,
    pub vundne: u32,
    pub tabte: u32,
    pub eggs: u32,
    pub aces: u32,
}

use std::mem::replace;
use bbt::Outcome::{Win, Loss};

impl Player {
    fn new<S: ToString>(name: S) -> Self {
        Player {
            name: name.to_string(),
            rating: SerRating(Rating::new(BETA, BETA / 3.0)),
            kampe: 0,
            vundne: 0,
            tabte: 0,
            eggs: 0,
            aces: 0,

        }
    }
    fn duel(&mut self, rater: &Rater, o: Rating, won: bool) {
        let a = replace(&mut self.rating.0, Default::default());

        let (a, _) = rater.duel(a, o, if won { Win } else { Loss });
        self.rating.0 = a;

        self.kampe += 1;
        if won {
            self.vundne += 1;
        } else {
            self.tabte += 1;
        }
    }
}

struct Game {
    home: i32,
    away: i32,
    ace: bool,
    home_win: bool,
}

fn main() {
    use errors::*;
    &*CONFIG;
    rocket::ignite()
        .mount("/",
               routes![analysis::analysis,
                       ratings::root,
                       statics::favicon_handler,
                       games::games,
                       games::newgame,
                       games::submit_newgame,
                       balls::balls,
                       balls::ball,
                       players::players,
                       players::player,
                       players::newplayer,
                       players::submit_newplayer,
                       ratings::reset,
                       ratings::rating,
                       statics::static_handler])
        .catch(errors![page_not_found, bad_request, server_error])
        .launch();
}
<commit_msg>Clone base context<commit_after>#![feature(plugin, custom_derive, conservative_impl_trait)]
#![plugin(rocket_codegen)]

extern crate rocket;
extern crate bbt;
extern crate rustc_serialize;
extern crate rand;
extern crate rusqlite;
extern crate toml;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate tera;
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_json;

use std::fs::File;
use std::path::{Path, PathBuf};
use std::io::Read;
use std::cmp::Ordering::{Greater, Less};
use std::collections::HashMap;
use std::sync::Mutex;
use rocket::request::{FormItems, FromFormValue, FromForm, Form};
use rocket::response::{NamedFile, Response, Redirect};
use rocket::http::Status;
use rocket::Data;
use rusqlite::Connection;
use tera::{Tera, Context, Value};
use bbt::{Rater, Rating};

mod balls;
mod errors;
mod games;
mod players;
mod statics;
mod ratings;
mod analysis;

const BETA: f64 = 5000.0;
const VERSION: &'static str = env!("CARGO_PKG_VERSION");
const INITIAL_DATE_CAP: &'static str = "now','-90 day";

pub type Res<'a> = Result<Response<'a>, Status>;

#[derive(Debug, RustcDecodable)]
pub struct Config {
    database: String,
    title: String,
    secret: String,
}

fn egg_filter(value: Value, args: HashMap<String, Value>) -> tera::Result<Value> {
    let goals = try_get_value!("egg", "value", i32, value);
    if goals == 0 {
        Ok(Value::String(format!(r#""#, try_get_value!("egg", "person", String, args["person"]))))
    } else {
        Ok(value)
    }
}

lazy_static! {
    pub static ref TERA: Tera = {
        let mut tera = compile_templates!("templates/**/*.html");
        tera.autoescape_on(vec![]);
        tera.register_filter("egg", egg_filter);
        tera
    };
    pub static ref CONFIG: Config = {
        let mut file = match std::fs::File::open("Foosball.toml") {
            Ok(f) => f,
            Err(e) => {
                let code = e.raw_os_error().unwrap_or(1);
                drop(e);
                println!("Couldn't open 'Foosball.toml'. Perhaps you didn't create one.\n\
                          Look at 'Foosball.toml.sample' for an example.");
                std::process::exit(code);
            }
        };

        let mut buf = String::new();
        file.read_to_string(&mut buf).unwrap();

        toml::decode_str(&buf).unwrap()
    };
    pub static ref RATER: Rater = Rater::new(BETA / 6.0);
    pub static ref PLAYERS: Mutex<HashMap<i32, Player>> = Mutex::new(gen_players());
    pub static ref LAST_DATE: Mutex<String> = Mutex::new(INITIAL_DATE_CAP.to_owned());
    // Has to be a `Mutex` because `Connection` isn't `Sync`
    pub static ref DB_CONNECTION: Mutex<Connection> = Mutex::new({
        let exists = match File::open(&CONFIG.database) {
            Ok(_) => true,
            Err(_) => false,
        };
        let conn = Connection::open(&CONFIG.database).unwrap();
        if !exists {
            println!("Database didn't exist... creating one");
            conn.execute_batch(include_str!("ratings.schema")).unwrap();
        }
        conn
    });
    static ref BASE_CONTEXT: Context = {
        let mut c = Context::new();
        c.add("version", &VERSION);
        c.add("league", &CONFIG.title);
        c
    };
}

fn gen_players() -> HashMap<i32, Player> {
    let conn = DB_CONNECTION.lock().unwrap();
    let mut stmt = conn.prepare("SELECT id, name from players").unwrap();
    let mut players = HashMap::new();
    for p in stmt.query_map(&[], |row| (row.get::<_, i32>(0), row.get::<_, String>(1))).unwrap() {
        let (id, name) = p.unwrap();
        players.insert(id, Player::new(name));
    }
    players
}

fn reset_ratings() {
    *PLAYERS.lock().unwrap() = gen_players();
    *LAST_DATE.lock().unwrap() = INITIAL_DATE_CAP.to_owned();
}

fn get_games<'a>() -> Vec<Game> {
    let conn = DB_CONNECTION.lock().unwrap();
    let mut last_date = LAST_DATE.lock().unwrap();
    let mut stmt =
        conn.prepare(&format!("SELECT home_id, away_id, home_score, away_score, dato from games WHERE dato > datetime('{}')", *last_date))
            .unwrap();

    let gs = stmt.query_map(&[], |row| {
            let home_score = row.get::<_, i32>(2);
            let away_score = row.get::<_, i32>(3);
            // FIXME
            *last_date = row.get(4);
            Game {
                home: row.get(0),
                away: row.get(1),
                ace: home_score == 0 || away_score == 0,
                home_win: home_score > away_score,
            }
        })
        .unwrap()
        .map(Result::unwrap);
    gs.collect()
}

#[derive(Debug, Serialize)]
struct PlayedGame {
    home: String,
    away: String,
    home_score: i32,
    away_score: i32,
    ball: String,
    ball_name: String,
    dato: String,
}

#[derive(Debug, Serialize)]
struct Named {
    id: i32,
    name: String
}

#[derive(Debug, Serialize)]
struct Ball {
    id: i32,
    name: String,
    img: String,
}

pub fn create_context(current_page: &str) -> Context {
    let mut c = BASE_CONTEXT.clone();
    c.add("cur", &current_page);
    c
}

#[derive(Debug, Clone)]
pub struct SerRating(Rating);

impl SerRating {
    fn get_rating(&self) -> f64 {
        self.0.mu() - 3. * self.0.sigma()
    }
}

impl serde::Serialize for SerRating {
    fn serialize<S: serde::Serializer>(&self, serializer: &mut S) -> Result<(), S::Error> {
        let mut state = serializer.serialize_struct("Rating", 2)?;
        serializer.serialize_struct_elt(&mut state, "mu", format!("{:.1}", self.0.mu()))?;
        serializer.serialize_struct_elt(&mut state, "sigma", format!("{:.1}", self.0.sigma()))?;
        serializer.serialize_struct_end(state)
    }
}

#[derive(Debug, Clone, Serialize)]
pub struct Player {
    pub name: String,
    pub rating: SerRating,
    pub kampe: u32,
    pub vundne: u32,
    pub tabte: u32,
    pub eggs: u32,
    pub aces: u32,
}

use std::mem::replace;
use bbt::Outcome::{Win, Loss};

impl Player {
    fn new<S: ToString>(name: S) -> Self {
        Player {
            name: name.to_string(),
            rating: SerRating(Rating::new(BETA, BETA / 3.0)),
            kampe: 0,
            vundne: 0,
            tabte: 0,
            eggs: 0,
            aces: 0,

        }
    }
    fn duel(&mut self, rater: &Rater, o: Rating, won: bool) {
        let a = replace(&mut self.rating.0, Default::default());

        let (a, _) = rater.duel(a, o, if won { Win } else { Loss });
        self.rating.0 = a;

        self.kampe += 1;
        if won {
            self.vundne += 1;
        } else {
            self.tabte += 1;
        }
    }
}

struct Game {
    home: i32,
    away: i32,
    ace: bool,
    home_win: bool,
}

fn main() {
    use errors::*;
    &*CONFIG;
    rocket::ignite()
        .mount("/",
               routes![analysis::analysis,
                       ratings::root,
                       statics::favicon_handler,
                       games::games,
                       games::newgame,
                       games::submit_newgame,
                       balls::balls,
                       balls::ball,
                       players::players,
                       players::player,
                       players::newplayer,
                       players::submit_newplayer,
                       ratings::reset,
                       ratings::rating,
                       statics::static_handler])
        .catch(errors![page_not_found, bad_request, server_error])
        .launch();
}
<|endoftext|>


<commit_before>// TODO: Why do I need these two lines "extern crate html5ever" and "extern crate
// html5ever_dom_sink" both here and in main.rs?
extern crate html5ever;
extern crate html5ever_dom_sink;
extern crate rand;
extern crate tendril;

use std::str::FromStr;
use std::sync::mpsc::{channel, Receiver, Sender};
use std::thread;

use html5ever::Attribute;
use html5ever::tree_builder::interface::TreeSink;
use html5ever_dom_sink::common::NodeEnum;
use html5ever_dom_sink::rcdom::Handle;
use html5ever_dom_sink::rcdom::RcDom;
use regex::Captures;

use wiki::Wiki;

// TODO: massive cleanup, all over this file.

// TODO: doc comments everywhere!
pub struct Page {
    html_body_sender: Sender<String>,
    replaced_body_receiver: Receiver<Result<String, String>>,
}

impl Page {
    pub fn new(title: &str, wiki: Wiki) -> Page {
        let current_content_receiver = Page::spawn_content_fetch_thread(title, wiki);
        let placeholder = format!("WMW_PLACEHOLDER_{}", rand::random::<u64>());
        let (html_body_sender, replaced_body_receiver) =
            Page::spawn_replace_body_thread(current_content_receiver, placeholder);
        Page {
            html_body_sender: html_body_sender,
            replaced_body_receiver: replaced_body_receiver,
        }
    }

    pub fn replace_body_and_remove_merge_markers(&self, html_body: String)
                                                 -> Result<String, String> {
        self.html_body_sender.send(html_body);
        try_display!(self.replaced_body_receiver.recv(), "Failed to get data from channel")
    }

    fn spawn_content_fetch_thread(title: &str, wiki: Wiki) -> Receiver<Result<String, String>> {
        let (sender, receiver) = channel();
        let title = title.to_owned().clone();
        thread::spawn(move|| sender.send(wiki.get_current_page_content(&title)));
        receiver
    }

    // TODO: doc comment
    fn spawn_replace_body_thread(
        current_content_receiver: Receiver<Result<String, String>>, placeholder: String)
        -> (Sender<String>, Receiver<Result<String, String>>) {
        let (html_body_sender, html_body_receiver) = channel::<String>();
        let (replaced_body_sender, replaced_body_receiver) = channel::<Result<String, String>>();
        thread::spawn(move|| {
            match (current_content_receiver.recv(), html_body_receiver.recv()) {
                (Ok(Ok(content)), Ok(body)) => {
                    // TODO: doing the replace_node_with_placeholder here means it has to wait for the body to be prepared. Fix that.
                    // TODO: get rid of the unwrap()
                    let placeholder_html =
                        replace_node_with_placeholder(&content, "mw-content-text", &placeholder)
                        .unwrap();
                    let replaced_body_html = placeholder_html.replace(&placeholder, &body);
                    let replaced_body_html = remove_merge_markers_from_html(replaced_body_html);
                    // TODO: Move this elsewhere, use constants, etc.
                    let start_regex = regex!("\u{E000}([0-9]+)\u{E000}");
                    let end_regex = regex!("\u{E001}[0-9]+\u{E001}");
                    let finished_html =
                        start_regex.replace_all(
                            &end_regex.replace_all(&replaced_body_html, ""),
                            |captures: &Captures|
                            format!("",
                                    captures.at(1).unwrap()));
                    replaced_body_sender.send(Ok(finished_html))
                },
                (Ok(Err(msg)), _) => replaced_body_sender.send(Err(msg)),
                (Err(err), _) => replaced_body_sender.send(Err(format!("error: {}", err))),
                (_, Err(err)) => replaced_body_sender.send(Err(format!("error: {}", err))),
            }.unwrap()
        });
        (html_body_sender, replaced_body_receiver)
    }
}

fn replace_node_with_placeholder(original_html: &str, div_id: &str, placeholder: &str)
    -> Result<String, String> {
    let html = tendril::StrTendril::from_str(original_html).unwrap();
    let mut dom: RcDom = html5ever::parse(html5ever::one_input(html), Default::default());

    let handle = try!(find_node_by_id(&dom.get_document(), div_id));
    let child_handles =
        (&handle.borrow().children).into_iter().map(|child| child.clone()).collect::<Vec<_>>();
    for child_handle in child_handles {
        dom.remove_from_parent(child_handle);
    }
    dom.append(handle,
               html5ever::tree_builder::interface::NodeOrText::AppendText(
                   tendril::StrTendril::from_str(placeholder).unwrap()));
    let mut serialized: Vec<u8> = vec![];
    try_display!(
        html5ever::serialize::serialize(&mut serialized, &dom.document, Default::default()),
        "Failed to serialize modified HTML");
    Ok(try_display!(String::from_utf8(serialized),
                    "Error converting serialized HTML to UTF-8 string"))
}

fn find_node_by_id(handle: &Handle, id: &str) -> Result<Handle, String> {
    fn has_matching_id(attributes: &Vec<Attribute>, id: &str) -> bool {
        return attributes.into_iter().any(
            |attribute| attribute.name.local.as_slice() == "id" &&
                format!("{}", attribute.value) == id);
    }

    let node = handle.borrow();
    match node.node {
        NodeEnum::Element(_, ref attributes) if has_matching_id(attributes, id) => Ok(handle.clone()),
        _ => (&node.children).into_iter()
            .map(|child| find_node_by_id(child, id))
            .filter(|result| result.is_ok())
            .map(|result| result.unwrap())
            .next().ok_or(format!("No node with ID {} found", id)),
    }
}

#[cfg(test)]
mod tests {
    use super::{remove_merge_markers_from_html, replace_node_with_placeholder};

    #[test]
    fn test_remove_merge_markers_from_html() {
        let html = format!("{}123{}",
                           ::START_MARKER, ::START_MARKER, ::END_MARKER, ::END_MARKER);
        let expected = "";
        assert_eq!(expected, remove_merge_markers_from_html(html));
    }

    #[test]
    fn test_remove_merge_markers_from_html_keep() {
        let html = format!("{}456{}{}456{}",
                           ::START_MARKER, ::START_MARKER, ::END_MARKER, ::END_MARKER);
        assert_eq!(html.clone(), remove_merge_markers_from_html(html));
    }

    #[test]
    fn test_remove_merge_markers_from_html_keep_one_remove_one() {
        let html = format!(
            "{}234{}text{}234{}{}567{}",
            ::START_MARKER, ::START_MARKER, ::END_MARKER, ::END_MARKER, ::START_MARKER, ::START_MARKER,
            ::END_MARKER, ::END_MARKER);
        let expected = format!(
            "{}234{}text{}234{}",
            ::START_MARKER, ::START_MARKER, ::END_MARKER, ::END_MARKER);
        assert_eq!(expected, remove_merge_markers_from_html(html));
    }

    #[test]
    fn test_replace_html_content() {
        let original_html = "

original text

Other text

";
        let expected_html = "

replaced text

Other text

";
        let processed_html = replace_node_with_placeholder(original_html, "mw-content-text", "replaced text").unwrap();
        assert_eq!(expected_html, processed_html);
    }
}

fn remove_merge_markers_from_html(html: String) -> String {
    // TODO: clean up this whole function. regex[1..4] are not good names.
    // TODO: use START_MARKER and END_MARKER constants here.
    // Finds markers where the end, but not the start, is inside a tag.
    let regex1 = regex!(
        r"\x{E000}[0-9]+\x{E000}([^\x{E001}]*?)<([^>]*?)\x{E001}[0-9]+\x{E001}([^>]*?)>");
    // Finds markers where the start, but not the end, is inside a tag.
    let regex2 = regex!(
        r"<([^>]*?)\x{E000}[0-9]+\x{E000}([^>]*?)>([^\x{E000}]*?)\x{E000}[0-9]+\x{E000}");
    // Finds markers where both the start and end are inside tags.
    let regex3 = regex!(
        r"<([^>]*?)\x{E000}[0-9]+\x{E000}([^>]*?)>([^\x{E000}\x{E001}]*?)<([^>]*?)\x{E001}[0-9]+\x{E001}([^>]*?)>");

    let html1 = regex1.replace_all(
        &html, |captures: &Captures|
        format!("{}<{}{}>", captures.at(1).unwrap(), captures.at(2).unwrap(),
                captures.at(3).unwrap()));
    let html2 = regex2.replace_all(
        &html1, |captures: &Captures|
        format!("<{}{}>{}>", captures.at(1).unwrap(), captures.at(2).unwrap(),
                captures.at(3).unwrap()));
    regex3.replace_all(
        &html2, |captures: &Captures|
        format!("<{}{}>{}<{}{}>", captures.at(1).unwrap(), captures.at(2).unwrap(),
                captures.at(3).unwrap(), captures.at(4).unwrap(), captures.at(5).unwrap()))
}
<commit_msg>Replace the HTML body with the placeholder in the content fetch thread (which is almost never in the critical path for page load), rather than on the body-replacement thread (which is always on the critical path for page load).<commit_after>// TODO: Why do I need these two lines "extern crate html5ever" and "extern crate
// html5ever_dom_sink" both here and in main.rs?
extern crate html5ever;
extern crate html5ever_dom_sink;
extern crate rand;
extern crate tendril;

use std::str::FromStr;
use std::sync::mpsc::{channel, Receiver, Sender};
use std::thread;

use html5ever::Attribute;
use html5ever::tree_builder::interface::TreeSink;
use html5ever_dom_sink::common::NodeEnum;
use html5ever_dom_sink::rcdom::Handle;
use html5ever_dom_sink::rcdom::RcDom;
use regex::Captures;

use wiki::Wiki;

// TODO: massive cleanup, all over this file.

// TODO: doc comments everywhere!
pub struct Page {
    html_body_sender: Sender<String>,
    replaced_body_receiver: Receiver<Result<String, String>>,
}

impl Page {
    pub fn new(title: &str, wiki: Wiki) -> Page {
        let placeholder = format!("WMW_PLACEHOLDER_{}", rand::random::<u64>());
        let current_content_receiver =
            Page::spawn_content_fetch_thread(title, placeholder.clone(), wiki);
        let (html_body_sender, replaced_body_receiver) =
            Page::spawn_replace_body_thread(current_content_receiver, placeholder);
        Page {
            html_body_sender: html_body_sender,
            replaced_body_receiver: replaced_body_receiver,
        }
    }

    pub fn replace_body_and_remove_merge_markers(&self, html_body: String)
                                                 -> Result<String, String> {
        self.html_body_sender.send(html_body);
        try_display!(self.replaced_body_receiver.recv(), "Failed to get data from channel")
    }

    fn spawn_content_fetch_thread(title: &str, placeholder: String, wiki: Wiki)
                                  -> Receiver<Result<String, String>> {
        let (sender, receiver) = channel::<Result<String, String>>();
        let title = title.to_owned().clone();
        thread::spawn(move|| {
            sender.send(
                match wiki.get_current_page_content(&title) {
                    Ok(content) =>
                        replace_node_with_placeholder(&content, "mw-content-text", &placeholder),
                Err(msg) => Err(msg),
            }).unwrap();
        });
        receiver
    }

    // TODO: doc comment
    fn spawn_replace_body_thread(
        page_skeleton_receiver: Receiver<Result<String, String>>, placeholder: String)
        -> (Sender<String>, Receiver<Result<String, String>>) {
        let (html_body_sender, html_body_receiver) = channel::<String>();
        let (replaced_body_sender, replaced_body_receiver) = channel::<Result<String, String>>();
        thread::spawn(move|| {
            match (page_skeleton_receiver.recv(), html_body_receiver.recv()) {
                (Ok(Ok(page_skeleton)), Ok(body)) => {
                    let html_with_merge_markers =
                        remove_merge_markers_from_html(page_skeleton.replace(&placeholder, &body));
                    // TODO: Move this elsewhere, use constants, etc.
                    let start_regex = regex!("\u{E000}([0-9]+)\u{E000}");
                    let end_regex = regex!("\u{E001}[0-9]+\u{E001}");
                    let finished_html =
                        start_regex.replace_all(
                            &end_regex.replace_all(&html_with_merge_markers, ""),
                            |captures: &Captures|
                            format!("",
                                    captures.at(1).unwrap()));
                    replaced_body_sender.send(Ok(finished_html))
                },
                (Ok(Err(msg)), _) => replaced_body_sender.send(Err(msg)),
                (Err(err), _) => replaced_body_sender.send(Err(format!("error: {}", err))),
                (_, Err(err)) => replaced_body_sender.send(Err(format!("error: {}", err))),
            }.unwrap()
        });
        (html_body_sender, replaced_body_receiver)
    }
}

fn replace_node_with_placeholder(original_html: &str, div_id: &str, placeholder: &str)
    -> Result<String, String> {
    let html = tendril::StrTendril::from_str(original_html).unwrap();
    let mut dom: RcDom = html5ever::parse(html5ever::one_input(html), Default::default());

    let handle = try!(find_node_by_id(&dom.get_document(), div_id));
    let child_handles =
        (&handle.borrow().children).into_iter().map(|child| child.clone()).collect::<Vec<_>>();
    for child_handle in child_handles {
        dom.remove_from_parent(child_handle);
    }
    dom.append(handle,
               html5ever::tree_builder::interface::NodeOrText::AppendText(
                   tendril::StrTendril::from_str(placeholder).unwrap()));
    let mut serialized: Vec<u8> = vec![];
    try_display!(
        html5ever::serialize::serialize(&mut serialized, &dom.document, Default::default()),
        "Failed to serialize modified HTML");
    Ok(try_display!(String::from_utf8(serialized),
                    "Error converting serialized HTML to UTF-8 string"))
}

fn find_node_by_id(handle: &Handle, id: &str) -> Result<Handle, String> {
    fn has_matching_id(attributes: &Vec<Attribute>, id: &str) -> bool {
        return attributes.into_iter().any(
            |attribute| attribute.name.local.as_slice() == "id" &&
                format!("{}", attribute.value) == id);
    }

    let node = handle.borrow();
    match node.node {
        NodeEnum::Element(_, ref attributes) if has_matching_id(attributes, id) => Ok(handle.clone()),
        _ => (&node.children).into_iter()
            .map(|child| find_node_by_id(child, id))
            .filter(|result| result.is_ok())
            .map(|result| result.unwrap())
            .next().ok_or(format!("No node with ID {} found", id)),
    }
}

#[cfg(test)]
mod tests {
    use super::{remove_merge_markers_from_html, replace_node_with_placeholder};

    #[test]
    fn test_remove_merge_markers_from_html() {
        let html = format!("{}123{}",
                           ::START_MARKER, ::START_MARKER, ::END_MARKER, ::END_MARKER);
        let expected = "";
        assert_eq!(expected, remove_merge_markers_from_html(html));
    }

    #[test]
    fn test_remove_merge_markers_from_html_keep() {
        let html = format!("{}456{}{}456{}",
                           ::START_MARKER, ::START_MARKER, ::END_MARKER, ::END_MARKER);
        assert_eq!(html.clone(), remove_merge_markers_from_html(html));
    }

    #[test]
    fn test_remove_merge_markers_from_html_keep_one_remove_one() {
        let html = format!(
            "{}234{}text{}234{}{}567{}",
            ::START_MARKER, ::START_MARKER, ::END_MARKER, ::END_MARKER, ::START_MARKER, ::START_MARKER,
            ::END_MARKER, ::END_MARKER);
        let expected = format!(
            "{}234{}text{}234{}",
            ::START_MARKER, ::START_MARKER, ::END_MARKER, ::END_MARKER);
        assert_eq!(expected, remove_merge_markers_from_html(html));
    }

    #[test]
    fn test_replace_html_content() {
        let original_html = "

original text

Other text

";
        let expected_html = "

replaced text

Other text

";
        let processed_html = replace_node_with_placeholder(original_html, "mw-content-text", "replaced text").unwrap();
        assert_eq!(expected_html, processed_html);
    }
}

fn remove_merge_markers_from_html(html: String) -> String {
    // TODO: clean up this whole function. regex[1..4] are not good names.
    // TODO: use START_MARKER and END_MARKER constants here.
    // Finds markers where the end, but not the start, is inside a tag.
    let regex1 = regex!(
        r"\x{E000}[0-9]+\x{E000}([^\x{E001}]*?)<([^>]*?)\x{E001}[0-9]+\x{E001}([^>]*?)>");
    // Finds markers where the start, but not the end, is inside a tag.
    let regex2 = regex!(
        r"<([^>]*?)\x{E000}[0-9]+\x{E000}([^>]*?)>([^\x{E000}]*?)\x{E000}[0-9]+\x{E000}");
    // Finds markers where both the start and end are inside tags.
    let regex3 = regex!(
        r"<([^>]*?)\x{E000}[0-9]+\x{E000}([^>]*?)>([^\x{E000}\x{E001}]*?)<([^>]*?)\x{E001}[0-9]+\x{E001}([^>]*?)>");

    let html1 = regex1.replace_all(
        &html, |captures: &Captures|
        format!("{}<{}{}>", captures.at(1).unwrap(), captures.at(2).unwrap(),
                captures.at(3).unwrap()));
    let html2 = regex2.replace_all(
        &html1, |captures: &Captures|
        format!("<{}{}>{}>", captures.at(1).unwrap(), captures.at(2).unwrap(),
                captures.at(3).unwrap()));
    regex3.replace_all(
        &html2, |captures: &Captures|
        format!("<{}{}>{}<{}{}>", captures.at(1).unwrap(), captures.at(2).unwrap(),
                captures.at(3).unwrap(), captures.at(4).unwrap(), captures.at(5).unwrap()))
}
<|endoftext|>


<commit_before>extern crate rand;

/// The `pick` macro allows to randomly select one expression from a sequence of
/// expressions according to associated weights.
#[macro_export]
macro_rules! pick {
    ($( $weight: expr, $expression: expr),+) => {{
        let total = 0 $(+ $weight)+;
        let mut bound = 0;

        let mut rng = rand::thread_rng();
        let random_number = rng.gen_range(0, total);
        let result = $( if bound <= random_number && random_number < { bound += $weight; bound } {
            $expression
        } else )+ {
           panic!();
        };
        result
    }}
}

<commit_msg>Introduce module documentation for pick<commit_after>//! pick an expression according to weights

extern crate rand;

/// The `pick` macro allows to randomly select one expression from a sequence of
/// expressions according to associated weights.
#[macro_export]
macro_rules! pick {
    ($( $weight: expr, $expression: expr),+) => {{
        let total = 0 $(+ $weight)+;
        let mut bound = 0;

        let mut rng = rand::thread_rng();
        let random_number = rng.gen_range(0, total);
        let result = $( if bound <= random_number && random_number < { bound += $weight; bound } {
            $expression
        } else )+ {
           panic!();
        };
        result
    }}
}

<|endoftext|>


<commit_before>use std::io;
use std::io::prelude::*;
use std::char;
use super::{alloc, value};

pub enum ReadError {
    EOFInList,
    EOFInVector,
    MissingCloseParen,
    IoError(io::Error),
    EOFInString,
    EOFInSymbol,
    EOFAfterSharpBackslash,

    /// Bad sharpsign read macro
    BadSharpMacro([char; 2]),

    /// Unexpected close parentheses
    UnexpectedCloseParen,

    /// Wrong close parentheses
    BadCloseParen,

    /// Bad backslash escape
    BadEscape,

    /// EOF after sharpsign
    EOFAfterSharp,

    /// Stream not valid UTF-8.  The argument is
    /// the partial sequence accumulated.
    InvalidUtf8(u32),
}

/// An event that can be emitted by the reader or tree-walker, and which
/// is part of the stream that is consumed by the tree-builder, printer,
/// and bytecode compiler.
pub enum Event {
    /// A string
    Str(String),

    /// A symbol
    Symbol(String),

    /// Boolean true `#t`
    True,

    /// Boolean false `#f`
    False,

    /// Character `#\\x`
    Char(char),

    /// Integer `12311324`
    Int(usize),

    /// Floating-point numbers (not yet implemented)
    Float(f64),

    /// Start of a list `(` (false) or `[` (true)
    StartList(bool),

    /// Start of a vector `#(`
    StartVec,

    /// End of token `)` (false) or `]` (true)
    EndList(bool),

    /// Read-time eval `#.`
    ReadEval,

    /// Quote `'`
    Quote,

    /// Quasiquote `\``
    Quasiquote,

    /// Unquote `,`
    Unquote,

    /// Unquote splicing `,@`
    UnquoteSplicing,

    /// Syntax `#'`
    Syntax,

    /// Quasisyntax `#\``
    Quasisyntax,

    /// Unsyntax `#,`
    Unsyntax,

    /// Unsyntax splicing #,@
    UnsyntaxSplicing,

    /// End of file
    EOF,
}

#[derive(PartialEq, Eq, Copy, Clone, Debug)]
enum StringOrSymbol {
    String,
    Symbol,
}

fn char_from_stream_and_byte<R: BufRead>(file: &mut Bytes<R>, unicode_char: u8)
                                         -> Result<char, ReadError> {
    if unicode_char <= 0x7F {
        return Ok(unicode_char as char);
    }
    let len = (!unicode_char).leading_zeros() as u8;
    match len {
        1 | 5...8 => Err(ReadError::InvalidUtf8((unicode_char as u32) << 24)),
        len @ 2...4 => {
            let len = len - 1;
            let mut value: u32 = (unicode_char >> (len + 2)).into();
            value <<= len * 6;
            for (count, current_byte_value) in file.take(len.into()).enumerate()  {
                let current: u32 = try!(current_byte_value.map_err(
                    ReadError::IoError)).into();
                value &= current << (len - count as u8)
            }
            char::from_u32(value).ok_or(ReadError::InvalidUtf8(value))
        }
        _ => unreachable!(),
    }
}
macro_rules! next {
    ($exp: expr, $err: expr) => {
        try!(try!($exp.next().ok_or($err)).map_err(|x|ReadError::IoError(x)))
    }
}

type ReadResult = Result<char, ReadError>;

use std::io::Bytes;
fn handle_unicode_escape<R: BufRead>(file: &mut Bytes<R>) -> ReadResult {
    loop {
        let eof = ReadError::BadEscape;
        let mut escaped_char = 0;
        let next_character = next!(file, eof);
        let subtract_amount = match next_character {
            b'a'...b'f' => 87,
            b'A'...b'F' => 55,
            b'0'...b'9' => 48,
            b';' => return char::from_u32(escaped_char).ok_or(ReadError::BadEscape),
            _ => return Err(ReadError::BadEscape),
        };
        escaped_char <<= 4;
        // No overflow is possible here – later check would
        // detect it.
        escaped_char += next_character as u32 - subtract_amount;
        if escaped_char > 0x10FFFF {
            // protect against overflow
            return Err(ReadError::BadEscape);
        }
    }
}

fn process_escape<R: BufRead>(file: &mut Bytes<R>) -> ReadResult {
    let bad = ReadError::BadEscape;
    loop {
        return Ok(match next!(file, bad) {
            b'n' => '\n',
            b't' => '\t',
            b'e' => '\x1b',
            b'b' => '\x08',
            b'v' => '\x0b',
            b'f' => '\x0c',
            b'\r' => {
                match file.next() {
                    Some(Ok(b'\n')) => continue,
                    Some(Ok(_)) | None => return Err(bad),
                    Some(Err(x)) => return Err(ReadError::IoError(x)),
                }
            }
            b'\n' => continue,
            b'x' | b'u' => try!(handle_unicode_escape(file)),
            l @ b'|' | l @ b'"' | l @ b'\\' | l @ b'#' | l @ b'`' | l @ b',' | l @ b'\'' => {
                l as char
            }
            _ => return Err(bad),
        });
    }
}

pub fn read_escaped<R: BufRead>(file: &mut Bytes<R>, delimiter: StringOrSymbol)
                             -> Result<String, ReadError> {
    use std::char;
    let premature_eof = || {
        match delimiter {
            StringOrSymbol::String => ReadError::EOFInString,
            StringOrSymbol::Symbol => ReadError::EOFInSymbol,
        }
    };

    let buf = String::new();
    loop {
        buf.push(match next!(file, premature_eof()) {
            b'\\' => try!(process_escape(file)),
            b'|' if delimiter == StringOrSymbol::Symbol => break,
            b'"' if delimiter == StringOrSymbol::String => break,
            normal_char if normal_char <= 0x7F => normal_char as char,
            unicode_char => try!(char_from_stream_and_byte(file, unicode_char)),
        })
    }
    Ok(buf)
}
// if delimiter == UndelimitedSymbol && c.is_whitespace() {
// break
// } else {
// c
// }
// }
// let bad = ReadError::BadEscape;
// loop {
// return Ok(match next!(file, bad) {
// b'n' => '\n',
// b't' => '\t',
// b'e' => '\x1b',
// b'b' => '\x08',
// b'v' => '\x0b',
// b'\r' => match next!(file, bad) {
// Some(b'\n') => continue,
// _ => return Err(bad),
// },
// b'\n' => continue,
// b'x' | b'u' => try!(handle_unicode_escape(file)),
// literal@b'|'|b'"'|b'\\'|b'#'|b'`'|b','|b'\'' => literal.into(),
// _ => return Err(bad),
// })
// }
//
pub struct Reader<'a, 'b, T: 'a + BufRead> {
    stream: &'a mut T,
    state: &'b mut interp::State,
}

//    let chars = file.chars().peekable();
// let mut depth = 1;
// let ref mut heap = state.heap;
// let run_macros_self_evaluating = |mut value| while let Some(x) = vec.pop()
// {
// match x {
// State::InList(ref x)|State::InVec(ref x) => {
// x += 1
// }
// State::ReadEval => unimplemented!(),
//
// State::Quote | State::Unquote | State::Quasiquote |
// State::Syntax | State::Unsyntax | State::Quasisyntax => {
// state.push_nil();
// state.list(2)
// }
// }
// };
//

pub fn read<R: BufRead>(file: &mut Bytes<R>) -> Result<Event, ReadError> {
    let handle_splicing = |file: &mut Bytes<R>, nosplice, splice| match file.peek() {
        Some(Ok('@')) => { file.next(); Ok(splice) }
        Some(Ok(_)) | None => Ok(nosplice),
        Some(x) => x,
    };

    loop {
        let next: Option<Result<u8, io::Error>> = file.next();
        if let Some(c) = next {
            return Ok(match try!(c.map_err(ReadError::IoError)) {
                b'(' => Event::StartList(false),
                b'[' => Event::StartList(true),
                b'\'' => Event::Quote,
                b'`' => Event::Quasiquote,
                b',' => try!(handle_splicing(file, Event::Unquote, Event::UnquoteSplicing)),
                b'#' => match next!(file, ReadError::EOFAfterSharp) {
                    b'.' => Event::ReadEval,
                    b'\\' => {
                        let byte = next!(file, ReadError::EOFAfterSharpBackslash);
                        Event::Char(try!(char_from_stream_and_byte(file, byte)))
                    }
                    b't' => Event::True,
                    b'f' => Event::False,
                    b'\'' => Event::Syntax,
                    b'`' => Event::Quasisyntax,
                    b',' => try!(handle_splicing(file, Event::Unsyntax,
                                                 Event::UnsyntaxSplicing)),
                    b'(' => Event::StartVec,
                    dispatch_char =>
                        return Err(ReadError::BadSharpMacro([dispatch_char as char,
                                                             '\0']))
                },
                b')' => Event::EndList(false),
                b']' => Event::EndList(true),
                b'"' => Event::Str(try!(read_escaped(file, StringOrSymbol::String))),
                b'|' => Event::Symbol(try!(read_escaped(file, StringOrSymbol::Symbol))),
                b'\t'...b'\r' | b' ' => continue, // ASCII whitespace

            })
        } else {
            return Ok(Event::EOF);
        }
    }
}
<commit_msg>The event emitter of the reader compiles.<commit_after>use std::io;
use std::io::prelude::*;
use std::char;
use std::iter::Peekable;
use super::interp;

#[derive(Debug)]
pub enum ReadError {
    /// EOF in list
    EOFInList,

    /// EOF in vector
    EOFInVector,

    /// Missing `)`
    MissingCloseParen,

    /// Input/output error
    IoError(io::Error),

    /// EOF in string
    EOFInString,

    /// EOF in symbol
    EOFInSymbol,

    /// EOF after `#\\`
    EOFAfterSharpBackslash,

    /// Bad sharpsign read macro
    BadSharpMacro([char; 2]),

    /// Unexpected close parentheses
    UnexpectedCloseParen,

    /// Wrong close parentheses
    BadCloseParen,

    /// Bad backslash escape
    BadEscape,

    /// EOF after sharpsign
    EOFAfterSharp,

    /// Stream not valid UTF-8.  The argument is
    /// the partial sequence accumulated.
    InvalidUtf8(u32),

    /// `|` in symbol unescaped
    PipeInSymbol,
}

/// An event that can be emitted by the reader or tree-walker, and which
/// is part of the stream that is consumed by the tree-builder, printer,
/// and bytecode compiler.
pub enum Event {
    /// A string
    Str(String),

    /// A symbol
    Symbol(String),

    /// Boolean true `#t`
    True,

    /// Boolean false `#f`
    False,

    /// Character `#\\x`
    Char(char),

    /// Integer `12311324`
    Int(usize),

    /// Floating-point numbers (not yet implemented)
    Float(f64),

    /// Start of a list `(` (false) or `[` (true)
    StartList(bool),

    /// Start of a vector `#(`
    StartVec,

    /// End of token `)` (false) or `]` (true)
    EndList(bool),

    /// Read-time eval `#.`
    ReadEval,

    /// Quote `'`
    Quote,

    /// Quasiquote `\``
    Quasiquote,

    /// Unquote `,`
    Unquote,

    /// Unquote splicing `,@`
    UnquoteSplicing,

    /// Syntax `#'`
    Syntax,

    /// Quasisyntax `#\``
    Quasisyntax,

    /// Unsyntax `#,`
    Unsyntax,

    /// Unsyntax splicing #,@
    UnsyntaxSplicing,

    /// Dot `.`
    Dot,

    /// End of file
    EOF,
}

#[derive(PartialEq, Eq, Copy, Clone, Debug)]
enum StringOrSymbol {
    String,
    Symbol,
}

fn char_from_stream_and_byte<R: BufRead>(file: &mut Peekable<Bytes<R>>,
                                         unicode_char: u8)
                                         -> Result<char, ReadError> {
    if unicode_char <= 0x7F {
        return Ok(unicode_char as char);
    }
    let len = (!unicode_char).leading_zeros() as u8;
    match len {
        1 | 5...8 => Err(ReadError::InvalidUtf8((unicode_char as u32) << 24)),
        len @ 2...4 => {
            let len = len - 1;
            let mut value: u32 = (unicode_char >> (len + 2)).into();
            value <<= len * 6;
            for (count, current_byte_value) in file.take(len.into()).enumerate() {
                let current: u32 = try!(current_byte_value.map_err(ReadError::IoError)).into();
                value &= current << (len - count as u8)
            }
            char::from_u32(value).ok_or(ReadError::InvalidUtf8(value))
        }
        _ => unreachable!(),
    }
}
macro_rules! next {
    ($exp: expr, $err: expr) => {
        try!(try!($exp.next().ok_or($err)).map_err(|x|ReadError::IoError(x)))
    }
}

type ReadResult = Result<char, ReadError>;

use std::io::Bytes;
fn handle_unicode_escape<R: BufRead>(file: &mut Peekable<Bytes<R>>) -> ReadResult {
    loop {
        let eof = ReadError::BadEscape;
        let mut escaped_char = 0;
        let next_character = next!(file, eof);
        let subtract_amount = match next_character {
            b'a'...b'f' => 87,
            b'A'...b'F' => 55,
            b'0'...b'9' => 48,
            b';' => return char::from_u32(escaped_char).ok_or(ReadError::BadEscape),
            _ => return Err(ReadError::BadEscape),
        };
        escaped_char <<= 4;
        // No overflow is possible here – later check would
        // detect it.
        escaped_char += next_character as u32 - subtract_amount;
        if escaped_char > 0x10FFFF {
            // protect against overflow
            return Err(ReadError::BadEscape);
        }
    }
}

fn process_escape<R: BufRead>(file: &mut Peekable<Bytes<R>>) -> ReadResult {
    let bad = ReadError::BadEscape;
    loop {
        return Ok(match next!(file, ReadError::BadEscape) {
            b'n' => '\n',
            b't' => '\t',
            b'e' => '\x1b',
            b'b' => '\x08',
            b'v' => '\x0b',
            b'f' => '\x0c',
            b'\r' => {
                match file.next() {
                    Some(Ok(b'\n')) => continue,
                    Some(Ok(_)) | None => return Err(bad),
                    Some(Err(x)) => return Err(ReadError::IoError(x)),
                }
            }
            b'\n' => continue,
            b'x' | b'u' => try!(handle_unicode_escape(file)),
            l @ b'|' | l @ b'"' | l @ b'\\' | l @ b'#' | l @ b'`' | l @ b',' | l @ b'\'' => {
                l as char
            }
            _ => return Err(bad),
        });
    }
}

fn read_escaped<R: BufRead>(file: &mut Peekable<Bytes<R>>,
                            delimiter: StringOrSymbol)
                            -> Result<String, ReadError> {
    use std::char;
    let premature_eof = || {
        match delimiter {
            StringOrSymbol::String => ReadError::EOFInString,
            StringOrSymbol::Symbol => ReadError::EOFInSymbol,
        }
    };

    let mut buf = String::new();
    loop {
        buf.push(match next!(file, premature_eof()) {
            b'\\' => try!(process_escape(file)),
            b'|' if delimiter == StringOrSymbol::Symbol => break,
            b'"' if delimiter == StringOrSymbol::String => break,
            normal_char if normal_char <= 0x7F => normal_char as char,
            unicode_char => try!(char_from_stream_and_byte(file, unicode_char)),
        })
    }
    Ok(buf)
}

pub struct Reader<'a, 'b, T: 'a + BufRead> {
    stream: &'a mut T,
    state: &'b mut interp::State,
}

pub struct EventSource<'a, R: 'a + BufRead> {
    file: &'a mut Peekable<Bytes<R>>,
    last_chr: Option<u8>,
}

impl<'a, R: BufRead> EventSource<'a, R> {
    pub fn new(reader: &'a mut Peekable<Bytes<R>>) -> Self {
        EventSource {
            file: reader,
            last_chr: Default::default(),
        }
    }
}
impl<'a, R: BufRead> Iterator for EventSource<'a, R> {
    type Item = Result<Event, ReadError>;

    fn next(&mut self) -> Option<<Self as Iterator>::Item> {
        let handle_splicing = |file: &mut Peekable<Bytes<R>>, nosplice: Event, splice: Event| {
            let res1 = {
                let q = file.peek();
                match q {
                    Some(&Ok(b'@')) => (Ok(splice), true),
                    Some(&Ok(_)) | None => (Ok(nosplice), false),
                    Some(&Err(ref _a)) => (Err(()), true),
                }
            };
            match res1 {
                (Ok(good), take_char) => {
                    if take_char {
                        file.next();
                    }
                    Ok(good)
                }
                (Err(()), false) => unreachable!(),
                (Err(()), true) => Err(file.next().unwrap().unwrap_err()),
            }
        };

        macro_rules! my_try {
            ($exp: expr) => {
                match $exp {
                    Ok(x) => x,
                    Err(x) => return Some(Err(x)),
                }
            }
        }

        macro_rules! iter_next {
            ($exp: expr, $err: expr) => {
                my_try!(my_try!($exp.next().ok_or($err)).map_err(|x|ReadError::IoError(x)))
            }
        }
        loop {
            let chr = if let Some(chr) = self.last_chr {
                chr
            } else {
                let next: Option<Result<u8, io::Error>> = self.file.next();
                if let Some(c) = next {
                    my_try!(c.map_err(ReadError::IoError))
                } else {
                    return None;
                }
            };
            return Some(Ok(match chr {
                b'(' => Event::StartList(false),
                b'[' => Event::StartList(true),
                b'\'' => Event::Quote,
                b'`' => Event::Quasiquote,
                b',' => {
                    my_try!(handle_splicing(self.file, Event::Unquote, Event::UnquoteSplicing)
                                .map_err(ReadError::IoError))
                }
                b'#' => {
                    match iter_next!(self.file, ReadError::EOFAfterSharp) {
                        b'.' => Event::ReadEval,
                        b'\\' => {
                            let byte = iter_next!(self.file, ReadError::EOFAfterSharpBackslash);
                            Event::Char(my_try!(char_from_stream_and_byte(self.file, byte)))
                        }
                        b't' => Event::True,
                        b'f' => Event::False,
                        b'\'' => Event::Syntax,
                        b'`' => Event::Quasisyntax,
                        b',' => {
                            my_try!(handle_splicing(self.file,
                                                    Event::Unsyntax,
                                                    Event::UnsyntaxSplicing)
                                        .map_err(ReadError::IoError))
                        }
                        b'(' => Event::StartVec,
                        dispatch_char => {
                            return Some(Err(ReadError::BadSharpMacro([dispatch_char as char,
                                                                      '\0'])))
                        }
                    }
                }
                b')' => Event::EndList(false),
                b']' => Event::EndList(true),
                b'"' => Event::Str(my_try!(read_escaped(self.file, StringOrSymbol::String))),
                b'|' => Event::Symbol(my_try!(read_escaped(self.file, StringOrSymbol::Symbol))),
                b'\t'...b'\r' | b' ' => continue, // ASCII whitespace
                val => {
                    let chr = if val < 0x7F {
                        val as char
                    } else {
                        my_try!(char_from_stream_and_byte(self.file, val))
                    };
                    if chr.is_whitespace() {
                        continue;
                    }
                    let mut buf = String::new();
                    buf.push(chr);
                    loop {
                        let chr = if let Some(x) = self.file.next() {
                            my_try!(x.map_err(ReadError::IoError))
                        } else {
                            break;
                        };
                        match chr {
                            b'\\' => buf.push(my_try!(process_escape(self.file))),
                            b'|' => return Some(Err(ReadError::PipeInSymbol)),
                            a @ b'"' |
                            a @ b'\'' |
                            a @ b'`' |
                            a @ b',' |
                            a @ b'(' |
                            a @ b'[' |
                            a @ b']' |
                            a @ b')' |
                            a @ b'{' |
                            a @ b'}' => {
                                self.last_chr = Some(a);
                                break;
                            }
                            b'\t'...b'\r' | b' ' => break, // ASCII whitespace
                            chr => {
                                let unicode_char = my_try!(char_from_stream_and_byte(self.file,
                                                                                chr));
                                if unicode_char.is_whitespace() {
                                    break;
                                }
                                buf.push(unicode_char)
                            }
                        }
                    }
                    return Some(Ok(if &buf == "." {
                        Event::Dot
                    } else {
                        Event::Symbol(buf)
                    }));
                }
            }));
        }
    }
}
<|endoftext|>


<commit_before>use proc_macro2::TokenStream;
use quote::{ToTokens, TokenStreamExt};
use syn;

/// Field for the builder struct, implementing `quote::ToTokens`.
///
/// # Examples
///
/// Will expand to something like the following (depending on settings):
///
/// ```rust
/// # extern crate proc_macro2;
/// # #[macro_use]
/// # extern crate quote;
/// # #[macro_use]
/// # extern crate syn;
/// # #[macro_use]
/// # extern crate derive_builder_core;
/// # use derive_builder_core::{BuilderField, BuilderPattern};
/// # fn main() {
/// #    let attrs = vec![parse_quote!(#[some_attr])];
/// #    let mut field = default_builder_field!();
/// #    field.attrs = attrs.as_slice();
/// #
/// #    assert_eq!(quote!(#field).to_string(), quote!(
/// #[some_attr] pub foo: ::derive_builder::export::core::option::Option<String>,
/// #    ).to_string());
/// # }
/// ```
#[derive(Debug, Clone)]
pub struct BuilderField<'a> {
    /// Name of the target field.
    pub field_ident: &'a syn::Ident,
    /// Type of the target field.
    ///
    /// The corresonding builder field will be `Option<field_type>`.
    pub field_type: &'a syn::Type,
    /// Whether the builder implements a setter for this field.
    ///
    /// Note: We will fallback to `PhantomData` if the setter is disabled
    ///       to hack around issues with unused generic type parameters - at
    ///       least for now.
    pub field_enabled: bool,
    /// Visibility of this builder field, e.g. `syn::Visibility::Public`.
    pub field_visibility: syn::Visibility,
    /// Attributes which will be attached to this builder field.
    pub attrs: &'a [syn::Attribute],
}

impl<'a> ToTokens for BuilderField<'a> {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        if self.field_enabled {
            trace!("Deriving builder field for `{}`.", self.field_ident);
            let vis = &self.field_visibility;
            let ident = self.field_ident;
            let ty = self.field_type;
            let attrs = self.attrs;

            tokens.append_all(quote!(
                #(#attrs)* #vis #ident: ::derive_builder::export::core::option::Option<#ty>,
            ));
        } else {
            trace!(
                "Skipping builder field for `{}`, fallback to PhantomData.",
                self.field_ident
            );
            let ident = self.field_ident;
            let ty = self.field_type;
            let attrs = self.attrs;

            tokens.append_all(quote!(
                #(#attrs)* #ident: ::derive_builder::export::core::marker::PhantomData<#ty>,
            ));
        }
    }
}

impl<'a> BuilderField<'a> {
    /// Emits a struct field initializer that initializes the field to `Default::default`.
    pub fn default_initializer_tokens(&self) -> TokenStream {
        let ident = self.field_ident;
        quote!{ #ident : ::derive_builder::export::core::default::Default::default(), }
    }
}

/// Helper macro for unit tests. This is _only_ public in order to be accessible
/// from doc-tests too.
#[doc(hidden)]
#[macro_export]
macro_rules! default_builder_field {
    () => {{
        BuilderField {
            field_ident: &syn::Ident::new("foo", ::proc_macro2::Span::call_site()),
            field_type: &syn::parse_str("String").unwrap(),
            field_enabled: true,
            field_visibility: syn::parse_str("pub").unwrap(),
            attrs: &[parse_quote!(#[some_attr])],
        }
    }};
}

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

    #[test]
    fn setter_enabled() {
        let field = default_builder_field!();

        assert_eq!(
            quote!(#field).to_string(),
            quote!(
                #[some_attr] pub foo: ::derive_builder::export::core::option::Option<String>,
            )
            .to_string()
        );
    }

    #[test]
    fn setter_disabled() {
        let mut field = default_builder_field!();
        field.field_enabled = false;

        assert_eq!(
            quote!(#field).to_string(),
            quote!(
                #[some_attr]
                foo: ::derive_builder::export::core::marker::PhantomData<String>,
            )
            .to_string()
        );
    }

    #[test]
    fn private_field() {
        let private = syn::Visibility::Inherited;
        let mut field = default_builder_field!();
        field.field_visibility = private;

        assert_eq!(
            quote!(#field).to_string(),
            quote!(
                #[some_attr]
                foo: ::derive_builder::export::core::option::Option<String>,
            )
            .to_string()
        );
    }
}
<commit_msg>Fix rustfmt violation<commit_after>use proc_macro2::TokenStream;
use quote::{ToTokens, TokenStreamExt};
use syn;

/// Field for the builder struct, implementing `quote::ToTokens`.
///
/// # Examples
///
/// Will expand to something like the following (depending on settings):
///
/// ```rust
/// # extern crate proc_macro2;
/// # #[macro_use]
/// # extern crate quote;
/// # #[macro_use]
/// # extern crate syn;
/// # #[macro_use]
/// # extern crate derive_builder_core;
/// # use derive_builder_core::{BuilderField, BuilderPattern};
/// # fn main() {
/// #    let attrs = vec![parse_quote!(#[some_attr])];
/// #    let mut field = default_builder_field!();
/// #    field.attrs = attrs.as_slice();
/// #
/// #    assert_eq!(quote!(#field).to_string(), quote!(
/// #[some_attr] pub foo: ::derive_builder::export::core::option::Option<String>,
/// #    ).to_string());
/// # }
/// ```
#[derive(Debug, Clone)]
pub struct BuilderField<'a> {
    /// Name of the target field.
    pub field_ident: &'a syn::Ident,
    /// Type of the target field.
    ///
    /// The corresonding builder field will be `Option<field_type>`.
    pub field_type: &'a syn::Type,
    /// Whether the builder implements a setter for this field.
    ///
    /// Note: We will fallback to `PhantomData` if the setter is disabled
    ///       to hack around issues with unused generic type parameters - at
    ///       least for now.
    pub field_enabled: bool,
    /// Visibility of this builder field, e.g. `syn::Visibility::Public`.
    pub field_visibility: syn::Visibility,
    /// Attributes which will be attached to this builder field.
    pub attrs: &'a [syn::Attribute],
}

impl<'a> ToTokens for BuilderField<'a> {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        if self.field_enabled {
            trace!("Deriving builder field for `{}`.", self.field_ident);
            let vis = &self.field_visibility;
            let ident = self.field_ident;
            let ty = self.field_type;
            let attrs = self.attrs;

            tokens.append_all(quote!(
                #(#attrs)* #vis #ident: ::derive_builder::export::core::option::Option<#ty>,
            ));
        } else {
            trace!(
                "Skipping builder field for `{}`, fallback to PhantomData.",
                self.field_ident
            );
            let ident = self.field_ident;
            let ty = self.field_type;
            let attrs = self.attrs;

            tokens.append_all(quote!(
                #(#attrs)* #ident: ::derive_builder::export::core::marker::PhantomData<#ty>,
            ));
        }
    }
}

impl<'a> BuilderField<'a> {
    /// Emits a struct field initializer that initializes the field to `Default::default`.
    pub fn default_initializer_tokens(&self) -> TokenStream {
        let ident = self.field_ident;
        quote! { #ident : ::derive_builder::export::core::default::Default::default(), }
    }
}

/// Helper macro for unit tests. This is _only_ public in order to be accessible
/// from doc-tests too.
#[doc(hidden)]
#[macro_export]
macro_rules! default_builder_field {
    () => {{
        BuilderField {
            field_ident: &syn::Ident::new("foo", ::proc_macro2::Span::call_site()),
            field_type: &syn::parse_str("String").unwrap(),
            field_enabled: true,
            field_visibility: syn::parse_str("pub").unwrap(),
            attrs: &[parse_quote!(#[some_attr])],
        }
    }};
}

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

    #[test]
    fn setter_enabled() {
        let field = default_builder_field!();

        assert_eq!(
            quote!(#field).to_string(),
            quote!(
                #[some_attr] pub foo: ::derive_builder::export::core::option::Option<String>,
            )
            .to_string()
        );
    }

    #[test]
    fn setter_disabled() {
        let mut field = default_builder_field!();
        field.field_enabled = false;

        assert_eq!(
            quote!(#field).to_string(),
            quote!(
                #[some_attr]
                foo: ::derive_builder::export::core::marker::PhantomData<String>,
            )
            .to_string()
        );
    }

    #[test]
    fn private_field() {
        let private = syn::Visibility::Inherited;
        let mut field = default_builder_field!();
        field.field_visibility = private;

        assert_eq!(
            quote!(#field).to_string(),
            quote!(
                #[some_attr]
                foo: ::derive_builder::export::core::option::Option<String>,
            )
            .to_string()
        );
    }
}
<|endoftext|>


<commit_before>extern mod linenoise;

mod rush {
    extern mod linenoise;
    extern mod core;
    use core::run;

    pub fn exec_command(stdin_fd: libc::c_int, command: &str) -> libc::c_int {
        let pipe_out = os::pipe();
        let pipe_err = os::pipe();
        let mut args: ~[~str] = ~[];
        let mut prog = ~"";
        let mut first = true;
        str::each_split_char(command, ' ', |item| {
            if (first) {
                prog = copy item.to_owned();
                first = false;
            } else {
                args.push(item.to_owned());
            }
            true
        });
        let pid = run::spawn_process(
                prog, args, &None, &None,
                stdin_fd, pipe_out.out, pipe_err.out);
        os::close(pipe_out.out);
        os::close(pipe_err.out);
        do task::spawn_sched(task::SingleThreaded) || {
            run::waitpid(pid);
        }
        pipe_out.in
    }

    pub fn handle_input(line: &str) {
        linenoise::history_add(line);
        linenoise::history_save("history.txt");
        let mut commands: ~[&str] = ~[];
        str::each_split_char_no_trailing(line, '|', |command| { commands.push(str::trim(command)); true });
        let pipe_in = os::pipe();
        let std_out = vec::foldl(pipe_in.in, commands, |stdin, command| {
            exec_command(stdin, *command)
        });
        os::close(pipe_in.out);
        do task::spawn_sched(task::SingleThreaded) || {
            io::print(core::run::readclose(std_out));
        }
    }

}

fn main() {
    linenoise::set_multiline(true);
    loop {
        let line = linenoise::init("rush: ");
        rush::handle_input(line);
    }
}
<commit_msg>Try outputting without waiting for EOF<commit_after>extern mod linenoise;

mod rush {
    extern mod linenoise;
    extern mod core;
    use core::run;

    pub fn exec_command(stdin_fd: libc::c_int, command: &str) -> libc::c_int {
        let pipe_out = os::pipe();
        let pipe_err = os::pipe();
        let mut args: ~[~str] = ~[];
        let mut prog = ~"";
        let mut first = true;
        str::each_split_char(command, ' ', |item| {
            if (first) {
                prog = copy item.to_owned();
                first = false;
            } else {
                args.push(item.to_owned());
            }
            true
        });
        let pid = run::spawn_process(
                prog, args, &None, &None,
                stdin_fd, pipe_out.out, pipe_err.out);
        os::close(pipe_out.out);
        os::close(pipe_err.out);
        do task::spawn_sched(task::SingleThreaded) || {
            run::waitpid(pid);
        }
        pipe_out.in
    }

    pub fn handle_input(line: &str) {
        linenoise::history_add(line);
        linenoise::history_save("history.txt");
        let mut commands: ~[&str] = ~[];
        str::each_split_char_no_trailing(line, '|', |command| { commands.push(str::trim(command)); true });
        let pipe_in = os::pipe();
        let std_out = vec::foldl(pipe_in.in, commands, |stdin, command| {
            exec_command(stdin, *command)
        });
        os::close(pipe_in.out);

        do task::spawn_sched(task::SingleThreaded) || {
            unsafe {
                let file = os::fdopen(std_out);
                let reader = io::FILE_reader(file, false);
                let buf = io::with_bytes_writer(|writer| {
                    let mut bytes = [0, ..4096];
                    while !reader.eof() {
                        let nread = reader.read(bytes, bytes.len());
                        writer.write(bytes.slice(0, nread));
                        io::print(str::from_bytes(bytes.slice(0, nread)))
                    }
                });
                os::fclose(file);
            }
        }
    }

}

fn main() {
    linenoise::set_multiline(true);
    loop {
        let line = linenoise::init("rush: ");
        rush::handle_input(line);
    }
}
<|endoftext|>


<commit_before>use crate::common::util::*;

#[test]
fn test_encode() {
    let input = "hello, world!";
    new_ucmd!()
        .pipe_in(input)
        .succeeds()
        .stdout_only("aGVsbG8sIHdvcmxkIQ==\n"); // spell-checker:disable-line

    // Using '-' as our file
    new_ucmd!()
        .arg("-")
        .pipe_in(input)
        .succeeds()
        .stdout_only("aGVsbG8sIHdvcmxkIQ==\n"); // spell-checker:disable-line
}

#[test]
fn test_base64_encode_file() {
    new_ucmd!()
        .arg("input-simple.txt")
        .succeeds()
        .stdout_only("SGVsbG8sIFdvcmxkIQo=\n"); // spell-checker:disable-line
}

#[test]
fn test_decode() {
    for decode_param in &["-d", "--decode"] {
        let input = "aGVsbG8sIHdvcmxkIQ=="; // spell-checker:disable-line
        new_ucmd!()
            .arg(decode_param)
            .pipe_in(input)
            .succeeds()
            .stdout_only("hello, world!");
    }
}

#[test]
fn test_garbage() {
    let input = "aGVsbG8sIHdvcmxkIQ==\0"; // spell-checker:disable-line
    new_ucmd!()
        .arg("-d")
        .pipe_in(input)
        .fails()
        .stderr_only("base64: error: invalid input\n");
}

#[test]
fn test_ignore_garbage() {
    for ignore_garbage_param in &["-i", "--ignore-garbage"] {
        let input = "aGVsbG8sIHdvcmxkIQ==\0"; // spell-checker:disable-line
        new_ucmd!()
            .arg("-d")
            .arg(ignore_garbage_param)
            .pipe_in(input)
            .succeeds()
            .stdout_only("hello, world!");
    }
}

#[test]
fn test_wrap() {
    for wrap_param in &["-w", "--wrap"] {
        let input = "The quick brown fox jumps over the lazy dog.";
        new_ucmd!()
            .arg(wrap_param)
            .arg("20")
            .pipe_in(input)
            .succeeds()
            // spell-checker:disable-next-line
            .stdout_only("VGhlIHF1aWNrIGJyb3du\nIGZveCBqdW1wcyBvdmVy\nIHRoZSBsYXp5IGRvZy4=\n");
    }
}

#[test]
fn test_wrap_no_arg() {
    for wrap_param in &["-w", "--wrap"] {
        new_ucmd!().arg(wrap_param).fails().stderr_contains(
            &"The argument '--wrap <wrap>' requires a value but none was supplied",
        );
    }
}

#[test]
fn test_wrap_bad_arg() {
    for wrap_param in &["-w", "--wrap"] {
        new_ucmd!()
            .arg(wrap_param)
            .arg("b")
            .fails()
            .stderr_only("base64: invalid wrap size: 'b'\n");
    }
}

#[test]
fn test_base64_extra_operand() {
    // Expect a failure when multiple files are specified.
    new_ucmd!()
        .arg("a.txt")
        .arg("b.txt")
        .fails()
        .stderr_only("base64: extra operand 'b.txt'\nTry 'base64 --help' for more information.");
}

#[test]
fn test_base64_file_not_found() {
    new_ucmd!()
        .arg("a.txt")
        .fails()
        .stderr_only("base64: a.txt: No such file or directory");
}
<commit_msg>tests/base64: update test<commit_after>use crate::common::util::*;

#[test]
fn test_encode() {
    let input = "hello, world!";
    new_ucmd!()
        .pipe_in(input)
        .succeeds()
        .stdout_only("aGVsbG8sIHdvcmxkIQ==\n"); // spell-checker:disable-line

    // Using '-' as our file
    new_ucmd!()
        .arg("-")
        .pipe_in(input)
        .succeeds()
        .stdout_only("aGVsbG8sIHdvcmxkIQ==\n"); // spell-checker:disable-line
}

#[test]
fn test_base64_encode_file() {
    new_ucmd!()
        .arg("input-simple.txt")
        .succeeds()
        .stdout_only("SGVsbG8sIFdvcmxkIQo=\n"); // spell-checker:disable-line
}

#[test]
fn test_decode() {
    for decode_param in &["-d", "--decode"] {
        let input = "aGVsbG8sIHdvcmxkIQ=="; // spell-checker:disable-line
        new_ucmd!()
            .arg(decode_param)
            .pipe_in(input)
            .succeeds()
            .stdout_only("hello, world!");
    }
}

#[test]
fn test_garbage() {
    let input = "aGVsbG8sIHdvcmxkIQ==\0"; // spell-checker:disable-line
    new_ucmd!()
        .arg("-d")
        .pipe_in(input)
        .fails()
        .stderr_only("base64: error: invalid input\n");
}

#[test]
fn test_ignore_garbage() {
    for ignore_garbage_param in &["-i", "--ignore-garbage"] {
        let input = "aGVsbG8sIHdvcmxkIQ==\0"; // spell-checker:disable-line
        new_ucmd!()
            .arg("-d")
            .arg(ignore_garbage_param)
            .pipe_in(input)
            .succeeds()
            .stdout_only("hello, world!");
    }
}

#[test]
fn test_wrap() {
    for wrap_param in &["-w", "--wrap"] {
        let input = "The quick brown fox jumps over the lazy dog.";
        new_ucmd!()
            .arg(wrap_param)
            .arg("20")
            .pipe_in(input)
            .succeeds()
            // spell-checker:disable-next-line
            .stdout_only("VGhlIHF1aWNrIGJyb3du\nIGZveCBqdW1wcyBvdmVy\nIHRoZSBsYXp5IGRvZy4=\n");
    }
}

#[test]
fn test_wrap_no_arg() {
    for wrap_param in &["-w", "--wrap"] {
        new_ucmd!().arg(wrap_param).fails().stderr_contains(
            &"The argument '--wrap <wrap>' requires a value but none was supplied",
        );
    }
}

#[test]
fn test_wrap_bad_arg() {
    for wrap_param in &["-w", "--wrap"] {
        new_ucmd!()
            .arg(wrap_param)
            .arg("b")
            .fails()
            .stderr_only("base64: invalid wrap size: 'b'\n");
    }
}

#[test]
fn test_base64_extra_operand() {
    let ts = TestScenario::new(util_name!());

    // Expect a failure when multiple files are specified.
    ts.ucmd()
        .arg("a.txt")
        .arg("b.txt")
        .fails()
        .stderr_only(format!(
            "{0}: extra operand 'b.txt'\nTry '{1} {0} --help' for more information.",
            ts.util_name,
            ts.bin_path.to_string_lossy()
        ));
}

#[test]
fn test_base64_file_not_found() {
    new_ucmd!()
        .arg("a.txt")
        .fails()
        .stderr_only("base64: a.txt: No such file or directory");
}
<|endoftext|>