<commit_before>use std::collections::HashMap;
use std::future::Future;
use std::sync::{Mutex, Arc};

use async_std::{fs, path::{Path, PathBuf}};

use http::status::StatusCode;

use serde::{Deserialize, Serialize};

use tide::{prelude::*, IntoResponse, Request, Response, ResultExt, Server};

struct Database {
    contents: Mutex<HashMap<usize, Message>>,
    static_file_server: Mutex<StaticFileHandler>
}

#[derive(Serialize, Deserialize, Clone)]
struct Message {
    author: Option<String>,
    contents: String
}

impl Database {
    async fn new(root_path: &str) -> std::io::Result<Database> {
        Ok(Database {
            contents: Default::default(),
            static_file_server: Mutex::new(StaticFileHandler::new(root_path).await?)
        })
    }

    fn set(&self, id: usize, msg: Message) {
        let mut contents = self.contents.lock().unwrap();

        if contents.contains_key(&id) {
            contents.entry(id).and_modify(|v| *v = msg);
            return
        }

        contents.insert(id, msg);
    }

    fn get(&self, id: usize) -> Option<Message> {
        let mut contents = self.contents.lock().unwrap();

        match contents.get(&id) {
            Some(v) => Some(v.clone()),
            None => None
        }
    }
}

struct StaticFileHandler {
    root_path: PathBuf,
    file_cache: HashMap<PathBuf, Arc<Mutex<String>>>
}

impl StaticFileHandler {
    async fn new(root_path: &str) -> std::io::Result<StaticFileHandler> {
        let abs_root_path = fs::canonicalize(root_path).await?;

        Ok(StaticFileHandler {
            root_path : abs_root_path,
            file_cache : Default::default()
        })
    }

    async fn check_valid_path(&self, input_path: &Path) -> std::io::Result<bool> {
        let abs_input_path = fs::canonicalize(input_path).await?;

        Ok(abs_input_path.as_path().starts_with(&self.root_path))
    }

    async fn cache_file(&mut self, input_path: &Path) -> std::io::Result<bool> {
        debug_assert!(self.check_valid_path(input_path).await?);

        // 1. load file
        let new_file_data = Arc::new(Mutex::new(fs::read_to_string(input_path).await?));

        // 2. build key
        let abs_input_path = fs::canonicalize(input_path).await?;

        // 3. set key value
        if self.file_cache.contains_key(&abs_input_path) {
            self.file_cache.entry(abs_input_path).and_modify(|e| *e = new_file_data);
        }
        else {
            self.file_cache.insert(abs_input_path, new_file_data);
        }

        Ok(true)
    }

    async fn get_cached_file(&self, input_path: &Path) -> std::io::Result<Arc<Mutex<String>>> {
        if !self.check_valid_path(input_path).await? {
            return Err(std::io::Error::from(std::io::ErrorKind::NotFound))
        }

        let abs_input_path = fs::canonicalize(input_path).await?;

        if !self.file_cache.contains_key(&abs_input_path) {
            self.cache_file(&abs_input_path).await?;
        }

        match self.file_cache.get(&abs_input_path) {
            Some(v) => Ok(v.clone()),
            None => Err(std::io::Error::from(std::io::ErrorKind::NotFound))
        }
    }
}

async fn handle_post(mut req: Request<Database>) -> Response {
    let mut msg = match req.body_json().await.client_err() {
        Ok(v) => v,
        Err(e) => return e.into_response()
    };
    let id = match req.param("id").client_err() {
        Ok(v) => v,
        Err(e) =>  return e.into_response()
    };

    req.state().set(id, msg);
    Response::new(StatusCode::OK.into()).body_string("".to_owned())
}

async fn handle_get(mut req: Request<Database>) -> Response {
    let id = match req.param("id").client_err() {
        Ok(v) => v,
        Err(e) => return e.into_response()
    };

    if let Some(msg) = req.state().get(id) {
        match Response::new(StatusCode::OK.into()).body_json(&msg) {
            Ok(v) => v,
            _ => Response::new(StatusCode::INTERNAL_SERVER_ERROR.into())

        }
    }
    else {
        Response::new(StatusCode::NOT_FOUND.into())
    }
}

async fn handle_get_static(mut req: Request<Database>) -> Response {
    let rel_path_buf = req.uri().path().to_owned();
    let rel_path = Path::new(&rel_path_buf[7..]);

    let mut sfs = req.state().static_file_server.lock().unwrap();

    match sfs.get_cached_file(&rel_path).await {
        //Ok(v) => Response::new(StatusCode::OK.into()).body_string(*v),
        Ok(v) => Response::new(StatusCode::OK.into()),
        _ => Response::new(StatusCode::INTERNAL_SERVER_ERROR.into())
    }
}

#[async_std::main]
async fn main() -> std::io::Result<()> {
    let database = Database::new("./static_files/").await?;

    let mut app = Server::with_state(database);
    app.at("/").get(|_| async move { "Hello, world!" });
    app.at("/message/:id").post(handle_post).get(handle_get);
    app.at("/static/*").get(handle_get_static);
    app.listen("127.0.0.1:8080").await?;
    Ok(())
}
<commit_msg>Rust_Tide: solving 'future is not send' problem.<commit_after>use std::collections::HashMap;
use std::future::Future;
use std::sync::{Mutex, Arc};
use std::time::Duration;

use async_std::{fs, path::{Path, PathBuf}, task};

use http::status::StatusCode;

use serde::{Deserialize, Serialize};

use tide::{prelude::*, IntoResponse, Request, Response, ResultExt, Server};

struct GlobalStorage {
    database: Arc<Mutex<Database>>
}

struct Database {
    message_storage: HashMap<usize, Message>,
    static_file_server: StaticFileHandler
}

#[derive(Serialize, Deserialize, Clone)]
struct Message {
    author: Option<String>,
    contents: String
}

impl GlobalStorage {
    async fn new(root_path: &str) -> std::io::Result<GlobalStorage> {
        Ok(GlobalStorage {
            database: Arc::new(Mutex::new(Database {
                message_storage: Default::default(),
                static_file_server: StaticFileHandler::new(root_path).await?
            }))
        })
    }

    fn set(&self, id: usize, msg: Message) {
        let contents = &mut self.database.lock().unwrap().message_storage;

        if contents.contains_key(&id) {
            contents.entry(id).and_modify(|v| *v = msg);
            return
        }

        contents.insert(id, msg);
    }

    fn get(&self, id: usize) -> Option<Message> {
        let contents = &self.database.lock().unwrap().message_storage;

        match contents.get(&id) {
            Some(v) => Some(v.clone()),
            None => None
        }
    }

    fn clone(&self) -> GlobalStorage {
        GlobalStorage {
            database: self.database.clone()
        }
    }

    async fn delay(&self) {
        println!("delaying...");
        task::sleep(Duration::from_secs(3)).await;
        println!("done...");
    }

}

async fn handle_post(mut req: Request<GlobalStorage>) -> Response {
    let msg = match req.body_json().await.client_err() {
        Ok(v) => v,
        Err(e) => {
            println!("body json parse failed. e = {:#?}", e);
            return e.into_response()
        }
    };
    let id = match req.param("id").client_err() {
        Ok(v) => v,
        Err(e) => {
            println!("param id is not found. {:#?}", e);
            return e.into_response()
        }
    };

    req.state().set(id, msg);
    Response::new(StatusCode::OK.into()).body_string("".to_owned())
}

async fn handle_get(req: Request<GlobalStorage>) -> Response {
    let id = match req.param("id").client_err() {
        Ok(v) => v,
        Err(e) => return e.into_response()
    };

    if let Some(msg) = req.state().get(id) {
        match Response::new(StatusCode::OK.into()).body_json(&msg) {
            Ok(v) => v,
            _ => Response::new(StatusCode::INTERNAL_SERVER_ERROR.into())

        }
    }
    else {
        Response::new(StatusCode::NOT_FOUND.into())
    }
}

async fn handle_delay(req: Request<GlobalStorage>) -> Response {
    let cloned_state = {
        req.state().clone()
    };

    cloned_state.delay().await;
    Response::new(StatusCode::OK.into()).body_string("ok.".to_owned())
}

/*
struct Database {
    contents: Mutex<HashMap<usize, Message>>,
    static_file_server: Mutex<StaticFileHandler>
}

#[derive(Serialize, Deserialize, Clone)]
struct Message {
    author: Option<String>,
    contents: String
}

impl Database {
    async fn new(root_path: &str) -> std::io::Result<Database> {
        Ok(Database {
            contents: Default::default(),
            static_file_server: Mutex::new(StaticFileHandler::new(root_path).await?)
        })
    }

    fn set(&self, id: usize, msg: Message) {
        let mut contents = self.contents.lock().unwrap();

        if contents.contains_key(&id) {
            contents.entry(id).and_modify(|v| *v = msg);
            return
        }

        contents.insert(id, msg);
    }

    fn get(&self, id: usize) -> Option<Message> {
        let mut contents = self.contents.lock().unwrap();

        match contents.get(&id) {
            Some(v) => Some(v.clone()),
            None => None
        }
    }
}
*/

struct StaticFileHandler {
    root_path: PathBuf,
    file_cache: HashMap<PathBuf, Arc<Mutex<String>>>
}

impl StaticFileHandler {
    async fn new(root_path: &str) -> std::io::Result<StaticFileHandler> {
        let abs_root_path = fs::canonicalize(root_path).await?;

        Ok(StaticFileHandler {
            root_path : abs_root_path,
            file_cache : Default::default()
        })
    }

    /*
    async fn check_valid_path(&self, input_path: &Path) -> std::io::Result<bool> {
        let abs_input_path = fs::canonicalize(input_path).await?;

        Ok(abs_input_path.as_path().starts_with(&self.root_path))
    }

    async fn cache_file(&mut self, input_path: &Path) -> std::io::Result<bool> {
        debug_assert!(self.check_valid_path(input_path).await?);

        // 1. load file
        let new_file_data = Arc::new(Mutex::new(fs::read_to_string(input_path).await?));

        // 2. build key
        let abs_input_path = fs::canonicalize(input_path).await?;

        // 3. set key value
        if self.file_cache.contains_key(&abs_input_path) {
            self.file_cache.entry(abs_input_path).and_modify(|e| *e = new_file_data);
        }
        else {
            self.file_cache.insert(abs_input_path, new_file_data);
        }

        Ok(true)
    }

    async fn get_cached_file(&self, input_path: &Path) -> std::io::Result<Arc<Mutex<String>>> {
        if !self.check_valid_path(input_path).await? {
            return Err(std::io::Error::from(std::io::ErrorKind::NotFound))
        }

        let abs_input_path = fs::canonicalize(input_path).await?;

        if !self.file_cache.contains_key(&abs_input_path) {
            self.cache_file(&abs_input_path).await?;
        }

        match self.file_cache.get(&abs_input_path) {
            Some(v) => Ok(v.clone()),
            None => Err(std::io::Error::from(std::io::ErrorKind::NotFound))
        }
    }
    */
}

/*
async fn handle_post(mut req: Request<Database>) -> Response {
    let mut msg = match req.body_json().await.client_err() {
        Ok(v) => v,
        Err(e) => return e.into_response()
    };
    let id = match req.param("id").client_err() {
        Ok(v) => v,
        Err(e) =>  return e.into_response()
    };

    req.state().set(id, msg);
    Response::new(StatusCode::OK.into()).body_string("".to_owned())
}

async fn handle_get(mut req: Request<Database>) -> Response {
    let id = match req.param("id").client_err() {
        Ok(v) => v,
        Err(e) => return e.into_response()
    };

    if let Some(msg) = req.state().get(id) {
        match Response::new(StatusCode::OK.into()).body_json(&msg) {
            Ok(v) => v,
            _ => Response::new(StatusCode::INTERNAL_SERVER_ERROR.into())

        }
    }
    else {
        Response::new(StatusCode::NOT_FOUND.into())
    }
}

async fn handle_get_static(mut req: Request<Database>) -> Response {
    let rel_path_buf = req.uri().path().to_owned();
    let rel_path = Path::new(&rel_path_buf[7..]);

    let mut sfs = req.state().static_file_server.lock().unwrap();

    match sfs.get_cached_file(&rel_path).await {
        //Ok(v) => Response::new(StatusCode::OK.into()).body_string(*v),
        Ok(v) => Response::new(StatusCode::OK.into()),
        _ => Response::new(StatusCode::INTERNAL_SERVER_ERROR.into())
    }
}

*/

#[async_std::main]
async fn main() -> std::io::Result<()> {
    let database = GlobalStorage::new("./static_files/").await?;

    let mut app = Server::with_state(database);
    app.at("/").get(|_| async move { "Hello, world!" });
    app.at("/message/:id").post(handle_post).get(handle_get);
    app.at("/delay").get(handle_delay);
    //app.at("/static/*").get(handle_get_static);
    app.listen("127.0.0.1:9876").await?;
    Ok(())
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate image;

use clap::{Arg,App,SubCommand};
use std::fs::File;
use image::{FilterType, GenericImage, Pixel};
use image::DynamicImage;
use std::path::Path;

fn main() {
     let matches = App::new("IPCLI ")
                          .version("0.1")
                          .author("Mikolaj Wawrzyniak <mikolaj.wawrzyniak at fh-dortmund.de>")
                          .about("Basic CLI for image processing")
                          .arg(Arg::with_name("operation")
                               .short("o")
                               .long("operation")
                               .help("Specifies operation to be done on the image")
                               .takes_value(true)
                               .required(true))
                          .arg(Arg::with_name("value")
                               .short("v")
                               .long("value")
                               .help("Value for the transformation. To see what values are needed, check the documentation.")
                               .takes_value(true)
                               .required(false))
                          .arg(Arg::with_name("image")
                               .short("i")
                               .long("image")
                               .value_name("FILE")
                               .help("Opens specified image file and uses it for transformations.")
                               .takes_value(true)
                               .required(true))
                          .get_matches();

    let imagePath = matches.value_of("image").unwrap_or("empty");
    println!("Transforming the image: {}", imagePath);

    let operation = matches.value_of("operation").unwrap_or("empty");
    println!("Using operation: {}", operation);

    let value = matches.value_of("value").unwrap_or("empty");
    println!("Value: {}", value);

    match operation.as_ref(){
        "copy" => {copy(imagePath)}
        "thumbnail" => {
            let size: u32 = value.parse().unwrap();
            createThumnbail(imagePath, size)}
        "blur" => {
            let v : f32 = value.parse().unwrap();
            gaussianBlur(imagePath,v)}
        "brighten" => {
            let v: i32 = value.parse().unwrap();
            brighten(imagePath,v)}
        "huerotate" => {
            let v: i32 = value.parse().unwrap();
            huerotate(imagePath,v)}
        "contrast" => {
            let v: f32 = value.parse().unwrap();
            contrast(imagePath,v);}
        "grayscale" => {
            grayscale(imagePath);
        }
        "invert" => {
            invert(imagePath);
        }
        _ => {println!("Not implemented yet!")}
    }
}

fn createThumnbail(i: &str, size: u32){
    let operation = "Thumbnail";
    let img = image::open(i).expect("Opening image failed");
    let thumbnail = img.resize(size,size, FilterType::Lanczos3);
    saveFile(&thumbnail, &i, &operation);

}

fn copy(i: &str){
    let operation = "Copy";
    let img = image::open(i).expect("Opening image failed");
    saveFile(&img, &i, &operation);
}

fn gaussianBlur(i: &str, v: f32){
    let operation = "GuassianBlur";
    let img = image::open(i).expect("Opening image failed");
    let blurred = img.blur(v);
    saveFile(&blurred, &i, &operation);
}

fn brighten(i: &str,v: i32){
    let operation = "Brighten";
    let img = image::open(i).expect("Opening image failed");
    let brightened = img.brighten(v);
    saveFile(&brightened, &i, &operation);
}

fn huerotate(i: &str, v: i32){
    let operation = "Huerotate";
    let img = image::open(i).expect("Opening image failed");
    let huerotated = img.huerotate(v);
    saveFile(&huerotated, &i, &operation);
}

fn contrast(i: &str, v: f32){
    let operation = "AdjustContrast";
    let img = image::open(i).expect("Opening image failed");
    let contrast = img.adjust_contrast(v);
    saveFile(&contrast, &i, &operation);
}

fn grayscale(i: &str){
    let operation = "Grayscale";
    let img = image::open(i).expect("Opening image failed");
    let grayscale = img.grayscale();
    saveFile(&grayscale, &i, &operation);
}

fn invert(i: &str){
    let operation = "Invert";
    let mut img = image::open(i).expect("Opening image failed");
    img.invert();
    saveFile(&img, &i, &operation);
}

fn saveFile(img: &DynamicImage, i: &str, operation: &str){
    let mut outputPath: String = i.chars().take(i.len()-4).collect();
    let ext: String = i.chars().skip(i.len()-3).take(3).collect();
    outputPath.push_str(operation);
    outputPath.push_str(".");
    outputPath.push_str(&ext);
    println!("Output path: {}", outputPath);
    let mut out = File::create(outputPath).unwrap();
    match ext.as_ref() {
        "jpg" | "JPG" => {img.save(&mut out, image::JPEG).expect("Saving image failed");}
        "png" | "PNG" => {img.save(&mut out, image::PNG).expect("Saving image failed");}
        "gif" | "GIF" => {img.save(&mut out, image::GIF).expect("Saving image failed");}
        "bmp" | "BMP" => {img.save(&mut out, image::BMP).expect("Saving image failed");}
        "ico" | "ICO" => {img.save(&mut out, image::ICO).expect("Saving image failed");}
        _ => {println!("Unsupported file format")}
    }
}

<commit_msg>added average color function<commit_after>extern crate clap;
extern crate image;

use clap::{Arg,App,SubCommand};
use std::fs::File;
use image::{FilterType, GenericImage, Pixel};
use image::DynamicImage;
use std::path::Path;

fn main() {
     let matches = App::new("IPCLI ")
                          .version("0.1")
                          .author("Mikolaj Wawrzyniak <mikolaj.wawrzyniak at fh-dortmund.de>")
                          .about("Basic CLI for image processing")
                          .arg(Arg::with_name("operation")
                               .short("o")
                               .long("operation")
                               .help("Specifies operation to be done on the image")
                               .takes_value(true)
                               .required(true))
                          .arg(Arg::with_name("value")
                               .short("v")
                               .long("value")
                               .help("Value for the transformation. To see what values are needed, check the documentation.")
                               .takes_value(true)
                               .required(false))
                          .arg(Arg::with_name("image")
                               .short("i")
                               .long("image")
                               .value_name("FILE")
                               .help("Opens specified image file and uses it for transformations.")
                               .takes_value(true)
                               .required(true))
                          .get_matches();

    let imagePath = matches.value_of("image").unwrap_or("empty");
    println!("Transforming the image: {}", imagePath);

    let operation = matches.value_of("operation").unwrap_or("empty");
    println!("Using operation: {}", operation);

    let value = matches.value_of("value").unwrap_or("empty");
    println!("Value: {}", value);

    match operation.as_ref(){
        "average" => {averageColor(imagePath)}
        "copy" => {copy(imagePath)}
        "thumbnail" => {
            let size: u32 = value.parse().unwrap();
            createThumnbail(imagePath, size)}
        "blur" => {
            let v : f32 = value.parse().unwrap();
            gaussianBlur(imagePath,v)}
        "brighten" => {
            let v: i32 = value.parse().unwrap();
            brighten(imagePath,v)}
        "huerotate" => {
            let v: i32 = value.parse().unwrap();
            huerotate(imagePath,v)}
        "contrast" => {
            let v: f32 = value.parse().unwrap();
            contrast(imagePath,v);}
        "grayscale" => {
            grayscale(imagePath);
        }
        "invert" => {
            invert(imagePath);
        }
        _ => {println!("Not implemented yet!")}
    }
}

fn averageColor(i: &str){
    let img = image::open(i).expect("Opening image failed");
    let mut r: u32 = 0;
    let mut g: u32 = 0;
    let mut b: u32 = 0;
    let (width,height) = img.dimensions();
    for x in 0..(width){
        for y in 0..(height){
            let px = img.get_pixel(x,y);
            let rgb = px.to_rgb();
            r = (r as u32 + rgb.data[0] as u32)/2;
            g = (g as u32 + rgb.data[1] as u32)/2;
            b = (b as u32 + rgb.data[2] as u32)/2;
        }
    }
    println!("Average color is: RGB {} {} {}",r,g,b);
}

fn createThumnbail(i: &str, size: u32){
    let operation = "Thumbnail";
    let img = image::open(i).expect("Opening image failed");
    let thumbnail = img.resize(size,size, FilterType::Lanczos3);
    saveFile(&thumbnail, &i, &operation);

}

fn copy(i: &str){
    let operation = "Copy";
    let img = image::open(i).expect("Opening image failed");
    saveFile(&img, &i, &operation);
}

fn gaussianBlur(i: &str, v: f32){
    let operation = "GuassianBlur";
    let img = image::open(i).expect("Opening image failed");
    let blurred = img.blur(v);
    saveFile(&blurred, &i, &operation);
}

fn brighten(i: &str,v: i32){
    let operation = "Brighten";
    let img = image::open(i).expect("Opening image failed");
    let brightened = img.brighten(v);
    saveFile(&brightened, &i, &operation);
}

fn huerotate(i: &str, v: i32){
    let operation = "Huerotate";
    let img = image::open(i).expect("Opening image failed");
    let huerotated = img.huerotate(v);
    saveFile(&huerotated, &i, &operation);
}

fn contrast(i: &str, v: f32){
    let operation = "AdjustContrast";
    let img = image::open(i).expect("Opening image failed");
    let contrast = img.adjust_contrast(v);
    saveFile(&contrast, &i, &operation);
}

fn grayscale(i: &str){
    let operation = "Grayscale";
    let img = image::open(i).expect("Opening image failed");
    let grayscale = img.grayscale();
    saveFile(&grayscale, &i, &operation);
}

fn invert(i: &str){
    let operation = "Invert";
    let mut img = image::open(i).expect("Opening image failed");
    img.invert();
    saveFile(&img, &i, &operation);
}

fn saveFile(img: &DynamicImage, i: &str, operation: &str){
    let mut outputPath: String = i.chars().take(i.len()-4).collect();
    let ext: String = i.chars().skip(i.len()-3).take(3).collect();
    outputPath.push_str(operation);
    outputPath.push_str(".");
    outputPath.push_str(&ext);
    println!("Output path: {}", outputPath);
    let mut out = File::create(outputPath).unwrap();
    match ext.as_ref() {
        "jpg" | "JPG" => {img.save(&mut out, image::JPEG).expect("Saving image failed");}
        "png" | "PNG" => {img.save(&mut out, image::PNG).expect("Saving image failed");}
        "gif" | "GIF" => {img.save(&mut out, image::GIF).expect("Saving image failed");}
        "bmp" | "BMP" => {img.save(&mut out, image::BMP).expect("Saving image failed");}
        "ico" | "ICO" => {img.save(&mut out, image::ICO).expect("Saving image failed");}
        _ => {println!("Unsupported file format")}
    }
}

<|endoftext|>


<commit_before>#![feature(custom_test_frameworks)]
// Custom test runner, to avoid libtest being wrapped around compiletest which wraps libtest.
#![test_runner(test_runner)]

use std::path::PathBuf;
use std::env;

use compiletest_rs as compiletest;
use colored::*;

fn miri_path() -> PathBuf {
    if rustc_test_suite().is_some() {
        PathBuf::from(option_env!("MIRI_PATH").unwrap())
    } else {
        PathBuf::from(concat!("target/", env!("PROFILE"), "/miri"))
    }
}

fn rustc_test_suite() -> Option<PathBuf> {
    option_env!("RUSTC_TEST_SUITE").map(PathBuf::from)
}

fn rustc_lib_path() -> PathBuf {
    option_env!("RUSTC_LIB_PATH").unwrap().into()
}

fn run_tests(mode: &str, path: &str, target: &str, mut flags: Vec<String>) {
    let in_rustc_test_suite = rustc_test_suite().is_some();
    // Add some flags we always want.
    if !in_rustc_test_suite {
      // Only `-Dwarnings` on the Miri side to make the rustc toolstate management less painful.
      // (We often get warnings when e.g. a feature gets stabilized or some lint gets added/improved.)
      flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs
    }
    flags.push("--edition 2018".to_owned());
    if let Ok(sysroot) = std::env::var("MIRI_SYSROOT") {
        flags.push(format!("--sysroot {}", sysroot));
    }

    // The rest of the configuration.
    let mut config = compiletest::Config::default().tempdir();
    config.mode = mode.parse().expect("Invalid mode");
    config.rustc_path = miri_path();
    if in_rustc_test_suite {
        config.run_lib_path = rustc_lib_path();
        config.compile_lib_path = rustc_lib_path();
    }
    config.filter = env::args().nth(1);
    config.host = get_host();
    config.src_base = PathBuf::from(path);
    config.target = target.to_owned();
    config.target_rustcflags = Some(flags.join(" "));
    compiletest::run_tests(&config);
}

fn compile_fail(path: &str, target: &str, opt: bool) {
    let opt_str = if opt { " with optimizations" } else { "" };
    eprintln!("{}", format!(
        "## Running compile-fail tests in {} against miri for target {}{}",
        path,
        target,
        opt_str
    ).green().bold());

    let mut flags = Vec::new();
    if opt {
        // Optimizing too aggressivley makes UB detection harder, but test at least
        // the default value.
        // FIXME: Opt level 3 ICEs during stack trace generation.
        flags.push("-Zmir-opt-level=1".to_owned());
    }

    run_tests("compile-fail", path, target, flags);
}

fn miri_pass(path: &str, target: &str, opt: bool) {
    let opt_str = if opt { " with optimizations" } else { "" };
    eprintln!("{}", format!(
        "## Running run-pass tests in {} against miri for target {}{}",
        path,
        target,
        opt_str
    ).green().bold());

    let mut flags = Vec::new();
    if opt {
        flags.push("-Zmir-opt-level=3".to_owned());
    }

    run_tests("ui", path, target, flags);
}

fn get_host() -> String {
    let rustc = rustc_test_suite().unwrap_or(PathBuf::from("rustc"));
    let rustc_version = std::process::Command::new(rustc)
        .arg("-vV")
        .output()
        .expect("rustc not found for -vV")
        .stdout;
    let rustc_version = std::str::from_utf8(&rustc_version).expect("rustc -vV is not utf8");
    let version_meta = rustc_version::version_meta_for(&rustc_version)
        .expect("failed to parse rustc version info");
    version_meta.host
}

fn get_target() -> String {
    std::env::var("MIRI_TEST_TARGET").unwrap_or_else(|_| get_host())
}

fn run_pass_miri(opt: bool) {
    miri_pass("tests/run-pass", &get_target(), opt);
}

fn compile_fail_miri(opt: bool) {
    compile_fail("tests/compile-fail", &get_target(), opt);
    if rustc_test_suite().is_none() {
        // FIXME: Some tests disabled in rustc test suite because
        // they run with a debug-assertion libstd which changes the errors.
        // We should build our own libstd for testing, see
        // <https://github.com/rust-lang/rust/issues/61833>.
        compile_fail("tests/compile-fail-norustc", &get_target(), opt);
    }
}

fn test_runner(_tests: &[&()]) {
    run_pass_miri(false);
    run_pass_miri(true);

    compile_fail_miri(false);
    compile_fail_miri(true);
}
<commit_msg>reorder for clarity<commit_after>#![feature(custom_test_frameworks)]
// Custom test runner, to avoid libtest being wrapped around compiletest which wraps libtest.
#![test_runner(test_runner)]

use std::path::PathBuf;
use std::env;

use compiletest_rs as compiletest;
use colored::*;

fn miri_path() -> PathBuf {
    if rustc_test_suite().is_some() {
        PathBuf::from(option_env!("MIRI_PATH").unwrap())
    } else {
        PathBuf::from(concat!("target/", env!("PROFILE"), "/miri"))
    }
}

fn rustc_test_suite() -> Option<PathBuf> {
    option_env!("RUSTC_TEST_SUITE").map(PathBuf::from)
}

fn rustc_lib_path() -> PathBuf {
    option_env!("RUSTC_LIB_PATH").unwrap().into()
}

fn run_tests(mode: &str, path: &str, target: &str, mut flags: Vec<String>) {
    let in_rustc_test_suite = rustc_test_suite().is_some();
    // Add some flags we always want.
    flags.push("--edition 2018".to_owned());
    if !in_rustc_test_suite {
      // Only `-Dwarnings` on the Miri side to make the rustc toolstate management less painful.
      // (We often get warnings when e.g. a feature gets stabilized or some lint gets added/improved.)
      flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs
    }
    if let Ok(sysroot) = std::env::var("MIRI_SYSROOT") {
        flags.push(format!("--sysroot {}", sysroot));
    }

    // The rest of the configuration.
    let mut config = compiletest::Config::default().tempdir();
    config.mode = mode.parse().expect("Invalid mode");
    config.rustc_path = miri_path();
    if in_rustc_test_suite {
        config.run_lib_path = rustc_lib_path();
        config.compile_lib_path = rustc_lib_path();
    }
    config.filter = env::args().nth(1);
    config.host = get_host();
    config.src_base = PathBuf::from(path);
    config.target = target.to_owned();
    config.target_rustcflags = Some(flags.join(" "));
    compiletest::run_tests(&config);
}

fn compile_fail(path: &str, target: &str, opt: bool) {
    let opt_str = if opt { " with optimizations" } else { "" };
    eprintln!("{}", format!(
        "## Running compile-fail tests in {} against miri for target {}{}",
        path,
        target,
        opt_str
    ).green().bold());

    let mut flags = Vec::new();
    if opt {
        // Optimizing too aggressivley makes UB detection harder, but test at least
        // the default value.
        // FIXME: Opt level 3 ICEs during stack trace generation.
        flags.push("-Zmir-opt-level=1".to_owned());
    }

    run_tests("compile-fail", path, target, flags);
}

fn miri_pass(path: &str, target: &str, opt: bool) {
    let opt_str = if opt { " with optimizations" } else { "" };
    eprintln!("{}", format!(
        "## Running run-pass tests in {} against miri for target {}{}",
        path,
        target,
        opt_str
    ).green().bold());

    let mut flags = Vec::new();
    if opt {
        flags.push("-Zmir-opt-level=3".to_owned());
    }

    run_tests("ui", path, target, flags);
}

fn get_host() -> String {
    let rustc = rustc_test_suite().unwrap_or(PathBuf::from("rustc"));
    let rustc_version = std::process::Command::new(rustc)
        .arg("-vV")
        .output()
        .expect("rustc not found for -vV")
        .stdout;
    let rustc_version = std::str::from_utf8(&rustc_version).expect("rustc -vV is not utf8");
    let version_meta = rustc_version::version_meta_for(&rustc_version)
        .expect("failed to parse rustc version info");
    version_meta.host
}

fn get_target() -> String {
    std::env::var("MIRI_TEST_TARGET").unwrap_or_else(|_| get_host())
}

fn run_pass_miri(opt: bool) {
    miri_pass("tests/run-pass", &get_target(), opt);
}

fn compile_fail_miri(opt: bool) {
    compile_fail("tests/compile-fail", &get_target(), opt);
    if rustc_test_suite().is_none() {
        // FIXME: Some tests disabled in rustc test suite because
        // they run with a debug-assertion libstd which changes the errors.
        // We should build our own libstd for testing, see
        // <https://github.com/rust-lang/rust/issues/61833>.
        compile_fail("tests/compile-fail-norustc", &get_target(), opt);
    }
}

fn test_runner(_tests: &[&()]) {
    run_pass_miri(false);
    run_pass_miri(true);

    compile_fail_miri(false);
    compile_fail_miri(true);
}
<|endoftext|>


<commit_before>#![cfg(feature = "integration")]

use std::env;
use std::process::Command;

#[cfg_attr(feature = "integration", test)]
fn integration_test() {
    let repo_name = env::var("INTEGRATION").expect("`INTEGRATION` var not set");
    let repo_url = format!("https://github.com/{}", repo_name);
    let crate_name = repo_name
        .split('/')
        .nth(1)
        .expect("repo name should have format `<org>/<name>`");

    let repo_dir = tempfile::tempdir()
        .expect("couldn't create temp dir")
        .path()
        .join(crate_name);

    let st = Command::new("git")
        .args(&["clone", "--depth=1", &repo_url, repo_dir.to_str().unwrap()])
        .status()
        .expect("unable to run git");
    assert!(st.success());

    let root_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
    let target_dir = std::path::Path::new(&root_dir).join("target");
    let clippy_binary = target_dir.join(env!("PROFILE")).join("cargo-clippy");

    let output = Command::new(clippy_binary)
        .current_dir(repo_dir)
        .env("RUST_BACKTRACE", "full")
        .env("CARGO_TARGET_DIR", target_dir)
        .args(&[
            "clippy",
            "--all-targets",
            "--all-features",
            "--",
            "--cap-lints",
            "warn",
            "-Wclippy::pedantic",
            "-Wclippy::nursery",
        ])
        .output()
        .expect("unable to run clippy");

    let stderr = String::from_utf8_lossy(&output.stderr);
    if stderr.contains("internal compiler error") {
        let backtrace_start = stderr
            .find("thread 'rustc' panicked at")
            .expect("start of backtrace not found");
        let backtrace_end = stderr
            .rfind("error: internal compiler error")
            .expect("end of backtrace not found");

        panic!(
            "internal compiler error\nBacktrace:\n\n{}",
            &stderr[backtrace_start..backtrace_end]
        );
    } else if stderr.contains("query stack during panic") {
        panic!("query stack during panic in the output");
    } else if stderr.contains("E0463") {
        panic!("error: E0463");
    } else if stderr.contains("E0514") {
        panic!("incompatible crate versions");
    } else if stderr.contains("failed to run `rustc` to learn about target-specific information") {
        panic!("couldn't find librustc_driver, consider setting `LD_LIBRARY_PATH`");
    }

    match output.status.code() {
        Some(0) => println!("Compilation successful"),
        Some(code) => eprintln!("Compilation failed. Exit code: {}", code),
        None => panic!("Process terminated by signal"),
    }
}
<commit_msg>Use `into_path`<commit_after>#![cfg(feature = "integration")]

use std::env;
use std::process::Command;

#[cfg_attr(feature = "integration", test)]
fn integration_test() {
    let repo_name = env::var("INTEGRATION").expect("`INTEGRATION` var not set");
    let repo_url = format!("https://github.com/{}", repo_name);
    let crate_name = repo_name
        .split('/')
        .nth(1)
        .expect("repo name should have format `<org>/<name>`");

    let mut repo_dir = tempfile::tempdir().expect("couldn't create temp dir").into_path();
    repo_dir.push(crate_name);

    let st = Command::new("git")
        .args(&["clone", "--depth=1", &repo_url, repo_dir.to_str().unwrap()])
        .status()
        .expect("unable to run git");
    assert!(st.success());

    let root_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
    let target_dir = std::path::Path::new(&root_dir).join("target");
    let clippy_binary = target_dir.join(env!("PROFILE")).join("cargo-clippy");

    let output = Command::new(clippy_binary)
        .current_dir(repo_dir)
        .env("RUST_BACKTRACE", "full")
        .env("CARGO_TARGET_DIR", target_dir)
        .args(&[
            "clippy",
            "--all-targets",
            "--all-features",
            "--",
            "--cap-lints",
            "warn",
            "-Wclippy::pedantic",
            "-Wclippy::nursery",
        ])
        .output()
        .expect("unable to run clippy");

    let stderr = String::from_utf8_lossy(&output.stderr);
    if stderr.contains("internal compiler error") {
        let backtrace_start = stderr
            .find("thread 'rustc' panicked at")
            .expect("start of backtrace not found");
        let backtrace_end = stderr
            .rfind("error: internal compiler error")
            .expect("end of backtrace not found");

        panic!(
            "internal compiler error\nBacktrace:\n\n{}",
            &stderr[backtrace_start..backtrace_end]
        );
    } else if stderr.contains("query stack during panic") {
        panic!("query stack during panic in the output");
    } else if stderr.contains("E0463") {
        panic!("error: E0463");
    } else if stderr.contains("E0514") {
        panic!("incompatible crate versions");
    } else if stderr.contains("failed to run `rustc` to learn about target-specific information") {
        panic!("couldn't find librustc_driver, consider setting `LD_LIBRARY_PATH`");
    }

    match output.status.code() {
        Some(0) => println!("Compilation successful"),
        Some(code) => eprintln!("Compilation failed. Exit code: {}", code),
        None => panic!("Process terminated by signal"),
    }
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate regex;

include!("../clap-test.rs");

use clap::{App, Arg, SubCommand, ErrorKind};

static VISIBLE_ALIAS_HELP: &'static str = "clap-test 2.6

USAGE:
    clap-test [FLAGS] [SUBCOMMAND]

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

SUBCOMMANDS:
    help      Prints this message or the help of the given subcommand(s)
    vim|vi    Some help";

#[test]
fn subcommand() {
    let m = App::new("test")
        .subcommand(SubCommand::with_name("some")
            .arg(Arg::with_name("test")
                .short("t")
                .long("test")
                .takes_value(true)
                .help("testing testing")))
        .arg(Arg::with_name("other").long("other"))
        .get_matches_from(vec!["myprog", "some", "--test", "testing"]);

    assert_eq!(m.subcommand_name().unwrap(), "some");
    let sub_m = m.subcommand_matches("some").unwrap();
    assert!(sub_m.is_present("test"));
    assert_eq!(sub_m.value_of("test").unwrap(), "testing");
}

#[test]
fn subcommand_none_given() {
    let m = App::new("test")
        .subcommand(SubCommand::with_name("some")
            .arg(Arg::with_name("test")
                .short("t")
                .long("test")
                .takes_value(true)
                .help("testing testing")))
        .arg(Arg::with_name("other").long("other"))
        .get_matches_from(vec![""]);

    assert!(m.subcommand_name().is_none());
}

#[test]
fn subcommand_multiple() {
    let m = App::new("test")
        .subcommands(vec![
            SubCommand::with_name("some")
                .arg(Arg::with_name("test")
                    .short("t")
                    .long("test")
                    .takes_value(true)
                    .help("testing testing")),
            SubCommand::with_name("add")
                .arg(Arg::with_name("roster").short("r"))
        ])
        .arg(Arg::with_name("other").long("other"))
        .get_matches_from(vec!["myprog", "some", "--test", "testing"]);

    assert!(m.subcommand_matches("some").is_some());
    assert!(m.subcommand_matches("add").is_none());
    assert_eq!(m.subcommand_name().unwrap(), "some");
    let sub_m = m.subcommand_matches("some").unwrap();
    assert!(sub_m.is_present("test"));
    assert_eq!(sub_m.value_of("test").unwrap(), "testing");
}

#[test]
fn single_alias() {
    let m = App::new("myprog")
                .subcommand(SubCommand::with_name("test")
                    .alias("do-stuff"))
                .get_matches_from(vec!["myprog", "do-stuff"]);
    assert_eq!(m.subcommand_name(), Some("test"));
}

#[test]
fn multiple_aliases() {
    let m = App::new("myprog")
                .subcommand(SubCommand::with_name("test")
                    .aliases(&["do-stuff", "test-stuff"]))
                .get_matches_from(vec!["myprog", "test-stuff"]);
    assert_eq!(m.subcommand_name(), Some("test"));
}

#[test]
fn subcmd_did_you_mean_output() {
    test::check_err_output(test::complex_app(), "clap-test subcm",
"error: The subcommand 'subcm' wasn't recognized
\tDid you mean 'subcmd' ?

If you believe you received this message in error, try re-running with 'clap-test -- subcm'

USAGE:
    clap-test [FLAGS] [OPTIONS] [ARGS] [SUBCOMMAND]

For more information try --help", true);
}

#[test]
fn alias_help() {
    let m = App::new("myprog")
                .subcommand(SubCommand::with_name("test")
                    .alias("do-stuff"))
                .get_matches_from_safe(vec!["myprog", "help", "do-stuff"]);
    assert!(m.is_err());
    assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
}

#[test]
fn visible_aliases_help_output() {
    let app = App::new("clap-test")
        .version("2.6")
        .subcommand(SubCommand::with_name("vim")
            .about("Some help")
            .alias("invisible")
            .visible_alias("vi"));
    test::check_help(app, VISIBLE_ALIAS_HELP);
}
<commit_msg>tests(Aliases): adds tests for alias help output<commit_after>extern crate clap;
extern crate regex;

include!("../clap-test.rs");

use clap::{App, Arg, SubCommand, ErrorKind};

static VISIBLE_ALIAS_HELP: &'static str = "clap-test 2.6

USAGE:
    clap-test [FLAGS] [SUBCOMMAND]

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

SUBCOMMANDS:
    help    Prints this message or the help of the given subcommand(s)
    test    Some help [aliases: dongle, done]";

static INVISIBLE_ALIAS_HELP: &'static str = "clap-test 2.6

USAGE:
    clap-test [FLAGS] [SUBCOMMAND]

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

SUBCOMMANDS:
    help    Prints this message or the help of the given subcommand(s)
    test    Some help";

#[test]
fn subcommand() {
    let m = App::new("test")
        .subcommand(SubCommand::with_name("some")
            .arg(Arg::with_name("test")
                .short("t")
                .long("test")
                .takes_value(true)
                .help("testing testing")))
        .arg(Arg::with_name("other").long("other"))
        .get_matches_from(vec!["myprog", "some", "--test", "testing"]);

    assert_eq!(m.subcommand_name().unwrap(), "some");
    let sub_m = m.subcommand_matches("some").unwrap();
    assert!(sub_m.is_present("test"));
    assert_eq!(sub_m.value_of("test").unwrap(), "testing");
}

#[test]
fn subcommand_none_given() {
    let m = App::new("test")
        .subcommand(SubCommand::with_name("some")
            .arg(Arg::with_name("test")
                .short("t")
                .long("test")
                .takes_value(true)
                .help("testing testing")))
        .arg(Arg::with_name("other").long("other"))
        .get_matches_from(vec![""]);

    assert!(m.subcommand_name().is_none());
}

#[test]
fn subcommand_multiple() {
    let m = App::new("test")
        .subcommands(vec![
            SubCommand::with_name("some")
                .arg(Arg::with_name("test")
                    .short("t")
                    .long("test")
                    .takes_value(true)
                    .help("testing testing")),
            SubCommand::with_name("add")
                .arg(Arg::with_name("roster").short("r"))
        ])
        .arg(Arg::with_name("other").long("other"))
        .get_matches_from(vec!["myprog", "some", "--test", "testing"]);

    assert!(m.subcommand_matches("some").is_some());
    assert!(m.subcommand_matches("add").is_none());
    assert_eq!(m.subcommand_name().unwrap(), "some");
    let sub_m = m.subcommand_matches("some").unwrap();
    assert!(sub_m.is_present("test"));
    assert_eq!(sub_m.value_of("test").unwrap(), "testing");
}

#[test]
fn single_alias() {
    let m = App::new("myprog")
                .subcommand(SubCommand::with_name("test")
                    .alias("do-stuff"))
                .get_matches_from(vec!["myprog", "do-stuff"]);
    assert_eq!(m.subcommand_name(), Some("test"));
}

#[test]
fn multiple_aliases() {
    let m = App::new("myprog")
                .subcommand(SubCommand::with_name("test")
                    .aliases(&["do-stuff", "test-stuff"]))
                .get_matches_from(vec!["myprog", "test-stuff"]);
    assert_eq!(m.subcommand_name(), Some("test"));
}

#[test]
fn subcmd_did_you_mean_output() {
    test::check_err_output(test::complex_app(), "clap-test subcm",
"error: The subcommand 'subcm' wasn't recognized
\tDid you mean 'subcmd' ?

If you believe you received this message in error, try re-running with 'clap-test -- subcm'

USAGE:
    clap-test [FLAGS] [OPTIONS] [ARGS] [SUBCOMMAND]

For more information try --help", true);
}

#[test]
fn alias_help() {
    let m = App::new("myprog")
                .subcommand(SubCommand::with_name("test")
                    .alias("do-stuff"))
                .get_matches_from_safe(vec!["myprog", "help", "do-stuff"]);
    assert!(m.is_err());
    assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
}

#[test]
fn visible_aliases_help_output() {
    let app = App::new("clap-test")
        .version("2.6")
        .subcommand(SubCommand::with_name("test")
            .about("Some help")
            .alias("invisible")
            .visible_alias("dongle")
            .visible_alias("done"));
    test::check_help(app, VISIBLE_ALIAS_HELP);
}

#[test]
fn invisible_aliases_help_output() {
    let app = App::new("clap-test")
        .version("2.6")
        .subcommand(SubCommand::with_name("test")
            .about("Some help")
            .alias("invisible"));
    test::check_help(app, INVISIBLE_ALIAS_HELP);
}<|endoftext|>


<commit_before>/*!
Test supports module.

*/
use glutin;
use glium::{mod, DisplayBuild};

use std::os;

/// Builds a headless display for tests.
pub fn build_display() -> glium::Display {
    if os::getenv("HEADLESS_TESTS").is_some() {
        glutin::HeadlessRendererBuilder::new(1024, 768).build_glium().unwrap()
    } else {
        glutin::WindowBuilder::new().build_glium().unwrap()
    }
}
<commit_msg>Tests no longer show windows<commit_after>/*!
Test supports module.

*/
use glutin;
use glium::{mod, DisplayBuild};

use std::os;

/// Builds a headless display for tests.
pub fn build_display() -> glium::Display {
    if os::getenv("HEADLESS_TESTS").is_some() {
        glutin::HeadlessRendererBuilder::new(1024, 768).build_glium().unwrap()
    } else {
        glutin::WindowBuilder::new().with_visibility(false).build_glium().unwrap()
    }
}
<|endoftext|>


<commit_before>extern crate redis;

use std::collections::HashMap;

/// This function demonstrates how a return value can be coerced into a
/// hashmap of tuples.  This is particularly useful for responses like
/// CONFIG GET or all most H functions which will return responses in
/// such list of implied tuples.
fn do_print_max_entry_limits(con: &redis::Connection) -> redis::RedisResult<()> {
    // since rust cannot know what format we actually want we need to be
    // explicit here and define the type of our response.  In this case
    // String -> int fits all the items we query for.
    let config : HashMap<String, int> = try!(
        redis::cmd("CONFIG").arg("GET").arg("*-max-*-entries").query(con));

    println!("Max entry limits:");

    // because our HashSet stores keys as actual strings we cannot use
    // the find method because of a type mismatch (it takes strings and
    // not slices).  We can however avoid the allocation we can use the
    // find_equiv method.
    println!("  max-intset:        {}", config.find_equiv(
        &"set-max-intset-entries").unwrap_or(&0));
    println!("  hash-max-ziplist:  {}", config.find_equiv
        (&"hash-max-ziplist-entries").unwrap_or(&0));
    println!("  list-max-ziplist:  {}", config.find_equiv(
        &"list-max-ziplist-entries").unwrap_or(&0));
    println!("  zset-max-ziplist:  {}", config.find_equiv(
        &"zset-max-ziplist-entries").unwrap_or(&0));

    Ok(())
}

/// This is a pretty stupid example that demonstrates how to create a large
/// set through a pipeline and how to iterate over it through implied
/// cursors.
fn do_show_scanning(con: &redis::Connection) -> redis::RedisResult<()> {
    // This makes a large pipeline of commands.  Because the pipeline is
    // modified in place we can just ignore the return value upon the end
    // of each iteration.
    let mut pipe = redis::pipe();
    for num in range(0, 1000u) {
        pipe.cmd("SADD").arg("my_set").arg(num).ignore();
    }

    // since we don't care about the return value of the pipeline we can
    // just cast it into the unit type.
    let _ : () = try!(pipe.query(con));

    // since rust currently does not track temporaries for us, we need to
    // store it in a local variable.
    let mut cmd = redis::cmd("SSCAN");
    cmd.arg("my_set").cursor_arg(0);

    // as a simple exercise we just sum up the iterator.  Since the fold
    // method carries an initial value we do not need to define the
    // type of the iterator, rust will figure "int" out for us.
    let sum = try!(cmd.iter(con)).fold(0i, |a, b| a + b);

    println!("The sum of all numbers in the set 0-1000: {}", sum);

    Ok(())
}

/// Demonstrates how to do an atomic increment in a very low level way.
fn do_atomic_increment_lowlevel(con: &redis::Connection) -> redis::RedisResult<()> {
    let key = "the_key";
    println!("Run low-level atomic increment:");

    // set the initial value so we have something to test with.
    let _ : () = try!(redis::cmd("SET").arg(key).arg(42i).query(con));

    loop {
        // we need to start watching the key we care about, so that our
        // exec fails if the key changes.
        let _ : () = try!(redis::cmd("WATCH").arg(key).query(con));

        // load the old value, so we know what to increment.
        let val : int = try!(redis::cmd("GET").arg(key).query(con));

        // at this point we can go into an atomic pipe (a multi block)
        // and set up the keys.
        let response : Option<(int,)> = try!(redis::pipe()
            .atomic()
            .cmd("SET").arg(key).arg(val + 1).ignore()
            .cmd("GET").arg(key)
            .query(con));

        match response {
            None => { continue; }
            Some(response) => {
                let (new_val,) = response;
                println!("  New value: {}", new_val);
                break;
            }
        }
    }

    Ok(())
}

/// Demonstrates how to do an atomic increment with transaction support.
fn do_atomic_increment(con: &redis::Connection) -> redis::RedisResult<()> {
    let key = "the_key";
    println!("Run high-level atomic increment:");

    // set the initial value so we have something to test with.
    let _ : () = try!(redis::cmd("SET").arg(key).arg(42i).query(con));

    // run the transaction block.
    let (new_val,) : (int,) = con.transaction([key][], |pipe| {
        // load the old value, so we know what to increment.
        let val : int = try!(redis::cmd("GET").arg(key).query(con));
        // increment
        pipe
            .cmd("SET").arg(key).arg(val + 1).ignore()
            .cmd("GET").arg(key).query(con)
    }).unwrap();

    // and print the result
    println!("New value: {}", new_val);

    Ok(())
}

/// Runs all the examples and propagates errors up.
fn do_redis_code() -> redis::RedisResult<()>
{
    // general connection handling
    let client = try!(redis::Client::open("redis://127.0.0.1/"));
    let con = try!(client.get_connection());

    // read some config and print it.
    try!(do_print_max_entry_limits(&con));

    // demonstrate how scanning works.
    try!(do_show_scanning(&con));

    // shows an atomic increment.
    try!(do_atomic_increment_lowlevel(&con));
    try!(do_atomic_increment(&con));

    Ok(())
}

fn main()
{
    // at this point the errors are fatal, let's just fail hard.
    do_redis_code().unwrap();
}
<commit_msg>Fixed example.<commit_after>extern crate redis;
use redis::{Commands, PipelineCommands, transaction};

use std::collections::HashMap;

/// This function demonstrates how a return value can be coerced into a
/// hashmap of tuples.  This is particularly useful for responses like
/// CONFIG GET or all most H functions which will return responses in
/// such list of implied tuples.
fn do_print_max_entry_limits(con: &redis::Connection) -> redis::RedisResult<()> {
    // since rust cannot know what format we actually want we need to be
    // explicit here and define the type of our response.  In this case
    // String -> int fits all the items we query for.
    let config : HashMap<String, int> = try!(
        redis::cmd("CONFIG").arg("GET").arg("*-max-*-entries").query(con));

    println!("Max entry limits:");

    // because our HashSet stores keys as actual strings we cannot use
    // the find method because of a type mismatch (it takes strings and
    // not slices).  We can however avoid the allocation we can use the
    // find_equiv method.
    println!("  max-intset:        {}", config.find_equiv(
        &"set-max-intset-entries").unwrap_or(&0));
    println!("  hash-max-ziplist:  {}", config.find_equiv
        (&"hash-max-ziplist-entries").unwrap_or(&0));
    println!("  list-max-ziplist:  {}", config.find_equiv(
        &"list-max-ziplist-entries").unwrap_or(&0));
    println!("  zset-max-ziplist:  {}", config.find_equiv(
        &"zset-max-ziplist-entries").unwrap_or(&0));

    Ok(())
}

/// This is a pretty stupid example that demonstrates how to create a large
/// set through a pipeline and how to iterate over it through implied
/// cursors.
fn do_show_scanning(con: &redis::Connection) -> redis::RedisResult<()> {
    // This makes a large pipeline of commands.  Because the pipeline is
    // modified in place we can just ignore the return value upon the end
    // of each iteration.
    let mut pipe = redis::pipe();
    for num in range(0, 1000u) {
        pipe.cmd("SADD").arg("my_set").arg(num).ignore();
    }

    // since we don't care about the return value of the pipeline we can
    // just cast it into the unit type.
    let _ : () = try!(pipe.query(con));

    // since rust currently does not track temporaries for us, we need to
    // store it in a local variable.
    let mut cmd = redis::cmd("SSCAN");
    cmd.arg("my_set").cursor_arg(0);

    // as a simple exercise we just sum up the iterator.  Since the fold
    // method carries an initial value we do not need to define the
    // type of the iterator, rust will figure "int" out for us.
    let sum = try!(cmd.iter(con)).fold(0i, |a, b| a + b);

    println!("The sum of all numbers in the set 0-1000: {}", sum);

    Ok(())
}

/// Demonstrates how to do an atomic increment in a very low level way.
fn do_atomic_increment_lowlevel(con: &redis::Connection) -> redis::RedisResult<()> {
    let key = "the_key";
    println!("Run low-level atomic increment:");

    // set the initial value so we have something to test with.
    let _ : () = try!(redis::cmd("SET").arg(key).arg(42i).query(con));

    loop {
        // we need to start watching the key we care about, so that our
        // exec fails if the key changes.
        let _ : () = try!(redis::cmd("WATCH").arg(key).query(con));

        // load the old value, so we know what to increment.
        let val : int = try!(redis::cmd("GET").arg(key).query(con));

        // at this point we can go into an atomic pipe (a multi block)
        // and set up the keys.
        let response : Option<(int,)> = try!(redis::pipe()
            .atomic()
            .cmd("SET").arg(key).arg(val + 1).ignore()
            .cmd("GET").arg(key)
            .query(con));

        match response {
            None => { continue; }
            Some(response) => {
                let (new_val,) = response;
                println!("  New value: {}", new_val);
                break;
            }
        }
    }

    Ok(())
}

/// Demonstrates how to do an atomic increment with transaction support.
fn do_atomic_increment(con: &redis::Connection) -> redis::RedisResult<()> {
    let key = "the_key";
    println!("Run high-level atomic increment:");

    // set the initial value so we have something to test with.
    let _ : () = try!(con.set(key, 42i));

    // run the transaction block.
    let (new_val,) : (int,) = transaction(con, [key].as_slice(), |pipe| {
        // load the old value, so we know what to increment.
        let val : int = try!(con.get(key));
        // increment
        pipe
            .set(key, val + 1).ignore()
            .get(key).query(con)
    }).unwrap();

    // and print the result
    println!("New value: {}", new_val);

    Ok(())
}

/// Runs all the examples and propagates errors up.
fn do_redis_code() -> redis::RedisResult<()>
{
    // general connection handling
    let client = try!(redis::Client::open("redis://127.0.0.1/"));
    let con = try!(client.get_connection());

    // read some config and print it.
    try!(do_print_max_entry_limits(&con));

    // demonstrate how scanning works.
    try!(do_show_scanning(&con));

    // shows an atomic increment.
    try!(do_atomic_increment_lowlevel(&con));
    try!(do_atomic_increment(&con));

    Ok(())
}

fn main()
{
    // at this point the errors are fatal, let's just fail hard.
    do_redis_code().unwrap();
}
<|endoftext|>


<commit_before>//! A hangman game to guess the hidden word.

use turtle::{Drawing, Point, Speed, Turtle};

// To run this example, use the command: cargo run --features unstable --example flower
#[cfg(all(not(feature = "unstable")))]
compile_error!("This example relies on unstable features. Run with `--features unstable`");

fn main() {
    let mut drawing = Drawing::new();
    let mut hangman = drawing.add_turtle();
    let mut lines = drawing.add_turtle();

    let secret = "trainstation";

    hangman.hide();
    hangman.set_speed(Speed::instant());
    hangman.set_pen_size(10.0);
    hangman.pen_up();
    hangman.go_to(Point { x: -300.0, y: -300.0 });
    hangman.pen_down();

    let list = &[hill, mast, bar, support, rope, head, arms, body, legs];

    for step in list.iter() {
        step(&mut hangman);
    }

    lines.hide();
    lines.set_speed(Speed::instant());
    lines.right(90.0);
    lines.pen_up();
    lines.go_to(Point{x:-300.0, y:200.0});
    lines.pen_down();

    for _letter in secret.chars(){
        lines.forward(20.0);
        lines.pen_up();
        lines.forward(20.0);
        lines.pen_down();
    }
}

fn hill(hangman: &mut Turtle) {
    hangman.arc_right(100.0, 180.0);
    hangman.left(180.0);
    hangman.arc_left(100.0, 90.0);
    hangman.right(90.0);
}

fn mast(hangman: &mut Turtle) {
    hangman.forward(300.0);
    //turtle.
}

fn bar(hangman: &mut Turtle) {
    hangman.right(90.0);
    hangman.forward(150.0);
}

fn support(hangman: &mut Turtle) {
    hangman.backward(100.0);
    hangman.right(135.0);
    hangman.forward(70.710678119);
    hangman.backward(70.710678119);
    hangman.left(135.0);
    hangman.forward(100.0);
}

fn rope(hangman: &mut Turtle) {
    hangman.set_pen_size(3.0);
    hangman.right(90.0);
    hangman.forward(70.0);
}

fn head(hangman: &mut Turtle) {
    hangman.left(90.0);
    hangman.arc_right(30.0, 540.0);
}

fn arms(hangman: &mut Turtle){
    hangman.left(60.0);
    hangman.forward(100.0);
    hangman.backward(100.0);
    hangman.left(60.0);
    hangman.forward(100.0);
    hangman.backward(100.0);
    hangman.right(30.0);
}

fn body(hangman: &mut Turtle){
    hangman.forward(100.0);
}

fn legs(hangman: &mut Turtle){
    hangman.right(20.0);
    hangman.forward(120.0);
    hangman.backward(120.0);
    hangman.left(40.0);
    hangman.forward(120.0);
    hangman.backward(120.0);
    hangman.right(20.0);
}
<commit_msg>Implement the missing fuctionality:<commit_after>//! A hangman game to guess the hidden word.
// To run this example, use the command: cargo run --features unstable --example flower
#[cfg(all(not(feature = "unstable")))]
compile_error!("This example relies on unstable features. Run with `--features unstable`");

use std::io::{Error, Write};

use graphic::HangmanDesign;
use turtle::{rand::RandomSlice, Drawing, Point, Speed, Turtle};

// A small word list to choose from
const WORDS: &[&str; 28] = &[
    "poetry",
    "formal",
    "type",
    "expresses",
    "personal",
    "emotions",
    "feelings",
    "typically",
    "spoken",
    "equivalent",
    "lyrics",
    "term",
    "derives",
    "literature",
    "defined",
    "musical",
    "accompaniment",
    "usually",
    "stringed",
    "instrument",
    "term",
    "importance",
    "literary",
    "theory",
    "division",
    "developed",
    "between",
    "categories",
];

fn main() {
    let mut drawing = Drawing::new();

    // the turtle that is responsible for drawing the hangman design
    let mut hangman = drawing.add_turtle();

    // the turtle that is responsible for drawing the lines on which the letters appear.
    let mut lines = drawing.add_turtle();

    // the turtle that is responsible for drawing the Won or lost smiley.
    let mut wl = drawing.add_turtle();
    wl.hide();

    // the secret word that is to be guessed
    let secret = *WORDS.choose().unwrap();

    // this list stores all the steps of the hangman so that they can be drawn from a for loop or an index.
    let hangman_design = HangmanDesign::default();
    graphic::setup(&mut hangman);

    let mut all_guesses = String::new();

    // Loop over each step basically there are two ways to do this either one loops over the steps or one loops over guesses. Both need two nested loops.
    // HangmanDesign has the [`Iterator`] trait implemented which is why we can loop it directly.
    // The `'won:` syntax is to be able to conviniently `break` from both nested loops.
    'won: for step in hangman_design {
        // for each step we only draw it after a wron guess. So the following loops guesses and only `break`s to the for loop on a wrong guess. If all characters have been guessed correctly then it `break`s both loops and continues with a won or lost smiley.
        loop {
            draw_lines(&mut lines, secret, &all_guesses);
            let mut new_guess = String::new();
            ask_for_letter(&mut new_guess).expect("Failed to read letter");
            if secret.contains(&new_guess) {
                println!("This was correct!");
                all_guesses += &new_guess;
                if secret.chars().all(|c| all_guesses.contains(c)) {
                    break 'won;
                }
            } else {
                println!("No that letter is not in the word");
                break;
            }
        }
        step(&mut hangman);
    }
    // Redraw the lines else they could be outdated.
    draw_lines(&mut lines, secret, &all_guesses);
    wl.set_speed(Speed::instant());
    // Draw a circle
    wl.arc_right(100.0, 360.0);
    // Draw the left eye
    teleport_relative(&mut wl, Point { x: 55.0, y: 40.0 });
    wl.arc_right(5.0, 360.0);
    // Draw the right eye
    teleport_relative(&mut wl, Point { x: 85.0, y: 0.0 });
    wl.arc_right(5.0, 360.0);
    // Go to the start of the mouth
    teleport_relative(&mut wl, Point { x: -85.0, y: -80.0 });
    wl.right(90.0);
    // Either draw it smiling or sad
    if secret.chars().all(|c| all_guesses.contains(c)) {
        println!("You Won!");
        wl.right(45.0);
        wl.arc_left(65.0, 90.0);
    } else {
        println!("You Lost!");
        wl.left(45.0);
        wl.arc_right(65.0, 90.0);
    }
}

/// A function to ask the user for a letter
fn ask_for_letter(guess: &mut String) -> Result<(), Error> {
    print!("Please guess a letter: ");
    std::io::stdout().flush()?;
    std::io::stdin().read_line(guess)?;

    // remove trailing newline characters
    let to_trim = guess.trim_end_matches(&['\r', '\n'][..]).len();
    guess.truncate(to_trim);

    println!("You guessed: {}", &guess);
    Ok(())
}

/// A function to conveniently teleport the turtle relative to its current position.
fn teleport_relative(turtle: &mut Turtle, direction: Point) {
    let cur = turtle.position();
    let new: Point = cur + direction;
    turtle.pen_up();
    turtle.go_to(new);
    turtle.pen_down();
}

/// Draw the lines one for each character. If the character has been guessed already correctly draw a green circle above the line.
fn draw_lines(lines: &mut Turtle, secret: &str, all_guesses: &str) {
    // hide the lines-turtle and go th the startigpoint of the lines.
    lines.reset();
    lines.hide();
    lines.set_speed(Speed::instant());
    lines.right(90.0);
    teleport_relative(lines, Point { x: -300.0, y: 200.0 });

    // draw a line for every character in the secret.
    for letter in secret.chars() {
        if all_guesses.contains(letter) {
            teleport_relative(lines, Point { x: 2.5, y: 10.0 });

            // as turtle is not yet able to draw text draw a green replacement circle.
            lines.left(90.0);
            lines.set_fill_color("green");
            lines.set_pen_color("green");
            lines.begin_fill();
            lines.arc_right(7.5, 360.0);
            lines.end_fill();
            lines.set_pen_color("black");
            lines.right(90.0);

            teleport_relative(lines, Point { x: -2.5, y: -10.0 });

            // print to the terminal
            print!(" {} ", letter);
        } else {
            print!(" _ ");
        }
        lines.forward(20.0);
        teleport_relative(lines, Point { x: 20.0, y: 0.0 });
    }
    println!(); // to switch to the next line and flush the output.
}

mod graphic {
    //! This module contains the drawing logic for the hangman graphic
    //!
    //! It is used by creating an instance of a [`HangmanDesign`] struct using [`HangmanDesign::default()`].
    //! Therein is contained a list of all the steps neccessary to draw the hangman in chronologic order.

    use turtle::{Point, Speed, Turtle};

    use crate::teleport_relative;

    pub struct HangmanDesign {
        state: usize,
        steps: &'static [fn(&mut turtle::Turtle); 9],
    }

    impl Default for HangmanDesign {
        fn default() -> Self {
            Self {
                state: 0,
                steps: &[hill, mast, bar, support, rope, head, arms, body, legs],
            }
        }
    }

    impl Iterator for HangmanDesign {
        type Item = &'static fn(&mut turtle::Turtle);

        fn next(&mut self) -> Option<Self::Item> {
            self.state += 1;
            self.steps.get(self.state - 1)
        }
    }

    pub fn setup(hangman: &mut Turtle) {
        // hide the hangman-turtle and go th the startigpoint of the graphic.
        hangman.hide();
        hangman.set_speed(Speed::instant());
        hangman.set_pen_size(10.0);
        teleport_relative(hangman, Point { x: -300.0, y: -300.0 });
    }

    fn hill(hangman: &mut Turtle) {
        // start drawing
        hangman.arc_right(100.0, 180.0);
        hangman.left(180.0);
        hangman.arc_left(100.0, 90.0);
        hangman.right(90.0);
    }

    fn mast(hangman: &mut Turtle) {
        hangman.forward(300.0);
    }

    fn bar(hangman: &mut Turtle) {
        hangman.right(90.0);
        hangman.forward(150.0);
    }

    fn support(hangman: &mut Turtle) {
        hangman.backward(100.0);
        hangman.right(135.0);
        hangman.forward(70.710678119);
        hangman.backward(70.710678119);
        hangman.left(135.0);
        hangman.forward(100.0);
    }

    fn rope(hangman: &mut Turtle) {
        hangman.set_pen_size(3.0);
        hangman.right(90.0);
        hangman.forward(70.0);
    }

    fn head(hangman: &mut Turtle) {
        hangman.left(90.0);
        hangman.arc_right(30.0, 540.0);
    }

    fn arms(hangman: &mut Turtle) {
        hangman.left(60.0);
        hangman.forward(100.0);
        hangman.backward(100.0);
        hangman.left(60.0);
        hangman.forward(100.0);
        hangman.backward(100.0);
        hangman.right(30.0);
    }

    fn body(hangman: &mut Turtle) {
        hangman.forward(100.0);
    }

    fn legs(hangman: &mut Turtle) {
        hangman.right(20.0);
        hangman.forward(120.0);
        hangman.backward(120.0);
        hangman.left(40.0);
        hangman.forward(120.0);
        hangman.backward(120.0);
        hangman.right(20.0);
    }
}
<|endoftext|>


<commit_before>extern crate calx;
extern crate content;
extern crate world;
extern crate render;

use calx::backend::{Key, Event, MouseButton};
use calx::{Kernel, V2, color};
use calx::backend::{WindowBuilder, Canvas, CanvasUtil, CanvasBuilder};
use content::TerrainType;
use content::Brush;
use world::{World, Location};
use world::query;
use render::{chart_to_screen, view_to_chart, cells_on_screen, render_terrain};
use render::{Angle, FLOOR_Z, BLOCK_Z};

fn draw_world(w: &World,
              ctx: &mut Canvas,
              center: Location,
              cursor_loc: Location) {
    for pt in cells_on_screen() {
        let screen_pos = chart_to_screen(pt);
        let loc = center + pt;

        let k = Kernel::new(|loc| query::terrain(w, loc), loc);
        render_terrain(&k, |img, angle, fore, back| {
            let z = match angle {
                Angle::Up => FLOOR_Z,
                _ => BLOCK_Z,
            };
            ctx.draw_image(img, screen_pos, z, fore, back)
        });
    }

    if let Some(pt) = center.v2_at(cursor_loc) {
        // Draw cursor
        let screen_pos = chart_to_screen(pt);
        ctx.draw_image(Brush::CursorBottom.get(0),
                       screen_pos,
                       FLOOR_Z,
                       color::RED,
                       color::BLACK);
        ctx.draw_image(Brush::CursorTop.get(0),
                       screen_pos,
                       BLOCK_Z,
                       color::RED,
                       color::BLACK);

    }
}

pub fn main() {
    let window = WindowBuilder::new()
                     .set_title("Mapedit")
                     .build();

    let mut builder = CanvasBuilder::new();
    content::Brush::init(&mut builder);
    let mut ctx = builder.build(window);

    let mut state = EditState::new();
    let mut cursor_pos = V2(0, 0);

    loop {
        let cursor_loc = state.center + view_to_chart(cursor_pos);
        draw_world(&state.world, &mut ctx, state.center, cursor_loc);

        for event in ctx.events().into_iter() {
            match event {
                Event::Quit => return,
                Event::KeyPress(Key::Escape) => return,

                Event::KeyPress(Key::W) => {
                    state.center = state.center + V2(-1, -1)
                }
                Event::KeyPress(Key::S) => {
                    state.center = state.center + V2(1, 1)
                }
                Event::KeyPress(Key::A) => {
                    state.center = state.center + V2(-1, 1)
                }
                Event::KeyPress(Key::D) => {
                    state.center = state.center + V2(1, -1)
                }

                Event::MouseMove(V2(x, y)) => {
                    state.paint(cursor_loc);

                    let size = ctx.window.size();
                    cursor_pos = V2(x as i32 - (size.0 / 2) as i32,
                                    y as i32 - (size.1 / 2) as i32);
                }

                Event::MousePress(MouseButton::Left) => {
                    state.paint_state = Some(PaintState::Draw);
                    state.paint(cursor_loc);
                }

                Event::MousePress(MouseButton::Right) => {
                    state.paint_state = Some(PaintState::Clear);
                    state.paint(cursor_loc);
                }

                Event::MouseRelease(_) => {
                    state.paint_state = None;
                }

                _ => (),
            }
        }
        ctx.end_frame();
    }
}

enum PaintState {
    Draw,
    Clear,
}

pub struct EditState {
    world: World,
    center: Location,
    brush: TerrainType,
    paint_state: Option<PaintState>,
}

impl EditState {
    pub fn new() -> EditState {
        EditState {
            world: World::new(None),
            center: Location::new(0, 0),
            brush: TerrainType::Rock,
            paint_state: None,
        }
    }

    pub fn paint(&mut self, cursor_loc: Location) {
        match self.paint_state {
            Some(PaintState::Draw) => {
                self.world.terrain.set(cursor_loc, self.brush)
            }
            Some(PaintState::Clear) => self.world.terrain.clear(cursor_loc),
            None => {}
        }
    }
}
<commit_msg>Start encapsulating world render logic<commit_after>extern crate calx;
extern crate content;
extern crate world;
extern crate render;

use calx::backend::{Key, Event, MouseButton};
use calx::{Kernel, V2, color};
use calx::backend::{WindowBuilder, Canvas, CanvasUtil, CanvasBuilder};
use content::TerrainType;
use content::Brush;
use world::{World, Location};
use world::query;
use render::{chart_to_screen, view_to_chart, cells_on_screen, render_terrain};
use render::{Angle, FLOOR_Z, BLOCK_Z};

/// State object for configuring world display.
struct DrawState {
    pub center: Location,
    pub cursor_loc: Option<Location>,
}

impl DrawState {
    pub fn new(center: Location) -> DrawState {
        DrawState {
            center: center,
            cursor_loc: None,
        }
    }

    pub fn cursor(mut self, cursor_loc: Location) -> DrawState {
        self.cursor_loc = Some(cursor_loc);
        self
    }

    fn draw(&self, ctx: &mut Canvas, w: &World) {
        for pt in cells_on_screen() {
            let screen_pos = chart_to_screen(pt);
            let loc = self.center + pt;

            let k = Kernel::new(|loc| query::terrain(w, loc), loc);
            render_terrain(&k, |img, angle, fore, back| {
                let z = match angle {
                    Angle::Up => FLOOR_Z,
                    _ => BLOCK_Z,
                };
                ctx.draw_image(img, screen_pos, z, fore, back)
            });
        }

        if let Some(cursor_loc) = self.cursor_loc {
            self.draw_cursor(ctx, cursor_loc)
        }
    }

    fn draw_cursor(&self, ctx: &mut Canvas, cursor_loc: Location) {
        if let Some(pt) = self.center.v2_at(cursor_loc) {
            // Draw cursor
            let screen_pos = chart_to_screen(pt);
            ctx.draw_image(Brush::CursorBottom.get(0),
                           screen_pos,
                           FLOOR_Z,
                           color::RED,
                           color::BLACK);
            ctx.draw_image(Brush::CursorTop.get(0),
                           screen_pos,
                           BLOCK_Z,
                           color::RED,
                           color::BLACK);

        }
    }
}

pub fn main() {
    let window = WindowBuilder::new()
                     .set_title("Mapedit")
                     .build();

    let mut builder = CanvasBuilder::new();
    content::Brush::init(&mut builder);
    let mut ctx = builder.build(window);

    let mut state = EditState::new();
    let mut cursor_pos = V2(0, 0);

    loop {
        let cursor_loc = state.center + view_to_chart(cursor_pos);

        DrawState::new(state.center)
            .cursor(cursor_loc)
            .draw(&mut ctx, &state.world);

        for event in ctx.events().into_iter() {
            match event {
                Event::Quit => return,
                Event::KeyPress(Key::Escape) => return,

                Event::KeyPress(Key::W) => {
                    state.center = state.center + V2(-1, -1)
                }
                Event::KeyPress(Key::S) => {
                    state.center = state.center + V2(1, 1)
                }
                Event::KeyPress(Key::A) => {
                    state.center = state.center + V2(-1, 1)
                }
                Event::KeyPress(Key::D) => {
                    state.center = state.center + V2(1, -1)
                }

                Event::MouseMove(V2(x, y)) => {
                    state.paint(cursor_loc);

                    let size = ctx.window.size();
                    cursor_pos = V2(x as i32 - (size.0 / 2) as i32,
                                    y as i32 - (size.1 / 2) as i32);
                }

                Event::MousePress(MouseButton::Left) => {
                    state.paint_state = Some(PaintState::Draw);
                    state.paint(cursor_loc);
                }

                Event::MousePress(MouseButton::Right) => {
                    state.paint_state = Some(PaintState::Clear);
                    state.paint(cursor_loc);
                }

                Event::MouseRelease(_) => {
                    state.paint_state = None;
                }

                _ => (),
            }
        }
        ctx.end_frame();
    }
}

enum PaintState {
    Draw,
    Clear,
}

pub struct EditState {
    world: World,
    center: Location,
    brush: TerrainType,
    paint_state: Option<PaintState>,
}

impl EditState {
    pub fn new() -> EditState {
        EditState {
            world: World::new(None),
            center: Location::new(0, 0),
            brush: TerrainType::Rock,
            paint_state: None,
        }
    }

    pub fn paint(&mut self, cursor_loc: Location) {
        match self.paint_state {
            Some(PaintState::Draw) => {
                self.world.terrain.set(cursor_loc, self.brush)
            }
            Some(PaintState::Clear) => self.world.terrain.clear(cursor_loc),
            None => {}
        }
    }
}
<|endoftext|>