<commit_before>// http://stackoverflow.com/questions/25877285/how-to-disable-unused-code-warnings-in-rust
// https://users.rust-lang.org/t/turning-off-compiler-warning-messages/4975/2
#![allow(non_snake_case)]

use postgres::{Connection, TlsMode};

use std::env;

use actix_web::{FromRequest, HttpRequest, HttpResponse};
use futures::future::{result, FutureResult};

use serde_derive::{Deserialize, Serialize};

#[derive(Serialize, Deserialize)]
struct UserInformation {
    userId: i32,
    name: String,
    surname: String,
    magicUrl: String,
    notifications: Vec<Notification>,
}

#[derive(Serialize, Deserialize)]
struct Notification {
    context: String,
    status: bool,
}

fn connection() -> Connection {
    Connection::connect(
        "postgres://".to_owned()
            + &env::var("PGUSER").unwrap()
            + "@localhost/"
            + &env::var("PGDATABASE").unwrap(),
        TlsMode::None,
    )
    .unwrap()
}

pub fn user_information(_req: &HttpRequest) -> FutureResult<HttpResponse, actix_web::error::Error> {
    let conn = connection();
    let user_id = 1;
    let rows = &conn.query(
    r#"SELECT "userId", name, surname, "magicUrl" FROM user_information where "userId" = $1"#,
                           &[&user_id])
                    .unwrap();
    let row = rows.into_iter().next().unwrap();

    let mut notifications = Vec::new();
    for row in &conn.query(
        r#"select context, status from user_information as u join notifications as n on n."userId"
         = u."userId" and u."userId" = $1"#,
                           &[&user_id])
                    .unwrap() {
        let notification = Notification {
            context: row.get(0),
            status: row.get(1),
        };
        notifications.push(notification);
    }

    let s = UserInformation {
        userId: row.get(0),
        name: row.get(1),
        surname: row.get(2),
        magicUrl: row.get(3),
        notifications,
    };
    result(Ok(HttpResponse::Ok().json(s)))
}
#[derive(Serialize, Deserialize)]
struct DataSet {
    id: i32,
    name: String,
}

pub fn data_sets(_req: &HttpRequest) -> FutureResult<HttpResponse, actix_web::error::Error> {
    let conn = connection();
    let mut data_sets = Vec::new();

    for row in &conn.query("SELECT id, name FROM data_sets", &[]).unwrap() {
        let data_set = DataSet {
            id: row.get(0),
            name: row.get(1),
        };
        // note: move occurs because `data_set` has type `DataSet`,
        // which does not implement the `Copy` trait
        println!("Found DataSet {}", &data_set.name);
        data_sets.push(data_set);
    }
    result(Ok(HttpResponse::Ok().json(data_sets)))
}

#[derive(Serialize, Deserialize)]
struct DataSetWithComments {
    id: i32,
    name: String,
    comments: Vec<Comment>,
}

#[derive(Serialize, Deserialize)]
struct Comment {
    id: i32,
    content: String,
    userName: String,
    userPhotoUrl: String,
    date: String,
}

#[derive(Deserialize)]
struct DataSetParams {
    url: String,
}

pub fn data_set(req: &HttpRequest) -> FutureResult<HttpResponse, actix_web::error::Error> {
    let conn = connection();

    let params = actix_web::Path::<DataSetParams>::extract(req).unwrap();
    let url = &params.url;

    let url2 = "dataSets/".to_owned() + url;
    let rows = &conn
        .query("SELECT id, name FROM data_sets where url = $1", &[&url2])
        .unwrap();
    let row = rows.into_iter().next().unwrap();
    let data_set_id: i32 = row.get(0);

    let mut comments = Vec::new();
    for row in &conn
        .query(
            r#"select c.id, content, "userName", "userPhotoUrl", date from comments as c
             join data_sets as d on c.data_set_id = d.id and d.id = $1"#,
            &[&data_set_id],
        )
        .unwrap()
    {
        let comment = Comment {
            id: row.get(0),
            content: row.get(1),
            userName: row.get(2),
            userPhotoUrl: row.get(3),
            date: row.get(4),
        };
        comments.push(comment);
    }

    let s = DataSetWithComments {
        id: row.get(0),
        name: row.get(1),
        comments: comments,
    };
    result(Ok(HttpResponse::Ok().json(s)))
}

/*
#[derive(Serialize, Deserialize)]
struct DataSetShort {
    id: i32,
    name: String,
    description: String,
    owner: String,
    releaseDate: String,
    rating: f32,
    favourite: bool,
    url: String,
}

#[get("/dataSetsCategories/<url>")]
fn data_set_category(url: &str) -> CORS<JSON<DataSetShort>> {
    let conn = connection();
    let url2 = "dataSetsCategories/".to_owned() + url;
    let rows = &conn
        .query(
            "select id from categories where \"contentUrl\" = $1",
            &[&url2],
        )
        .unwrap();
    let row = rows.into_iter().next().unwrap();
    let category_id: i32 = row.get(0);

    let dataSetShortRows = &conn.query("select d.id, name, SUBSTRING(description,0,100) as description, owner, \"releaseDate\", \
        rating, favourite, url from data_sets d join data_sets_in_categories di on d.id = di.data_sets_id \
        and di.categories_id = $1",
                    &[&category_id])
             .unwrap();
    let dataSetShortRow = dataSetShortRows.into_iter().next().unwrap();

    CORS::any(JSON(DataSetShort {
        id: dataSetShortRow.get(0),
        name: dataSetShortRow.get(1),
        description: dataSetShortRow.get(2),
        owner: dataSetShortRow.get(3),
        releaseDate: dataSetShortRow.get(4),
        rating: dataSetShortRow.get(5),
        favourite: dataSetShortRow.get(6),
        url: dataSetShortRow.get(7),
    }))
}

#[derive(Serialize, Deserialize)]
struct Category {
    id: i32,
    title: String,
    route: String,
    count: i32,
    contentUrl: String,
    subcategories: Vec<Subcategory>,
}

#[derive(Serialize, Deserialize)]
struct Subcategory {
    id: i32,
    title: String,
    route: String,
    count: i32,
    contentUrl: String,
}

#[get("/dataSetsCategories")]
fn data_sets_categories() -> CORS<JSON<Vec<Category>>> {
    let conn = connection();
    let mut categories = Vec::new();
    for row in &conn
        .query(
            "SELECT id, title, route, count, \"contentUrl\" FROM categories \
             where type = 'dataSet' and \"parentId\" is null",
            &[],
        )
        .unwrap()
    {
        let row_id: i32 = row.get(0);

        let mut subcategories = Vec::new();
        for subcategoryRow in &conn
            .query(
                "SELECT id, title, route, count, \"contentUrl\" FROM categories \
                 where type = 'dataSet' and \"parentId\" = $1",
                &[&row_id],
            )
            .unwrap()
        {
            let subcategory = Subcategory {
                id: subcategoryRow.get(0),
                title: subcategoryRow.get(1),
                route: subcategoryRow.get(2),
                count: subcategoryRow.get(3),
                contentUrl: subcategoryRow.get(4),
            };

            subcategories.push(subcategory);
        }

        let category = Category {
            id: row.get(0),
            title: row.get(1),
            route: row.get(2),
            count: row.get(3),
            contentUrl: row.get(4),
            subcategories: subcategories,
        };
        println!("Found Category {}", &category.title);
        categories.push(category);
    }
    CORS::any(JSON(categories))
}

use std::fs::File;
use std::io::{BufWriter, Write};

#[post("/dataSets/new", data = "<upload>")]
fn data_sets_new(upload: DataSetMultipart) -> CORS<String> {
    let f = File::create("plik").expect("Unable to create file");
    let mut f = BufWriter::new(f);
    f.write_all(&*upload.metadata)
        .expect("Unable to write data");
    CORS::any(format!("I read this: {:?}", upload))
}

#[derive(Debug)]
struct DataSetMultipart {
    name: String,
    description: String,
    categoryId: i32,
    metadata: Vec<u8>,
}

use std::io::{Cursor, Read};

impl FromData for DataSetMultipart {
    type Error = ();

    fn from_data(request: &Request, data: Data) -> data::Outcome<Self, Self::Error> {
        // All of these errors should be reported
        let ct = request
            .headers()
            .get_one("Content-Type")
            .expect("no content-type");
        let idx = ct.find("boundary=").expect("no boundary");
        let boundary = &ct[(idx + "boundary=".len())..];

        let mut d = Vec::new();
        data.stream_to(&mut d).expect("Unable to read");

        let mut mp = Multipart::with_body(Cursor::new(d), boundary);

        // Custom implementation parts

        let mut name = None;
        let mut description = None;
        let mut categoryId = None;
        let mut metadata = None;

        mp.foreach_entry(|mut entry| match entry.name.as_str() {
            "name" => {
                let t = entry.data.as_text().expect("not text");
                name = Some(t.into());
            }
            "description" => {
                let t = entry.data.as_text().expect("not text");
                description = Some(t.into());
            }
            "categoryId" => {
                let t = entry.data.as_text().expect("not text");
                let n = t.parse().expect("not number");
                categoryId = Some(n);
            }
            "metadata" => {
                let mut d = Vec::new();
                let f = entry.data.as_file().expect("not file");
                f.read_to_end(&mut d).expect("can't read");
                metadata = Some(d);
            }
            other => panic!("No known key {}", other),
        })
        .expect("Unable to iterate");

        let v = DataSetMultipart {
            name: name.expect("name not set"),
            description: description.expect("description not set"),
            categoryId: categoryId.expect("categoryId not set"),
            metadata: metadata.expect("file not set"),
        };

        // End custom

        Outcome::Success(v)
    }
}
*/
<commit_msg>/dataSets/{url}<commit_after>// http://stackoverflow.com/questions/25877285/how-to-disable-unused-code-warnings-in-rust
// https://users.rust-lang.org/t/turning-off-compiler-warning-messages/4975/2
#![allow(non_snake_case)]

use postgres::{Connection, TlsMode};

use std::env;

use actix_web::{FromRequest, HttpRequest, HttpResponse};
use futures::future::{result, FutureResult};

use serde_derive::{Deserialize, Serialize};

#[derive(Serialize, Deserialize)]
struct UserInformation {
    userId: i32,
    name: String,
    surname: String,
    magicUrl: String,
    notifications: Vec<Notification>,
}

#[derive(Serialize, Deserialize)]
struct Notification {
    context: String,
    status: bool,
}

fn connection() -> Connection {
    Connection::connect(
        "postgres://".to_owned()
            + &env::var("PGUSER").unwrap()
            + "@localhost/"
            + &env::var("PGDATABASE").unwrap(),
        TlsMode::None,
    )
    .unwrap()
}

pub fn user_information(_req: &HttpRequest) -> FutureResult<HttpResponse, actix_web::error::Error> {
    let conn = connection();
    let user_id = 1;
    let rows = &conn.query(
    r#"SELECT "userId", name, surname, "magicUrl" FROM user_information where "userId" = $1"#,
                           &[&user_id])
                    .expect("Query failed");
    let row = rows.into_iter().next().expect("No next row");

    let mut notifications = Vec::new();
    for row in &conn.query(
        r#"select context, status from user_information as u join notifications as n on n."userId"
         = u."userId" and u."userId" = $1"#,
                           &[&user_id])
                    .expect("Query failed") {
        let notification = Notification {
            context: row.get(0),
            status: row.get(1),
        };
        notifications.push(notification);
    }

    let s = UserInformation {
        userId: row.get(0),
        name: row.get(1),
        surname: row.get(2),
        magicUrl: row.get(3),
        notifications,
    };
    result(Ok(HttpResponse::Ok().json(s)))
}
#[derive(Serialize, Deserialize)]
struct DataSet {
    id: i32,
    name: String,
}

pub fn data_sets(_req: &HttpRequest) -> FutureResult<HttpResponse, actix_web::error::Error> {
    let conn = connection();
    let mut data_sets = Vec::new();

    for row in &conn
        .query("SELECT id, name FROM data_sets", &[])
        .expect("Query failed")
    {
        let data_set = DataSet {
            id: row.get(0),
            name: row.get(1),
        };
        // note: move occurs because `data_set` has type `DataSet`,
        // which does not implement the `Copy` trait
        println!("Found DataSet {}", &data_set.name);
        data_sets.push(data_set);
    }
    result(Ok(HttpResponse::Ok().json(data_sets)))
}

#[derive(Serialize, Deserialize)]
struct DataSetWithComments {
    id: i32,
    name: String,
    comments: Vec<Comment>,
}

#[derive(Serialize, Deserialize)]
struct Comment {
    id: i32,
    content: String,
    userName: String,
    userPhotoUrl: String,
    date: String,
}

#[derive(Deserialize)]
struct DataSetParams {
    url: String,
}

// test url: /dataSets/name-of-data-set
pub fn data_set(req: &HttpRequest) -> FutureResult<HttpResponse, actix_web::error::Error> {
    let conn = connection();

    let params = actix_web::Path::<DataSetParams>::extract(req).expect("Path extract failed");
    let url = &params.url;

    let url2 = "dataSets/".to_owned() + url;
    let rows = &conn
        .query("SELECT id, name FROM data_sets where url = $1", &[&url2])
        .expect("Query failed");
    let row = rows.into_iter().next().expect("No next row");
    let data_set_id: i32 = row.get(0);

    let mut comments = Vec::new();
    for row in &conn
        .query(
            r#"select c.id, content, "userName", "userPhotoUrl", date from comments as c join data_sets as d on c.data_set_id = d.id and d.id = $1"#,
            &[&data_set_id],
        )
        .expect("Query failed")
    {
        let comment = Comment {
            id: row.get(0),
            content: row.get(1),
            userName: row.get(2),
            userPhotoUrl: row.get(3),
            date: row.get(4),
        };
        comments.push(comment);
    }

    let s = DataSetWithComments {
        id: row.get(0),
        name: row.get(1),
        comments: comments,
    };
    result(Ok(HttpResponse::Ok().json(s)))
}

/*
#[derive(Serialize, Deserialize)]
struct DataSetShort {
    id: i32,
    name: String,
    description: String,
    owner: String,
    releaseDate: String,
    rating: f32,
    favourite: bool,
    url: String,
}

#[get("/dataSetsCategories/<url>")]
fn data_set_category(url: &str) -> CORS<JSON<DataSetShort>> {
    let conn = connection();
    let url2 = "dataSetsCategories/".to_owned() + url;
    let rows = &conn
        .query(
            "select id from categories where \"contentUrl\" = $1",
            &[&url2],
        )
        .unwrap();
    let row = rows.into_iter().next().unwrap();
    let category_id: i32 = row.get(0);

    let dataSetShortRows = &conn.query("select d.id, name, SUBSTRING(description,0,100) as description, owner, \"releaseDate\", \
        rating, favourite, url from data_sets d join data_sets_in_categories di on d.id = di.data_sets_id \
        and di.categories_id = $1",
                    &[&category_id])
             .unwrap();
    let dataSetShortRow = dataSetShortRows.into_iter().next().unwrap();

    CORS::any(JSON(DataSetShort {
        id: dataSetShortRow.get(0),
        name: dataSetShortRow.get(1),
        description: dataSetShortRow.get(2),
        owner: dataSetShortRow.get(3),
        releaseDate: dataSetShortRow.get(4),
        rating: dataSetShortRow.get(5),
        favourite: dataSetShortRow.get(6),
        url: dataSetShortRow.get(7),
    }))
}

#[derive(Serialize, Deserialize)]
struct Category {
    id: i32,
    title: String,
    route: String,
    count: i32,
    contentUrl: String,
    subcategories: Vec<Subcategory>,
}

#[derive(Serialize, Deserialize)]
struct Subcategory {
    id: i32,
    title: String,
    route: String,
    count: i32,
    contentUrl: String,
}

#[get("/dataSetsCategories")]
fn data_sets_categories() -> CORS<JSON<Vec<Category>>> {
    let conn = connection();
    let mut categories = Vec::new();
    for row in &conn
        .query(
            "SELECT id, title, route, count, \"contentUrl\" FROM categories \
             where type = 'dataSet' and \"parentId\" is null",
            &[],
        )
        .unwrap()
    {
        let row_id: i32 = row.get(0);

        let mut subcategories = Vec::new();
        for subcategoryRow in &conn
            .query(
                "SELECT id, title, route, count, \"contentUrl\" FROM categories \
                 where type = 'dataSet' and \"parentId\" = $1",
                &[&row_id],
            )
            .unwrap()
        {
            let subcategory = Subcategory {
                id: subcategoryRow.get(0),
                title: subcategoryRow.get(1),
                route: subcategoryRow.get(2),
                count: subcategoryRow.get(3),
                contentUrl: subcategoryRow.get(4),
            };

            subcategories.push(subcategory);
        }

        let category = Category {
            id: row.get(0),
            title: row.get(1),
            route: row.get(2),
            count: row.get(3),
            contentUrl: row.get(4),
            subcategories: subcategories,
        };
        println!("Found Category {}", &category.title);
        categories.push(category);
    }
    CORS::any(JSON(categories))
}

use std::fs::File;
use std::io::{BufWriter, Write};

#[post("/dataSets/new", data = "<upload>")]
fn data_sets_new(upload: DataSetMultipart) -> CORS<String> {
    let f = File::create("plik").expect("Unable to create file");
    let mut f = BufWriter::new(f);
    f.write_all(&*upload.metadata)
        .expect("Unable to write data");
    CORS::any(format!("I read this: {:?}", upload))
}

#[derive(Debug)]
struct DataSetMultipart {
    name: String,
    description: String,
    categoryId: i32,
    metadata: Vec<u8>,
}

use std::io::{Cursor, Read};

impl FromData for DataSetMultipart {
    type Error = ();

    fn from_data(request: &Request, data: Data) -> data::Outcome<Self, Self::Error> {
        // All of these errors should be reported
        let ct = request
            .headers()
            .get_one("Content-Type")
            .expect("no content-type");
        let idx = ct.find("boundary=").expect("no boundary");
        let boundary = &ct[(idx + "boundary=".len())..];

        let mut d = Vec::new();
        data.stream_to(&mut d).expect("Unable to read");

        let mut mp = Multipart::with_body(Cursor::new(d), boundary);

        // Custom implementation parts

        let mut name = None;
        let mut description = None;
        let mut categoryId = None;
        let mut metadata = None;

        mp.foreach_entry(|mut entry| match entry.name.as_str() {
            "name" => {
                let t = entry.data.as_text().expect("not text");
                name = Some(t.into());
            }
            "description" => {
                let t = entry.data.as_text().expect("not text");
                description = Some(t.into());
            }
            "categoryId" => {
                let t = entry.data.as_text().expect("not text");
                let n = t.parse().expect("not number");
                categoryId = Some(n);
            }
            "metadata" => {
                let mut d = Vec::new();
                let f = entry.data.as_file().expect("not file");
                f.read_to_end(&mut d).expect("can't read");
                metadata = Some(d);
            }
            other => panic!("No known key {}", other),
        })
        .expect("Unable to iterate");

        let v = DataSetMultipart {
            name: name.expect("name not set"),
            description: description.expect("description not set"),
            categoryId: categoryId.expect("categoryId not set"),
            metadata: metadata.expect("file not set"),
        };

        // End custom

        Outcome::Success(v)
    }
}
*/
<|endoftext|>


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

extern crate grin_api as api;
extern crate grin_chain as chain;
extern crate grin_core as core;
extern crate grin_servers as servers;
extern crate grin_p2p as p2p;
extern crate grin_pow as pow;
extern crate grin_util as util;
extern crate grin_wallet as wallet;

extern crate bufstream;
extern crate serde_json;

mod framework;

use std::io::prelude::*;
use std::net::TcpStream;
use bufstream::BufStream;
use serde_json::Value;

use std::thread;
use std::time;

use core::global;
use core::global::ChainTypes;

use framework::{config, miner_config};

// Create a grin server, and a stratum server.
// Simulate a few JSONRpc requests and verify the results.
// Validate disconnected workers
// Validate broadcasting new jobs
#[test]
fn basic_stratum_server() {
	util::init_test_logger();
	global::set_mining_mode(ChainTypes::AutomatedTesting);

	let test_name_dir = "stratum_server";
	framework::clean_all_output(test_name_dir);

	// Create a server
	let s = servers::Server::new(config(4000, test_name_dir, 0)).unwrap();

	// Get mining config with stratumserver enabled
	let mut miner_cfg = miner_config();
	miner_cfg.enable_mining = false;
	miner_cfg.attempt_time_per_block = 999;
	miner_cfg.enable_stratum_server = Some(true);
	miner_cfg.stratum_server_addr = Some(String::from("127.0.0.1:11101"));

	// Start stratum server
	s.start_stratum_server(miner_cfg);

	// Wait for stratum server to start and
	// Verify stratum server accepts connections
	loop {
		if let Ok(_stream) = TcpStream::connect("127.0.0.1:11101") {
			break;
		} else {
			thread::sleep(time::Duration::from_millis(500));
		}
		// As this stream falls out of scope it will be disconnected
	}

	// Create a few new worker connections
	let mut workers = vec![];
	for _n in 0..5 {
		let w = TcpStream::connect("127.0.0.1:11101").unwrap();
		w.set_nonblocking(true)
			.expect("Failed to set TcpStream to non-blocking");
		let stream = BufStream::new(w);
		workers.push(stream);
	}
	assert!(workers.len() == 5);

	// Simulate a worker lost connection
	workers.remove(4);

	// Swallow the genesis block
	thread::sleep(time::Duration::from_secs(1)); // Wait for the server to broadcast
	let mut response = String::new();
	for n in 0..workers.len() {
		let _result = workers[n].read_line(&mut response);
	}

	// Verify a few stratum JSONRpc commands
	// getjobtemplate - expected block template result
	let mut response = String::new();
	let job_req = "{\"id\": \"Stratum\", \"jsonrpc\": \"2.0\", \"method\": \"getjobtemplate\"}\n";
	workers[2].write(job_req.as_bytes()).unwrap();
	workers[2].flush().unwrap();
	thread::sleep(time::Duration::from_secs(1)); // Wait for the server to reply
	match workers[2].read_line(&mut response) {
		Ok(_) => {
			let r: Value = serde_json::from_str(&response).unwrap();
			assert_eq!(r["error"], serde_json::Value::Null);
			assert_ne!(r["result"], serde_json::Value::Null);
		}
		Err(_e) => {
			assert!(false);
		}
	}

	// keepalive - expected "ok" result
	let mut response = String::new();
	let job_req = "{\"id\":\"3\",\"jsonrpc\":\"2.0\",\"method\":\"keepalive\"}\n";
	let ok_resp = "{\"id\":\"3\",\"jsonrpc\":\"2.0\",\"result\":\"ok\",\"error\":null}\n";
	workers[2].write(job_req.as_bytes()).unwrap();
	workers[2].flush().unwrap();
	thread::sleep(time::Duration::from_secs(1)); // Wait for the server to reply
	let _st = workers[2].read_line(&mut response);
	assert_eq!(response.as_str(), ok_resp);

	// "doesnotexist" - error expected
	let mut response = String::new();
	let job_req = "{\"id\":\"4\",\"jsonrpc\":\"2.0\",\"method\":\"doesnotexist\"}\n";
	let ok_resp = "{\"id\":\"4\",\"jsonrpc\":\"2.0\",\"result\":null,\"error\":{\"code\":-32601,\"message\":\"Method not found\"}}\n";
	workers[3].write(job_req.as_bytes()).unwrap();
	workers[3].flush().unwrap();
	thread::sleep(time::Duration::from_secs(1)); // Wait for the server to reply
	let _st = workers[3].read_line(&mut response);
	assert_eq!(response.as_str(), ok_resp);

	// Simulate a worker lost connection
	workers.remove(1);

	// Start mining blocks
	s.start_miner(miner_config());

	// Verify blocks are being broadcast to workers
	let expected = String::from("job");
	thread::sleep(time::Duration::from_secs(3)); // Wait for a few mined blocks
	let mut jobtemplate = String::new();
	let _st = workers[2].read_line(&mut jobtemplate);
	let job_template: Value = serde_json::from_str(&jobtemplate).unwrap();
	assert_eq!(job_template["method"], expected);
}
<commit_msg>enhance test by validating against stats (#959)<commit_after>// Copyright 2018 The Grin Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate grin_api as api;
extern crate grin_chain as chain;
extern crate grin_core as core;
extern crate grin_servers as servers;
extern crate grin_p2p as p2p;
extern crate grin_pow as pow;
extern crate grin_util as util;
extern crate grin_wallet as wallet;

extern crate bufstream;
extern crate serde_json;

mod framework;

use std::io::prelude::*;
use std::net::TcpStream;
use bufstream::BufStream;
use serde_json::Value;

use std::thread;
use std::time;

use core::global;
use core::global::ChainTypes;

use framework::{config, miner_config};

// Create a grin server, and a stratum server.
// Simulate a few JSONRpc requests and verify the results.
// Validate disconnected workers
// Validate broadcasting new jobs
#[test]
fn basic_stratum_server() {
	util::init_test_logger();
	global::set_mining_mode(ChainTypes::AutomatedTesting);

	let test_name_dir = "stratum_server";
	framework::clean_all_output(test_name_dir);

	// Create a server
	let s = servers::Server::new(config(4000, test_name_dir, 0)).unwrap();

	// Get mining config with stratumserver enabled
	let mut miner_cfg = miner_config();
	miner_cfg.enable_mining = false;
	miner_cfg.attempt_time_per_block = 999;
	miner_cfg.enable_stratum_server = Some(true);
	miner_cfg.stratum_server_addr = Some(String::from("127.0.0.1:11101"));

	// Start stratum server
	s.start_stratum_server(miner_cfg);

	// Wait for stratum server to start and
	// Verify stratum server accepts connections
	loop {
		if let Ok(_stream) = TcpStream::connect("127.0.0.1:11101") {
			break;
		} else {
			thread::sleep(time::Duration::from_millis(500));
		}
		// As this stream falls out of scope it will be disconnected
	}

	// Create a few new worker connections
	let mut workers = vec![];
	for _n in 0..5 {
		let w = TcpStream::connect("127.0.0.1:11101").unwrap();
		w.set_nonblocking(true)
			.expect("Failed to set TcpStream to non-blocking");
		let stream = BufStream::new(w);
		workers.push(stream);
	}
	assert!(workers.len() == 5);

	// Simulate a worker lost connection
	workers.remove(4);

	// Swallow the genesis block
	thread::sleep(time::Duration::from_secs(1)); // Wait for the server to broadcast
	let mut response = String::new();
	for n in 0..workers.len() {
		let _result = workers[n].read_line(&mut response);
	}

	// Verify a few stratum JSONRpc commands
	// getjobtemplate - expected block template result
	let mut response = String::new();
	let job_req = "{\"id\": \"Stratum\", \"jsonrpc\": \"2.0\", \"method\": \"getjobtemplate\"}\n";
	workers[2].write(job_req.as_bytes()).unwrap();
	workers[2].flush().unwrap();
	thread::sleep(time::Duration::from_secs(1)); // Wait for the server to reply
	match workers[2].read_line(&mut response) {
		Ok(_) => {
			let r: Value = serde_json::from_str(&response).unwrap();
			assert_eq!(r["error"], serde_json::Value::Null);
			assert_ne!(r["result"], serde_json::Value::Null);
		}
		Err(_e) => {
			assert!(false);
		}
	}

	// keepalive - expected "ok" result
	let mut response = String::new();
	let job_req = "{\"id\":\"3\",\"jsonrpc\":\"2.0\",\"method\":\"keepalive\"}\n";
	let ok_resp = "{\"id\":\"3\",\"jsonrpc\":\"2.0\",\"result\":\"ok\",\"error\":null}\n";
	workers[2].write(job_req.as_bytes()).unwrap();
	workers[2].flush().unwrap();
	thread::sleep(time::Duration::from_secs(1)); // Wait for the server to reply
	let _st = workers[2].read_line(&mut response);
	assert_eq!(response.as_str(), ok_resp);

	// "doesnotexist" - error expected
	let mut response = String::new();
	let job_req = "{\"id\":\"4\",\"jsonrpc\":\"2.0\",\"method\":\"doesnotexist\"}\n";
	let ok_resp = "{\"id\":\"4\",\"jsonrpc\":\"2.0\",\"result\":null,\"error\":{\"code\":-32601,\"message\":\"Method not found\"}}\n";
	workers[3].write(job_req.as_bytes()).unwrap();
	workers[3].flush().unwrap();
	thread::sleep(time::Duration::from_secs(1)); // Wait for the server to reply
	let _st = workers[3].read_line(&mut response);
	assert_eq!(response.as_str(), ok_resp);

	// Verify stratum server and worker stats
	let stats = s.get_server_stats().unwrap();
	assert_eq!(stats.stratum_stats.block_height, 1); // just 1 genesis block
	assert_eq!(stats.stratum_stats.num_workers, 4); // 5 - 1 = 4
	assert_eq!(stats.stratum_stats.worker_stats[5].is_connected, false); // worker was removed
	assert_eq!(stats.stratum_stats.worker_stats[1].is_connected, true);

	// Start mining blocks
	s.start_miner(miner_config());

	// Simulate a worker lost connection
	workers.remove(1);

	// Verify blocks are being broadcast to workers
	let expected = String::from("job");
	thread::sleep(time::Duration::from_secs(3)); // Wait for a few mined blocks
	let mut jobtemplate = String::new();
	let _st = workers[2].read_line(&mut jobtemplate);
	let job_template: Value = serde_json::from_str(&jobtemplate).unwrap();
	assert_eq!(job_template["method"], expected);

	// Verify stratum server and worker stats
	let stats = s.get_server_stats().unwrap();
	assert_eq!(stats.stratum_stats.num_workers, 3); // 5 - 2 = 3
	assert_eq!(stats.stratum_stats.worker_stats[2].is_connected, false); // worker was removed
	assert_ne!(stats.stratum_stats.block_height, 1);
}
<|endoftext|>


<commit_before>#![crate_name = "docopt_macros"]
#![crate_type = "dylib"]

#![feature(plugin_registrar, quote, rustc_private)]

//! This crate defines the `docopt!` macro. It is documented in the
//! documentation of the `docopt` crate.

extern crate syntax;
extern crate rustc_plugin;
extern crate docopt;

use std::borrow::Borrow;
use std::collections::HashMap;

use rustc_plugin::Registry;
use syntax::{ast, codemap};
use syntax::errors::DiagnosticBuilder;
use syntax::ext::base::{ExtCtxt, MacResult, MacEager, DummyResult};
use syntax::ext::build::AstBuilder;
use syntax::fold::Folder;
use syntax::parse::common::SeqSep;
use syntax::parse::parser::Parser;
use syntax::parse::token;
use syntax::print::pprust;
use syntax::ptr::P;
use syntax::util::small_vector::SmallVector;

use docopt::{Docopt, ArgvMap};
use docopt::parse::{Options, Atom, Positional, Zero, One};

type PResult<'a, T> = Result<T, DiagnosticBuilder<'a>>;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("docopt", expand);
}

fn expand(cx: &mut ExtCtxt, span: codemap::Span, tts: &[ast::TokenTree])
         -> Box<MacResult+'static> {
    let parsed = match MacParser::new(cx, tts).parse() {
        Ok(parsed) => parsed,
        Err(_) => return DummyResult::any(span),
    };
    parsed.items(cx)
}

/// Parsed corresponds to the result of parsing a `docopt` macro call.
/// It can be used to write a corresponding struct.
struct Parsed {
    struct_info: StructInfo,
    doc: Docopt,
    /// Overrided type annotations for struct members. May be empty.
    /// When a type annotation for an atom doesn't exist, then one is
    /// inferred automatically. It is one of: `bool`, `usize`, `String` or
    /// `Vec<String>`.
    types: HashMap<Atom, P<ast::Ty>>,
}

impl Parsed {
    /// Returns a macro result suitable for expansion.
    /// Contains two items: one for the struct and one for the struct impls.
    fn items(&self, cx: &ExtCtxt) -> Box<MacResult+'static> {
        let mut its = vec!();
        its.push(self.struct_decl(cx));

        let struct_name = self.struct_info.name;
        let full_doc = &*self.doc.parser().full_doc;
        its.push(quote_item!(cx,
            impl $struct_name {
                #[allow(dead_code)]
                fn docopt() -> docopt::Docopt {
                    // The unwrap is justified here because this code
                    // gen only happens if the Docopt usage string is valid.
                    docopt::Docopt::new($full_doc).unwrap()
                }
            }
        ).unwrap());
        MacEager::items(SmallVector::many(its))
    }

    /// Returns an item for the struct definition.
    fn struct_decl(&self, cx: &ExtCtxt) -> P<ast::Item> {
        let name = self.struct_info.name.clone();
        let vis = if self.struct_info.public { ast::Public }
                  else { ast::Inherited };
        let def = ast::VariantData::Struct(
            self.struct_fields(cx), ast::DUMMY_NODE_ID);

        let mut traits = vec!["RustcDecodable".to_string()];
        traits.extend(self.struct_info.deriving.iter().cloned());
        let attrs = vec![attribute(cx, "allow", vec!["non_snake_case"]),
                         attribute(cx, "derive", traits)];

        let st = cx.item_struct(codemap::DUMMY_SP, name.clone(), def);
        cx.item(codemap::DUMMY_SP, name, attrs, st.node.clone()).map(|mut it| {
            it.vis = vis;
            it
        })
    }

    /// Returns a list of fields for the struct definition.
    /// Handles type annotations.
    fn struct_fields(&self, cx: &ExtCtxt) -> Vec<ast::StructField> {
        let mut fields: Vec<ast::StructField> = vec!();
        for (atom, opts) in self.doc.parser().descs.iter() {
            let name = ArgvMap::key_to_struct_field(&*atom.to_string());
            let ty = match self.types.get(atom) {
                None => self.pat_type(cx, atom, opts),
                Some(ty) => ty.clone(),
            };
            fields.push(self.mk_struct_field(&*name, ty));
        }
        fields
    }

    /// Returns an inferred type for a usage pattern.
    /// This is only invoked when a type annotation is not present.
    fn pat_type(&self, cx: &ExtCtxt, atom: &Atom, opts: &Options) -> P<ast::Ty> {
        let sp = codemap::DUMMY_SP;
        match (opts.repeats, &opts.arg) {
            (false, &Zero) => {
                match atom {
                    &Positional(_) => cx.ty_ident(sp, ident("String")),
                    _ => cx.ty_ident(sp, ident("bool")),
                }
            }
            (true, &Zero) => {
                match atom {
                    &Positional(_) => ty_vec_string(cx),
                    _ => cx.ty_ident(sp, ident("usize")),
                }
            }
            (false, &One(_)) => cx.ty_ident(sp, ident("String")),
            (true, &One(_)) => ty_vec_string(cx),
        }
    }

    /// Creates a struct field from a member name and type.
    fn mk_struct_field(&self, name: &str, ty: P<ast::Ty>) -> ast::StructField {
        codemap::dummy_spanned(ast::StructField_ {
            kind: ast::NamedField(ident(name), ast::Public),
            id: ast::DUMMY_NODE_ID,
            ty: ty,
            attrs: vec!(),
        })
    }
}

/// State for parsing a `docopt` macro invocation.
struct MacParser<'a, 'b:'a> {
    cx: &'a mut ExtCtxt<'b>,
    p: Parser<'b>,
}

impl<'a, 'b> MacParser<'a, 'b> {
    fn new(cx: &'a mut ExtCtxt<'b>, tts: &[ast::TokenTree]) -> MacParser<'a, 'b> {
        let p = cx.new_parser_from_tts(tts);
        MacParser { cx: cx, p: p }
    }

    /// Main entry point for parsing arguments to `docopt` macro.
    /// First looks for an identifier for the struct name.
    /// Second, a string containing the docopt usage patterns.
    /// Third, an optional list of type annotations.
    fn parse(&mut self) -> PResult<'b, Parsed> {
        if self.p.token == token::Eof {
            let err = self.cx.struct_span_err(self.cx.call_site(), "macro expects arguments");
            return Err(err);
        }
        let struct_info = try!(self.parse_struct_info());
        let docstr = try!(self.parse_str());

        let sep = SeqSep {
            sep: Some(token::Comma),
            trailing_sep_allowed: true,
        };
        let types = try!(self.p.parse_seq_to_end(
            &token::Eof, sep, |p| MacParser::parse_type_annotation(p)
        )).into_iter()
          .map(|(ident, ty)| {
              let field_name = ident.to_string();
              let key = ArgvMap::struct_field_to_key(&*field_name);
              (Atom::new(&*key), ty)
           })
          .collect::<HashMap<Atom, P<ast::Ty>>>();
        try!(self.p.expect(&token::Eof));

        // This config does not matter because we're only asking for the
        // usage patterns in the Docopt string. The configuration does not
        // affect the retrieval of usage patterns.
        let doc = match Docopt::new(docstr) {
            Ok(doc) => doc,
            Err(err) => {
                let err = self.cx.struct_span_err(self.cx.call_site(),
                                                  &format!("Invalid Docopt usage: {}", err));
                return Err(err);
            }
        };
        Ok(Parsed {
            struct_info: struct_info,
            doc: doc,
            types: types,
        })
    }

    /// Parses a single string literal. On failure, an error is logged and
    /// unit is returned.
    fn parse_str(&mut self) -> PResult<'b, String> {
        fn lit_is_str(lit: &ast::Lit) -> bool {
            match lit.node {
                ast::LitStr(_, _) => true,
                _ => false,
            }
        }
        fn lit_to_string(lit: &ast::Lit) -> String {
            match lit.node {
                ast::LitStr(ref s, _) => s.to_string(),
                _ => panic!("BUG: expected string literal"),
            }
        }
        let exp = self.cx.expander().fold_expr(self.p.parse_expr().unwrap());
        let s = match exp.node {
            ast::ExprLit(ref lit) if lit_is_str(&**lit) => {
                lit_to_string(&**lit)
            }
            _ => {
                let err = format!("Expected string literal but got {}",
                                  pprust::expr_to_string(&*exp));
                let err = self.cx.struct_span_err(exp.span, &*err);
                return Err(err);
            }
        };
        try!(self.p.bump());
        Ok(s)
    }

    /// Parses a type annotation in a `docopt` invocation of the form
    /// `ident: Ty`.
    /// Note that this is a static method as it is used as a HOF.
    fn parse_type_annotation(p: &mut Parser<'b>)
                             -> PResult<'b, (ast::Ident, P<ast::Ty>)> {
        let ident = try!(p.parse_ident());
        try!(p.expect(&token::Colon));
        let ty = p.parse_ty().unwrap();
        Ok((ident, ty))
    }

    /// Parses struct information, like visibility, name and deriving.
    fn parse_struct_info(&mut self) -> PResult<'b, StructInfo> {
        let public = try!(self.p.eat_keyword(token::keywords::Pub));
        let mut info = StructInfo {
            name: try!(self.p.parse_ident()),
            public: public,
            deriving: vec![],
        };
        if try!(self.p.eat(&token::Comma)) { return Ok(info); }
        let deriving = try!(self.p.parse_ident());
        if deriving.name.as_str() != "derive" {
            let err = format!("Expected 'derive' keyword but got '{}'",
                              deriving);
            let err = self.cx.struct_span_err(self.cx.call_site(), &*err);
            return Err(err);
        }
        while !try!(self.p.eat(&token::Comma)) {
            info.deriving.push(
                try!(self.p.parse_ident()).name.to_string());
        }
        Ok(info)
    }
}

struct StructInfo {
    name: ast::Ident,
    public: bool,
    deriving: Vec<String>,
}

// Convenience functions for building intermediate values.

fn ident(s: &str) -> ast::Ident {
    ast::Ident::with_empty_ctxt(token::intern(s))
}

fn attribute<S, T>(cx: &ExtCtxt, name: S, items: Vec<T>) -> ast::Attribute
            where S: Borrow<str>, T: Borrow<str> {
    let sp = codemap::DUMMY_SP;
    let its = items.into_iter().map(|s| meta_item(cx, s.borrow())).collect();
    let mi = cx.meta_list(sp, intern(name.borrow()), its);
    cx.attribute(sp, mi)
}

fn meta_item(cx: &ExtCtxt, s: &str) -> P<ast::MetaItem> {
    cx.meta_word(codemap::DUMMY_SP, intern(s))
}

fn intern(s: &str) -> token::InternedString {
    token::intern_and_get_ident(s)
}

fn ty_vec_string(cx: &ExtCtxt) -> P<ast::Ty> {
    let sp = codemap::DUMMY_SP;
    let tystr = ast::AngleBracketedParameterData {
        lifetimes: vec![],
        types: P::from_vec(vec![cx.ty_ident(sp, ident("String"))]),
        bindings: P::empty(),
    };
    cx.ty_path(ast::Path {
        span: sp,
        global: false,
        segments: vec![ast::PathSegment {
            identifier: ident("Vec"),
            parameters: ast::PathParameters::AngleBracketed(tystr),
        }]
    })
}
<commit_msg>Update for simplified parser API.<commit_after>#![crate_name = "docopt_macros"]
#![crate_type = "dylib"]

#![feature(plugin_registrar, quote, rustc_private)]

//! This crate defines the `docopt!` macro. It is documented in the
//! documentation of the `docopt` crate.

extern crate syntax;
extern crate rustc_plugin;
extern crate docopt;

use std::borrow::Borrow;
use std::collections::HashMap;

use rustc_plugin::Registry;
use syntax::{ast, codemap};
use syntax::errors::DiagnosticBuilder;
use syntax::ext::base::{ExtCtxt, MacResult, MacEager, DummyResult};
use syntax::ext::build::AstBuilder;
use syntax::fold::Folder;
use syntax::parse::common::SeqSep;
use syntax::parse::parser::Parser;
use syntax::parse::token;
use syntax::print::pprust;
use syntax::ptr::P;
use syntax::util::small_vector::SmallVector;

use docopt::{Docopt, ArgvMap};
use docopt::parse::{Options, Atom, Positional, Zero, One};

type PResult<'a, T> = Result<T, DiagnosticBuilder<'a>>;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("docopt", expand);
}

fn expand(cx: &mut ExtCtxt, span: codemap::Span, tts: &[ast::TokenTree])
         -> Box<MacResult+'static> {
    let parsed = match MacParser::new(cx, tts).parse() {
        Ok(parsed) => parsed,
        Err(_) => return DummyResult::any(span),
    };
    parsed.items(cx)
}

/// Parsed corresponds to the result of parsing a `docopt` macro call.
/// It can be used to write a corresponding struct.
struct Parsed {
    struct_info: StructInfo,
    doc: Docopt,
    /// Overrided type annotations for struct members. May be empty.
    /// When a type annotation for an atom doesn't exist, then one is
    /// inferred automatically. It is one of: `bool`, `usize`, `String` or
    /// `Vec<String>`.
    types: HashMap<Atom, P<ast::Ty>>,
}

impl Parsed {
    /// Returns a macro result suitable for expansion.
    /// Contains two items: one for the struct and one for the struct impls.
    fn items(&self, cx: &ExtCtxt) -> Box<MacResult+'static> {
        let mut its = vec!();
        its.push(self.struct_decl(cx));

        let struct_name = self.struct_info.name;
        let full_doc = &*self.doc.parser().full_doc;
        its.push(quote_item!(cx,
            impl $struct_name {
                #[allow(dead_code)]
                fn docopt() -> docopt::Docopt {
                    // The unwrap is justified here because this code
                    // gen only happens if the Docopt usage string is valid.
                    docopt::Docopt::new($full_doc).unwrap()
                }
            }
        ).unwrap());
        MacEager::items(SmallVector::many(its))
    }

    /// Returns an item for the struct definition.
    fn struct_decl(&self, cx: &ExtCtxt) -> P<ast::Item> {
        let name = self.struct_info.name.clone();
        let vis = if self.struct_info.public { ast::Public }
                  else { ast::Inherited };
        let def = ast::VariantData::Struct(
            self.struct_fields(cx), ast::DUMMY_NODE_ID);

        let mut traits = vec!["RustcDecodable".to_string()];
        traits.extend(self.struct_info.deriving.iter().cloned());
        let attrs = vec![attribute(cx, "allow", vec!["non_snake_case"]),
                         attribute(cx, "derive", traits)];

        let st = cx.item_struct(codemap::DUMMY_SP, name.clone(), def);
        cx.item(codemap::DUMMY_SP, name, attrs, st.node.clone()).map(|mut it| {
            it.vis = vis;
            it
        })
    }

    /// Returns a list of fields for the struct definition.
    /// Handles type annotations.
    fn struct_fields(&self, cx: &ExtCtxt) -> Vec<ast::StructField> {
        let mut fields: Vec<ast::StructField> = vec!();
        for (atom, opts) in self.doc.parser().descs.iter() {
            let name = ArgvMap::key_to_struct_field(&*atom.to_string());
            let ty = match self.types.get(atom) {
                None => self.pat_type(cx, atom, opts),
                Some(ty) => ty.clone(),
            };
            fields.push(self.mk_struct_field(&*name, ty));
        }
        fields
    }

    /// Returns an inferred type for a usage pattern.
    /// This is only invoked when a type annotation is not present.
    fn pat_type(&self, cx: &ExtCtxt, atom: &Atom, opts: &Options) -> P<ast::Ty> {
        let sp = codemap::DUMMY_SP;
        match (opts.repeats, &opts.arg) {
            (false, &Zero) => {
                match atom {
                    &Positional(_) => cx.ty_ident(sp, ident("String")),
                    _ => cx.ty_ident(sp, ident("bool")),
                }
            }
            (true, &Zero) => {
                match atom {
                    &Positional(_) => ty_vec_string(cx),
                    _ => cx.ty_ident(sp, ident("usize")),
                }
            }
            (false, &One(_)) => cx.ty_ident(sp, ident("String")),
            (true, &One(_)) => ty_vec_string(cx),
        }
    }

    /// Creates a struct field from a member name and type.
    fn mk_struct_field(&self, name: &str, ty: P<ast::Ty>) -> ast::StructField {
        codemap::dummy_spanned(ast::StructField_ {
            kind: ast::NamedField(ident(name), ast::Public),
            id: ast::DUMMY_NODE_ID,
            ty: ty,
            attrs: vec!(),
        })
    }
}

/// State for parsing a `docopt` macro invocation.
struct MacParser<'a, 'b:'a> {
    cx: &'a mut ExtCtxt<'b>,
    p: Parser<'b>,
}

impl<'a, 'b> MacParser<'a, 'b> {
    fn new(cx: &'a mut ExtCtxt<'b>, tts: &[ast::TokenTree]) -> MacParser<'a, 'b> {
        let p = cx.new_parser_from_tts(tts);
        MacParser { cx: cx, p: p }
    }

    /// Main entry point for parsing arguments to `docopt` macro.
    /// First looks for an identifier for the struct name.
    /// Second, a string containing the docopt usage patterns.
    /// Third, an optional list of type annotations.
    fn parse(&mut self) -> PResult<'b, Parsed> {
        if self.p.token == token::Eof {
            let err = self.cx.struct_span_err(self.cx.call_site(), "macro expects arguments");
            return Err(err);
        }
        let struct_info = try!(self.parse_struct_info());
        let docstr = try!(self.parse_str());

        let sep = SeqSep {
            sep: Some(token::Comma),
            trailing_sep_allowed: true,
        };
        let types = try!(self.p.parse_seq_to_end(
            &token::Eof, sep, |p| MacParser::parse_type_annotation(p)
        )).into_iter()
          .map(|(ident, ty)| {
              let field_name = ident.to_string();
              let key = ArgvMap::struct_field_to_key(&*field_name);
              (Atom::new(&*key), ty)
           })
          .collect::<HashMap<Atom, P<ast::Ty>>>();
        try!(self.p.expect(&token::Eof));

        // This config does not matter because we're only asking for the
        // usage patterns in the Docopt string. The configuration does not
        // affect the retrieval of usage patterns.
        let doc = match Docopt::new(docstr) {
            Ok(doc) => doc,
            Err(err) => {
                let err = self.cx.struct_span_err(self.cx.call_site(),
                                                  &format!("Invalid Docopt usage: {}", err));
                return Err(err);
            }
        };
        Ok(Parsed {
            struct_info: struct_info,
            doc: doc,
            types: types,
        })
    }

    /// Parses a single string literal. On failure, an error is logged and
    /// unit is returned.
    fn parse_str(&mut self) -> PResult<'b, String> {
        fn lit_is_str(lit: &ast::Lit) -> bool {
            match lit.node {
                ast::LitStr(_, _) => true,
                _ => false,
            }
        }
        fn lit_to_string(lit: &ast::Lit) -> String {
            match lit.node {
                ast::LitStr(ref s, _) => s.to_string(),
                _ => panic!("BUG: expected string literal"),
            }
        }
        let exp = self.cx.expander().fold_expr(self.p.parse_expr().unwrap());
        let s = match exp.node {
            ast::ExprLit(ref lit) if lit_is_str(&**lit) => {
                lit_to_string(&**lit)
            }
            _ => {
                let err = format!("Expected string literal but got {}",
                                  pprust::expr_to_string(&*exp));
                let err = self.cx.struct_span_err(exp.span, &*err);
                return Err(err);
            }
        };
        self.p.bump();
        Ok(s)
    }

    /// Parses a type annotation in a `docopt` invocation of the form
    /// `ident: Ty`.
    /// Note that this is a static method as it is used as a HOF.
    fn parse_type_annotation(p: &mut Parser<'b>)
                             -> PResult<'b, (ast::Ident, P<ast::Ty>)> {
        let ident = try!(p.parse_ident());
        try!(p.expect(&token::Colon));
        let ty = p.parse_ty().unwrap();
        Ok((ident, ty))
    }

    /// Parses struct information, like visibility, name and deriving.
    fn parse_struct_info(&mut self) -> PResult<'b, StructInfo> {
        let public = self.p.eat_keyword(token::keywords::Pub);
        let mut info = StructInfo {
            name: try!(self.p.parse_ident()),
            public: public,
            deriving: vec![],
        };
        if self.p.eat(&token::Comma) { return Ok(info); }
        let deriving = try!(self.p.parse_ident());
        if deriving.name.as_str() != "derive" {
            let err = format!("Expected 'derive' keyword but got '{}'",
                              deriving);
            let err = self.cx.struct_span_err(self.cx.call_site(), &*err);
            return Err(err);
        }
        while !self.p.eat(&token::Comma) {
            info.deriving.push(
                try!(self.p.parse_ident()).name.to_string());
        }
        Ok(info)
    }
}

struct StructInfo {
    name: ast::Ident,
    public: bool,
    deriving: Vec<String>,
}

// Convenience functions for building intermediate values.

fn ident(s: &str) -> ast::Ident {
    ast::Ident::with_empty_ctxt(token::intern(s))
}

fn attribute<S, T>(cx: &ExtCtxt, name: S, items: Vec<T>) -> ast::Attribute
            where S: Borrow<str>, T: Borrow<str> {
    let sp = codemap::DUMMY_SP;
    let its = items.into_iter().map(|s| meta_item(cx, s.borrow())).collect();
    let mi = cx.meta_list(sp, intern(name.borrow()), its);
    cx.attribute(sp, mi)
}

fn meta_item(cx: &ExtCtxt, s: &str) -> P<ast::MetaItem> {
    cx.meta_word(codemap::DUMMY_SP, intern(s))
}

fn intern(s: &str) -> token::InternedString {
    token::intern_and_get_ident(s)
}

fn ty_vec_string(cx: &ExtCtxt) -> P<ast::Ty> {
    let sp = codemap::DUMMY_SP;
    let tystr = ast::AngleBracketedParameterData {
        lifetimes: vec![],
        types: P::from_vec(vec![cx.ty_ident(sp, ident("String"))]),
        bindings: P::empty(),
    };
    cx.ty_path(ast::Path {
        span: sp,
        global: false,
        segments: vec![ast::PathSegment {
            identifier: ident("Vec"),
            parameters: ast::PathParameters::AngleBracketed(tystr),
        }]
    })
}
<|endoftext|>


<commit_before>use std::collections::hash_map::DefaultHasher;
use std::hash::{BuildHasherDefault, Hash};

use utils::HashIter;

pub trait Counter: Copy + Ord + Sized {
    fn checked_add(self, other: Self) -> Option<Self>;

    fn zero() -> Self;

    fn one() -> Self;
}

macro_rules! impl_counter {
    ($t:ty) => {
        impl Counter for $t {
            #[inline]
            fn checked_add(self, other: Self) -> Option<Self> {
                self.checked_add(other)
            }

            #[inline]
            fn zero() -> Self {
                0
            }

            #[inline]
            fn one() -> Self {
                1
            }
        }
    }
}

impl_counter!(usize);
impl_counter!(u64);
impl_counter!(u32);
impl_counter!(u16);
impl_counter!(u8);

pub struct CountMinSketch<C>
where
    C: Counter,
{
    table: Vec<C>,
    w: usize,
    d: usize,
}

impl<C> CountMinSketch<C>
where
    C: Counter,
{
    pub fn with_params(w: usize, d: usize) -> CountMinSketch<C> {
        let table = vec![C::zero(); w.checked_mul(d).unwrap()];
        CountMinSketch {
            table: table,
            w: w,
            d: d,
        }
    }

    pub fn add<T>(&mut self, obj: &T)
    where
        T: Hash,
    {
        self.add_n(&obj, C::one())
    }

    pub fn add_n<T>(&mut self, obj: &T, n: C)
    where
        T: Hash,
    {
        let bh = BuildHasherDefault::<DefaultHasher>::default();
        for (i, pos) in HashIter::new(self.w, self.d, obj, bh).enumerate() {
            let x = i * self.w + pos;
            self.table[x] = self.table[x].checked_add(n).unwrap();
        }
    }

    pub fn query_point<T>(&self, obj: &T) -> C
    where
        T: Hash,
    {
        let bh = BuildHasherDefault::<DefaultHasher>::default();
        HashIter::new(self.w, self.d, obj, bh)
            .enumerate()
            .map(|(i, pos)| i * self.w + pos)
            .map(|x| self.table[x])
            .min()
            .unwrap()
    }
}

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

    #[test]
    fn empty() {
        let cms = CountMinSketch::<usize>::with_params(10, 10);
        assert_eq!(cms.query_point(&1), 0);
    }

    #[test]
    fn add_1() {
        let mut cms = CountMinSketch::<usize>::with_params(10, 10);

        cms.add(&1);
        assert_eq!(cms.query_point(&1), 1);
        assert_eq!(cms.query_point(&2), 0);
    }

    #[test]
    fn add_2() {
        let mut cms = CountMinSketch::<usize>::with_params(10, 10);

        cms.add(&1);
        cms.add(&1);
        assert_eq!(cms.query_point(&1), 2);
        assert_eq!(cms.query_point(&2), 0);
    }

    #[test]
    fn add_2_1() {
        let mut cms = CountMinSketch::<usize>::with_params(10, 10);

        cms.add(&1);
        cms.add(&2);
        cms.add(&1);
        assert_eq!(cms.query_point(&1), 2);
        assert_eq!(cms.query_point(&2), 1);
        assert_eq!(cms.query_point(&3), 0);
    }
}
<commit_msg>countminsketch: docs<commit_after>use std::collections::hash_map::DefaultHasher;
use std::hash::{BuildHasherDefault, Hash};

use utils::HashIter;

/// Abstract, but safe counter.
pub trait Counter: Copy + Ord + Sized {
    /// Add self to another counter.
    ///
    /// Returns `Some(Self)` when the addition was successfull (i.e. no overflow occured) and
    /// `None` in case of an error.
    fn checked_add(self, other: Self) -> Option<Self>;

    /// Return a counter representing zero.
    fn zero() -> Self;

    /// Return a counter representing one.
    fn one() -> Self;
}

macro_rules! impl_counter {
    ($t:ty) => {
        impl Counter for $t {
            #[inline]
            fn checked_add(self, other: Self) -> Option<Self> {
                self.checked_add(other)
            }

            #[inline]
            fn zero() -> Self {
                0
            }

            #[inline]
            fn one() -> Self {
                1
            }
        }
    }
}

impl_counter!(usize);
impl_counter!(u64);
impl_counter!(u32);
impl_counter!(u16);
impl_counter!(u8);

/// Simple implementation of a
/// [Count-min sketch](https://en.wikipedia.org/wiki/Count%E2%80%93min_sketch)
///
/// The type parameter `C` sets the type of the counter in the internal table and can be used to
/// reduce memory consumption when low counts are expected.
pub struct CountMinSketch<C = usize>
where
    C: Counter,
{
    table: Vec<C>,
    w: usize,
    d: usize,
}

impl<C> CountMinSketch<C>
where
    C: Counter,
{
    /// Create new CountMinSketch based on table size.
    ///
    /// - `w` sets the number of columns
    /// - `d` sets the number of rows
    pub fn with_params(w: usize, d: usize) -> CountMinSketch<C> {
        let table = vec![C::zero(); w.checked_mul(d).unwrap()];
        CountMinSketch {
            table: table,
            w: w,
            d: d,
        }
    }

    /// Add one to the counter of the given element.
    pub fn add<T>(&mut self, obj: &T)
    where
        T: Hash,
    {
        self.add_n(&obj, C::one())
    }

    /// Add `n` to the counter of the given element.
    pub fn add_n<T>(&mut self, obj: &T, n: C)
    where
        T: Hash,
    {
        let bh = BuildHasherDefault::<DefaultHasher>::default();
        for (i, pos) in HashIter::new(self.w, self.d, obj, bh).enumerate() {
            let x = i * self.w + pos;
            self.table[x] = self.table[x].checked_add(n).unwrap();
        }
    }

    /// Runs a point query, i.e. a query for the count of a single object.
    pub fn query_point<T>(&self, obj: &T) -> C
    where
        T: Hash,
    {
        let bh = BuildHasherDefault::<DefaultHasher>::default();
        HashIter::new(self.w, self.d, obj, bh)
            .enumerate()
            .map(|(i, pos)| i * self.w + pos)
            .map(|x| self.table[x])
            .min()
            .unwrap()
    }
}

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

    #[test]
    fn empty() {
        let cms = CountMinSketch::<usize>::with_params(10, 10);
        assert_eq!(cms.query_point(&1), 0);
    }

    #[test]
    fn add_1() {
        let mut cms = CountMinSketch::<usize>::with_params(10, 10);

        cms.add(&1);
        assert_eq!(cms.query_point(&1), 1);
        assert_eq!(cms.query_point(&2), 0);
    }

    #[test]
    fn add_2() {
        let mut cms = CountMinSketch::<usize>::with_params(10, 10);

        cms.add(&1);
        cms.add(&1);
        assert_eq!(cms.query_point(&1), 2);
        assert_eq!(cms.query_point(&2), 0);
    }

    #[test]
    fn add_2_1() {
        let mut cms = CountMinSketch::<usize>::with_params(10, 10);

        cms.add(&1);
        cms.add(&2);
        cms.add(&1);
        assert_eq!(cms.query_point(&1), 2);
        assert_eq!(cms.query_point(&2), 1);
        assert_eq!(cms.query_point(&3), 0);
    }
}
<|endoftext|>


<commit_before>//
// Copyright (c) 2016, Boris Popov <popov@whitekefir.ru>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//

extern crate libc;

use self::libc::c_char;
use self::libc::c_void;
use self::libc::c_ulong;
use self::libc::c_int;
use std::ptr;
use std::ffi::CString;
use strerror::getStrError;

//////////////////////////////////////////////////////////////////
pub struct MountInfo<'a> {
    source:     &'a str,
    target:     &'a str,
    filesystem: &'a str
}

pub fn mount(mi: &MountInfo) -> Result<(), String> {
    let c_source = CString::new(mi.source).unwrap();
    let source_raw = c_source.into_raw();
    let c_target = CString::new(mi.target).unwrap();
    let target_raw = c_target.into_raw();
    let c_filesystem = CString::new(mi.filesystem).unwrap();
    let filesystem_raw = c_filesystem.into_raw();
    let flags: c_ulong = 0;
    let data: *const c_void = ptr::null();
    let mut result: c_int = 0;
    unsafe {
        result = libc::mount(source_raw,
                             target_raw,
                             filesystem_raw,
                             flags,
                             data);
    }
    return get_result(result, "mount");
}

pub fn umount(mi: &MountInfo) -> Result<(), String> {
    let c_target = CString::new(mi.target).unwrap();
    let target_raw = c_target.into_raw();
    let mut result: c_int = 0;
    unsafe {
        result = libc::umount(target_raw);
    }
    return get_result(result, "umount");
}

fn get_result(result: c_int, s: &str) -> Result<(), String> {
    match result {
        0  => Ok(()),
        -1 => Err(getStrError()),
        _  => {
            let mut mess = "Unexpected error in mount::".to_string();
            mess += s;
            mess += "!";
            Err(mess)
        }
    }
}
//////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////
#[test]
fn test_mount_01() {
    let mi = MountInfo{source: "/dev/sdb1",
                       target: "/mnt/temp",
                       filesystem: "ext4"};
    println!("\n *** mount *** \n");
    let res = mount(&mi);
    match res {
        Err(e) => println!("\nMOUNT ERROR: {}", e),
        _      => println!("\nMOUNT OK")
    }

    let res2 = umount(&mi);
    match res2 {
        Err(e) => println!("\nUMOUNT ERROR: {}", e),
        _      => println!("\nUMOUNT OK")
    }
}
//////////////////////////////////////////////////////////////////
<commit_msg>fix mount::umount<commit_after>//
// Copyright (c) 2016, Boris Popov <popov@whitekefir.ru>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//

extern crate libc;

use self::libc::c_void;
use self::libc::c_ulong;
use self::libc::c_int;
use std::ptr;
use std::ffi::CString;
use strerror::getStrError;

//////////////////////////////////////////////////////////////////
pub struct MountInfo<'a> {
    pub source:     &'a str,
    pub target:     &'a str,
    pub filesystem: &'a str
}

pub fn mount(mi: &MountInfo) -> Result<(), String> {
    let c_source = CString::new(mi.source).unwrap();
    let source_raw = c_source.into_raw();
    let c_target = CString::new(mi.target).unwrap();
    let target_raw = c_target.into_raw();
    let c_filesystem = CString::new(mi.filesystem).unwrap();
    let filesystem_raw = c_filesystem.into_raw();
    let flags: c_ulong = 0;
    let data: *const c_void = ptr::null();
    let mut result: c_int = 0;
    unsafe {
        result = libc::mount(source_raw,
                             target_raw,
                             filesystem_raw,
                             flags,
                             data);
    }
    return get_result(result, "mount");
}

pub fn umount(target: &str) -> Result<(), String> {
    let c_target = CString::new(target).unwrap();
    let target_raw = c_target.into_raw();
    let mut result: c_int = 0;
    unsafe {
        result = libc::umount(target_raw);
    }
    return get_result(result, "umount");
}

fn get_result(result: c_int, s: &str) -> Result<(), String> {
    match result {
        0  => Ok(()),
        -1 => Err(getStrError()),
        _  => {
            let mut mess = "Unexpected error in mount::".to_string();
            mess += s;
            mess += "!";
            Err(mess)
        }
    }
}
//////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////
#[test]
fn test_mount_01() {
    let mi = MountInfo{source: "/dev/sdb1",
                       target: "/mnt/temp",
                       filesystem: "ext4"};
    println!("\n *** mount *** \n");
    let res = mount(&mi);
    match res {
        Err(e) => println!("\nMOUNT ERROR: {}", e),
        _      => println!("\nMOUNT OK")
    }

    let res2 = umount(mi.target);
    match res2 {
        Err(e) => println!("\nUMOUNT ERROR: {}", e),
        _      => println!("\nUMOUNT OK")
    }
}
//////////////////////////////////////////////////////////////////
<|endoftext|>


<commit_before><commit_msg>make possible to add more than one o parameter<commit_after><|endoftext|>


<commit_before><commit_msg>Update comparison of nightly syntax trees for DelimSpan change<commit_after><|endoftext|>


<commit_before>extern mod extra;
extern mod glfw;
extern mod gl;
extern mod cgmath;
extern mod noise;

use std::cast;
use std::ptr;
use std::hashmap::HashMap;
use std;

use gl::types::*;

use cgmath::vector::Vector;
use cgmath::vector::Vec3;
use cgmath::vector::Vec4;

use noise::Perlin;

use CHUNK_SIZE;
use WORLD_SIZE;
use GraphicsResources;

static MAX_CHUNKS : uint = 32;

pub struct ChunkLoader<'a> {
    seed : u32,
    graphics_resources : &'a GraphicsResources,
    cache : HashMap<(i64, i64), ~Chunk>
}

impl<'a> ChunkLoader<'a> {
    pub fn new<'a>(seed : u32, graphics_resources : &'a GraphicsResources) -> ChunkLoader<'a> {
        ChunkLoader {
            seed: seed,
            graphics_resources : graphics_resources,
            cache: HashMap::new(),
        }
    }

    pub fn update(&mut self, x : i64, z: i64) {
        let mask : i64 = !(CHUNK_SIZE as i64 - 1);
        let mut loaded = false;

        for ix in range(-(WORLD_SIZE as i64)/2, (WORLD_SIZE as i64)/2) {
            for iz in range(-(WORLD_SIZE as i64)/2, (WORLD_SIZE as i64)/2) {
                let cx : i64 = (x & mask) + ix*CHUNK_SIZE as i64;
                let cz : i64 = (z & mask) + iz*CHUNK_SIZE as i64;
                if !self.cache.contains_key(&(cx, cz)) {
                    if !loaded {
                        println!("loading chunk ({}, {})", cx, cz);
                        let chunk = chunk_gen(self.graphics_resources, self.seed, cx, cz);
                        self.cache.insert((cx, cz), chunk);
                        loaded = true;
                    }
                } else {
                    let chunk = self.cache.find_mut(&(cx, cz)).unwrap();
                    chunk.touch();
                }
            }
        }

        while self.cache.len() > MAX_CHUNKS {
            let (&k, _) = self.cache.iter().min_by(|&(_, chunk)| chunk.used_time).unwrap();
            self.cache.remove(&k);
        }
    }
}

pub struct Chunk {
    x: i64,
    z: i64,
    map: ~Map,
    vao: GLuint,
    vertex_buffer: GLuint,
    normal_buffer: GLuint,
    element_buffer: GLuint,
    num_elements: uint,
    used_time: u64,
}

impl Chunk {
    fn touch(&mut self) {
        self.used_time = extra::time::precise_time_ns();
    }
}

impl Drop for Chunk {
    fn drop(&mut self) {
        unsafe {
            println!("unloading chunk ({}, {})", self.x, self.z);
            gl::DeleteBuffers(1, &self.vertex_buffer);
            gl::DeleteBuffers(1, &self.normal_buffer);
            gl::DeleteBuffers(1, &self.element_buffer);
            gl::DeleteVertexArrays(1, &self.vao);
        }
    }
}

struct Block {
    color: Vec4<f32>,
}

struct Map {
    blocks: [[[Block, ..CHUNK_SIZE], ..CHUNK_SIZE], ..CHUNK_SIZE],
}

struct Face {
    normal: Vec3<f32>,
    vertices: [Vec3<f32>, ..4],
}

pub fn chunk_gen(res: &GraphicsResources, seed: u32, chunk_x: i64, chunk_z: i64) -> ~Chunk {
    let def_block = Block { color: Vec4::<f32>::new(0.0, 0.0, 0.0, 0.0) };
    let mut map = ~Map {
        blocks: [[[def_block, ..CHUNK_SIZE], ..CHUNK_SIZE], ..CHUNK_SIZE],
    };

    let block_exists = |x: int, y: int, z: int| -> bool {
        if x < 0 || x >= CHUNK_SIZE as int || y < 0 || y >= CHUNK_SIZE as int || z < 0 || z >= CHUNK_SIZE as int {
            return false;
        }

        map.blocks[x][y][z].color.w == 1.0f32
    };

    let perlin = Perlin::from_seed([seed as uint]);

    for block_x in range(0, CHUNK_SIZE) {
        for block_z in range(0, CHUNK_SIZE) {
            let noise = perlin.gen([
                (chunk_x + block_x as i64) as f64 * 0.1,
                (chunk_z + block_z as i64) as f64 * 0.1
            ]);
            let height = ((noise + 1.0) * (CHUNK_SIZE as f64 / 8.0)) as uint;
            for y in range(0, height) {
                let color = Vec4::<f32>::new(0.2, 0.8, 0.2, 1.0);
                map.blocks[block_x][y][block_z] = Block { color: color };
            }
        }
    }

    let mut vertices : ~[Vec3<f32>] = ~[];
    let mut normals : ~[Vec3<f32>] = ~[];
    let mut elements : ~[GLuint] = ~[];

    let mut idx = 0;

    for x in range(0, CHUNK_SIZE) {
        for y in range(0, CHUNK_SIZE) {
            for z in range(0, CHUNK_SIZE) {
                let block = &map.blocks[x][y][z];

                if (block.color.w == 0.0f32) {
                    continue;
                }

                let block_position = Vec3 { x: x as f32, y: y as f32, z: z as f32 };

                for face in faces.iter() {
                    let neighbor_position = block_position.add_v(&face.normal);
                    if block_exists(neighbor_position.x as int, neighbor_position.y as int, neighbor_position.z as int) {
                        continue;
                    }

                    for v in face.vertices.iter() {
                        vertices.push(v.add_v(&block_position));
                        normals.push(face.normal);
                    }

                    for e in face_elements.iter() {
                        elements.push((idx * face.vertices.len()) as GLuint + *e);
                    }

                    idx += 1;
                }
            }
        }
    }

    let mut vao = 0;
    let mut vertex_buffer = 0;
    let mut normal_buffer = 0;
    let mut element_buffer = 0;

    unsafe {
        // Create Vertex Array Object
        gl::GenVertexArrays(1, &mut vao);
        gl::BindVertexArray(vao);

        // Create a Vertex Buffer Object and copy the vertex data to it
        gl::GenBuffers(1, &mut vertex_buffer);
        gl::BindBuffer(gl::ARRAY_BUFFER, vertex_buffer);
        gl::BufferData(gl::ARRAY_BUFFER,
                        (vertices.len() * std::mem::size_of::<Vec3<f32>>()) as GLsizeiptr,
                        cast::transmute(&vertices[0]),
                        gl::STATIC_DRAW);

        // Create a Vertex Buffer Object and copy the normal data to it
        gl::GenBuffers(1, &mut normal_buffer);
        gl::BindBuffer(gl::ARRAY_BUFFER, normal_buffer);
        gl::BufferData(gl::ARRAY_BUFFER,
                        (normals.len() * std::mem::size_of::<Vec3<f32>>()) as GLsizeiptr,
                        cast::transmute(&normals[0]),
                        gl::STATIC_DRAW);

        // Create a Vertex Buffer Object and copy the element data to it
        gl::GenBuffers(1, &mut element_buffer);
        gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, element_buffer);
        gl::BufferData(gl::ELEMENT_ARRAY_BUFFER,
                        (elements.len() * std::mem::size_of::<GLuint>()) as GLsizeiptr,
                        cast::transmute(&elements[0]),
                        gl::STATIC_DRAW);

        // Specify the layout of the vertex data
        let vert_attr = "position".with_c_str(|ptr| gl::GetAttribLocation(res.program, ptr));
        assert!(vert_attr as u32 != gl::INVALID_VALUE);
        gl::BindBuffer(gl::ARRAY_BUFFER, vertex_buffer);
        gl::EnableVertexAttribArray(vert_attr as GLuint);
        gl::VertexAttribPointer(vert_attr as GLuint, 3, gl::FLOAT,
                                gl::FALSE as GLboolean, 0, ptr::null());

        let normal_attr = "normal".with_c_str(|ptr| gl::GetAttribLocation(res.program, ptr));
        assert!(normal_attr as u32 != gl::INVALID_VALUE);
        gl::BindBuffer(gl::ARRAY_BUFFER, normal_buffer);
        gl::EnableVertexAttribArray(normal_attr as GLuint);
        gl::VertexAttribPointer(normal_attr as GLuint, 3, gl::FLOAT,
                                gl::FALSE as GLboolean, 0, ptr::null());
    }

    gl::BindVertexArray(0);

    return ~Chunk {
        x: chunk_x,
        z: chunk_z,
        map: map,
        vao: vao,
        vertex_buffer: vertex_buffer,
        normal_buffer: normal_buffer,
        element_buffer: element_buffer,
        num_elements: elements.len(),
        used_time: extra::time::precise_time_ns(),
    };
}

static face_elements : [GLuint, ..6] = [
    0, 1, 2, 3, 2, 1,
];

static faces : [Face, ..6] = [
    /* front */
    Face {
        normal: Vec3 { x: 0.0, y: 0.0, z: 1.0 },
        vertices: [
            Vec3 { x: 0.0, y: 0.0, z: 1.0 }, /* bottom left */
            Vec3 { x: 1.0, y: 0.0, z: 1.0 },  /* bottom right */
            Vec3 { x: 0.0, y: 1.0, z: 1.0 }, /* top left */
            Vec3 { x: 1.0, y: 1.0, z: 1.0 },  /* top right */
        ],
    },

    /* back */
    Face {
        normal: Vec3 { x: 0.0, y: 0.0, z: -1.0 },
        vertices: [
            Vec3 { x: 1.0, y: 0.0, z: 0.0 }, /* bottom right */
            Vec3 { x: 0.0, y: 0.0, z: 0.0 },  /* bottom left */
            Vec3 { x: 1.0, y: 1.0, z: 0.0 }, /* top right */
            Vec3 { x: 0.0, y: 1.0, z: 0.0 },  /* top left */
        ],
    },

    /* right */
    Face {
        normal: Vec3 { x: 1.0, y: 0.0, z: 0.0 },
        vertices: [
            Vec3 { x: 1.0, y: 0.0, z: 1.0 }, /* bottom front */
            Vec3 { x: 1.0, y: 0.0, z: 0.0 }, /* bottom back */
            Vec3 { x: 1.0, y: 1.0, z: 1.0 }, /* top front */
            Vec3 { x: 1.0, y: 1.0, z: 0.0 }, /* top back */
        ],
    },

    /* left */
    Face {
        normal: Vec3 { x: -1.0, y: 0.0, z: 0.0 },
        vertices: [
            Vec3 { x: 0.0, y: 0.0, z: 0.0 }, /* bottom back */
            Vec3 { x: 0.0, y: 0.0, z: 1.0 }, /* bottom front */
            Vec3 { x: 0.0, y: 1.0, z: 0.0 }, /* top back */
            Vec3 { x: 0.0, y: 1.0, z: 1.0 }, /* top front */
        ],
    },

    /* top */
    Face {
        normal: Vec3 { x: 0.0, y: 1.0, z: 0.0 },
        vertices: [
            Vec3 { x: 0.0, y: 1.0, z: 1.0 }, /* front left */
            Vec3 { x: 1.0, y: 1.0, z: 1.0 }, /* front right */
            Vec3 { x: 0.0, y: 1.0, z: 0.0 }, /* back left */
            Vec3 { x: 1.0, y: 1.0, z: 0.0 }, /* back right */
        ],
    },

    /* bottom */
    Face {
        normal: Vec3 { x: 0.0, y: -1.0, z: 0.0 },
        vertices: [
            Vec3 { x: 0.0, y: 0.0, z: 0.0 }, /* back left */
            Vec3 { x: 1.0, y: 0.0, z: 0.0 }, /* back right */
            Vec3 { x: 0.0, y: 0.0, z: 1.0 }, /* front left */
            Vec3 { x: 1.0, y: 0.0, z: 1.0 }, /* front right */
        ],
    },
];
<commit_msg>load an equal radius of chunks on all sides<commit_after>extern mod extra;
extern mod glfw;
extern mod gl;
extern mod cgmath;
extern mod noise;

use std::cast;
use std::ptr;
use std::hashmap::HashMap;
use std;

use gl::types::*;

use cgmath::vector::Vector;
use cgmath::vector::Vec3;
use cgmath::vector::Vec4;

use noise::Perlin;

use CHUNK_SIZE;
use WORLD_SIZE;
use GraphicsResources;

static MAX_CHUNKS : uint = 32;

pub struct ChunkLoader<'a> {
    seed : u32,
    graphics_resources : &'a GraphicsResources,
    cache : HashMap<(i64, i64), ~Chunk>
}

impl<'a> ChunkLoader<'a> {
    pub fn new<'a>(seed : u32, graphics_resources : &'a GraphicsResources) -> ChunkLoader<'a> {
        ChunkLoader {
            seed: seed,
            graphics_resources : graphics_resources,
            cache: HashMap::new(),
        }
    }

    pub fn update(&mut self, x : i64, z: i64) {
        let mask : i64 = !(CHUNK_SIZE as i64 - 1);
        let mut loaded = false;

        for ix in std::iter::range_inclusive(-(WORLD_SIZE as i64)/2, (WORLD_SIZE as i64)/2) {
            for iz in std::iter::range_inclusive(-(WORLD_SIZE as i64)/2, (WORLD_SIZE as i64)/2) {
                let cx : i64 = (x & mask) + ix*CHUNK_SIZE as i64;
                let cz : i64 = (z & mask) + iz*CHUNK_SIZE as i64;
                if !self.cache.contains_key(&(cx, cz)) {
                    if !loaded {
                        println!("loading chunk ({}, {})", cx, cz);
                        let chunk = chunk_gen(self.graphics_resources, self.seed, cx, cz);
                        self.cache.insert((cx, cz), chunk);
                        loaded = true;
                    }
                } else {
                    let chunk = self.cache.find_mut(&(cx, cz)).unwrap();
                    chunk.touch();
                }
            }
        }

        while self.cache.len() > MAX_CHUNKS {
            let (&k, _) = self.cache.iter().min_by(|&(_, chunk)| chunk.used_time).unwrap();
            self.cache.remove(&k);
        }
    }
}

pub struct Chunk {
    x: i64,
    z: i64,
    map: ~Map,
    vao: GLuint,
    vertex_buffer: GLuint,
    normal_buffer: GLuint,
    element_buffer: GLuint,
    num_elements: uint,
    used_time: u64,
}

impl Chunk {
    fn touch(&mut self) {
        self.used_time = extra::time::precise_time_ns();
    }
}

impl Drop for Chunk {
    fn drop(&mut self) {
        unsafe {
            println!("unloading chunk ({}, {})", self.x, self.z);
            gl::DeleteBuffers(1, &self.vertex_buffer);
            gl::DeleteBuffers(1, &self.normal_buffer);
            gl::DeleteBuffers(1, &self.element_buffer);
            gl::DeleteVertexArrays(1, &self.vao);
        }
    }
}

struct Block {
    color: Vec4<f32>,
}

struct Map {
    blocks: [[[Block, ..CHUNK_SIZE], ..CHUNK_SIZE], ..CHUNK_SIZE],
}

struct Face {
    normal: Vec3<f32>,
    vertices: [Vec3<f32>, ..4],
}

pub fn chunk_gen(res: &GraphicsResources, seed: u32, chunk_x: i64, chunk_z: i64) -> ~Chunk {
    let def_block = Block { color: Vec4::<f32>::new(0.0, 0.0, 0.0, 0.0) };
    let mut map = ~Map {
        blocks: [[[def_block, ..CHUNK_SIZE], ..CHUNK_SIZE], ..CHUNK_SIZE],
    };

    let block_exists = |x: int, y: int, z: int| -> bool {
        if x < 0 || x >= CHUNK_SIZE as int || y < 0 || y >= CHUNK_SIZE as int || z < 0 || z >= CHUNK_SIZE as int {
            return false;
        }

        map.blocks[x][y][z].color.w == 1.0f32
    };

    let perlin = Perlin::from_seed([seed as uint]);

    for block_x in range(0, CHUNK_SIZE) {
        for block_z in range(0, CHUNK_SIZE) {
            let noise = perlin.gen([
                (chunk_x + block_x as i64) as f64 * 0.1,
                (chunk_z + block_z as i64) as f64 * 0.1
            ]);
            let height = ((noise + 1.0) * (CHUNK_SIZE as f64 / 8.0)) as uint;
            for y in range(0, height) {
                let color = Vec4::<f32>::new(0.2, 0.8, 0.2, 1.0);
                map.blocks[block_x][y][block_z] = Block { color: color };
            }
        }
    }

    let mut vertices : ~[Vec3<f32>] = ~[];
    let mut normals : ~[Vec3<f32>] = ~[];
    let mut elements : ~[GLuint] = ~[];

    let mut idx = 0;

    for x in range(0, CHUNK_SIZE) {
        for y in range(0, CHUNK_SIZE) {
            for z in range(0, CHUNK_SIZE) {
                let block = &map.blocks[x][y][z];

                if (block.color.w == 0.0f32) {
                    continue;
                }

                let block_position = Vec3 { x: x as f32, y: y as f32, z: z as f32 };

                for face in faces.iter() {
                    let neighbor_position = block_position.add_v(&face.normal);
                    if block_exists(neighbor_position.x as int, neighbor_position.y as int, neighbor_position.z as int) {
                        continue;
                    }

                    for v in face.vertices.iter() {
                        vertices.push(v.add_v(&block_position));
                        normals.push(face.normal);
                    }

                    for e in face_elements.iter() {
                        elements.push((idx * face.vertices.len()) as GLuint + *e);
                    }

                    idx += 1;
                }
            }
        }
    }

    let mut vao = 0;
    let mut vertex_buffer = 0;
    let mut normal_buffer = 0;
    let mut element_buffer = 0;

    unsafe {
        // Create Vertex Array Object
        gl::GenVertexArrays(1, &mut vao);
        gl::BindVertexArray(vao);

        // Create a Vertex Buffer Object and copy the vertex data to it
        gl::GenBuffers(1, &mut vertex_buffer);
        gl::BindBuffer(gl::ARRAY_BUFFER, vertex_buffer);
        gl::BufferData(gl::ARRAY_BUFFER,
                        (vertices.len() * std::mem::size_of::<Vec3<f32>>()) as GLsizeiptr,
                        cast::transmute(&vertices[0]),
                        gl::STATIC_DRAW);

        // Create a Vertex Buffer Object and copy the normal data to it
        gl::GenBuffers(1, &mut normal_buffer);
        gl::BindBuffer(gl::ARRAY_BUFFER, normal_buffer);
        gl::BufferData(gl::ARRAY_BUFFER,
                        (normals.len() * std::mem::size_of::<Vec3<f32>>()) as GLsizeiptr,
                        cast::transmute(&normals[0]),
                        gl::STATIC_DRAW);

        // Create a Vertex Buffer Object and copy the element data to it
        gl::GenBuffers(1, &mut element_buffer);
        gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, element_buffer);
        gl::BufferData(gl::ELEMENT_ARRAY_BUFFER,
                        (elements.len() * std::mem::size_of::<GLuint>()) as GLsizeiptr,
                        cast::transmute(&elements[0]),
                        gl::STATIC_DRAW);

        // Specify the layout of the vertex data
        let vert_attr = "position".with_c_str(|ptr| gl::GetAttribLocation(res.program, ptr));
        assert!(vert_attr as u32 != gl::INVALID_VALUE);
        gl::BindBuffer(gl::ARRAY_BUFFER, vertex_buffer);
        gl::EnableVertexAttribArray(vert_attr as GLuint);
        gl::VertexAttribPointer(vert_attr as GLuint, 3, gl::FLOAT,
                                gl::FALSE as GLboolean, 0, ptr::null());

        let normal_attr = "normal".with_c_str(|ptr| gl::GetAttribLocation(res.program, ptr));
        assert!(normal_attr as u32 != gl::INVALID_VALUE);
        gl::BindBuffer(gl::ARRAY_BUFFER, normal_buffer);
        gl::EnableVertexAttribArray(normal_attr as GLuint);
        gl::VertexAttribPointer(normal_attr as GLuint, 3, gl::FLOAT,
                                gl::FALSE as GLboolean, 0, ptr::null());
    }

    gl::BindVertexArray(0);

    return ~Chunk {
        x: chunk_x,
        z: chunk_z,
        map: map,
        vao: vao,
        vertex_buffer: vertex_buffer,
        normal_buffer: normal_buffer,
        element_buffer: element_buffer,
        num_elements: elements.len(),
        used_time: extra::time::precise_time_ns(),
    };
}

static face_elements : [GLuint, ..6] = [
    0, 1, 2, 3, 2, 1,
];

static faces : [Face, ..6] = [
    /* front */
    Face {
        normal: Vec3 { x: 0.0, y: 0.0, z: 1.0 },
        vertices: [
            Vec3 { x: 0.0, y: 0.0, z: 1.0 }, /* bottom left */
            Vec3 { x: 1.0, y: 0.0, z: 1.0 },  /* bottom right */
            Vec3 { x: 0.0, y: 1.0, z: 1.0 }, /* top left */
            Vec3 { x: 1.0, y: 1.0, z: 1.0 },  /* top right */
        ],
    },

    /* back */
    Face {
        normal: Vec3 { x: 0.0, y: 0.0, z: -1.0 },
        vertices: [
            Vec3 { x: 1.0, y: 0.0, z: 0.0 }, /* bottom right */
            Vec3 { x: 0.0, y: 0.0, z: 0.0 },  /* bottom left */
            Vec3 { x: 1.0, y: 1.0, z: 0.0 }, /* top right */
            Vec3 { x: 0.0, y: 1.0, z: 0.0 },  /* top left */
        ],
    },

    /* right */
    Face {
        normal: Vec3 { x: 1.0, y: 0.0, z: 0.0 },
        vertices: [
            Vec3 { x: 1.0, y: 0.0, z: 1.0 }, /* bottom front */
            Vec3 { x: 1.0, y: 0.0, z: 0.0 }, /* bottom back */
            Vec3 { x: 1.0, y: 1.0, z: 1.0 }, /* top front */
            Vec3 { x: 1.0, y: 1.0, z: 0.0 }, /* top back */
        ],
    },

    /* left */
    Face {
        normal: Vec3 { x: -1.0, y: 0.0, z: 0.0 },
        vertices: [
            Vec3 { x: 0.0, y: 0.0, z: 0.0 }, /* bottom back */
            Vec3 { x: 0.0, y: 0.0, z: 1.0 }, /* bottom front */
            Vec3 { x: 0.0, y: 1.0, z: 0.0 }, /* top back */
            Vec3 { x: 0.0, y: 1.0, z: 1.0 }, /* top front */
        ],
    },

    /* top */
    Face {
        normal: Vec3 { x: 0.0, y: 1.0, z: 0.0 },
        vertices: [
            Vec3 { x: 0.0, y: 1.0, z: 1.0 }, /* front left */
            Vec3 { x: 1.0, y: 1.0, z: 1.0 }, /* front right */
            Vec3 { x: 0.0, y: 1.0, z: 0.0 }, /* back left */
            Vec3 { x: 1.0, y: 1.0, z: 0.0 }, /* back right */
        ],
    },

    /* bottom */
    Face {
        normal: Vec3 { x: 0.0, y: -1.0, z: 0.0 },
        vertices: [
            Vec3 { x: 0.0, y: 0.0, z: 0.0 }, /* back left */
            Vec3 { x: 1.0, y: 0.0, z: 0.0 }, /* back right */
            Vec3 { x: 0.0, y: 0.0, z: 1.0 }, /* front left */
            Vec3 { x: 1.0, y: 0.0, z: 1.0 }, /* front right */
        ],
    },
];
<|endoftext|>


<commit_before>use std::io::{TempDir, MemWriter};
use std::str::from_utf8;
use schema;
use buffer;

#[deriving(Show, Eq, Hash)]
struct Register {
	record: schema::Record,
	datatype: schema::SqlType,
}

impl Register {
	fn new(rec: schema::Record, typ: schema::SqlType) -> Register {
		Register {
			record: rec,
			datatype: typ,
		}
	}

	fn set_int(&mut self, val: int) {
		// TODO
	}

	fn get_int(&self) -> int {
		self.record.to_int()
	}

	fn set_str(&mut self) {
		// TODO
	}

	fn get_str(&self) -> ~str {
		// TODO
		~"TODO"
	}
}

impl Ord for Register {
	fn lt(&self, other: &Register) -> bool {
		// not the most robust implementation
		self.get_int() < other.get_int()
	}
}

trait Operatorish<T>: Iterator<T> {
	//fn open();
	//fn close(&self);
}

struct TableScan<'a, 'b> {
	relation: schema::Relation,
	segment: &'a mut schema::SPSegment<'b>,
	current: uint,
}

impl<'a, 'b> TableScan<'a, 'b> {
	fn new(rel: schema::Relation, seg: &'a mut schema::SPSegment<'b>) -> TableScan<'a, 'b> {
		TableScan {
			relation: rel,
			segment: seg,
			current: 0,
		}
	}
}

impl<'a, 'b> Operatorish<Vec<Register>> for TableScan<'a, 'b> {
}

impl<'a, 'b> Iterator<Vec<Register>> for TableScan<'a, 'b> {
	fn next(&mut self) -> Option<Vec<Register>> {
		if (self.current as u64) < self.relation.inserted {
			let tup = self.relation.get(self.segment, self.current);
			let mut res = tup.move_iter().map(|(v, t)| Register::new(v, t)).
				collect::<Vec<Register>>();
			println!("res: {}", res);
			self.current += 1;
			Some(res)
		} else {
			None
		}
	}
}

struct Print<'a, T, V> {
	input: T,
	output: &'a mut V,
}

impl<'a, T: Operatorish<Vec<Register>>, V: Writer> Print<'a, T, V> {
	fn new(input: T, output: &'a mut V) -> Print<'a, T, V> {
		Print {
			input: input,
			output: output
		}
	}
}

impl<'a, T: Operatorish<Vec<Register>>, V: Writer> Iterator<Vec<Register>> for Print<'a, T, V> {
	fn next(&mut self) -> Option<Vec<Register>> {
		let cur = self.input.next();
		match cur {
			Some(reg) => {
				for item in reg.iter() {
					// TODO: construct string from result
					match item.datatype {
						schema::Varchar(_) => self.output.write(item.get_str().as_bytes()),
						schema::Integer => self.output.write("TODONUM".as_bytes())
					};
					self.output.write(", ".as_bytes());
				}
				self.output.write("\n".as_bytes());
				Some(reg)
			},
			None => None,
		}
	}
}

#[test]
fn simple_tablescan() {
	let dir = match TempDir::new("tablescan") {
		Some(temp_dir) => temp_dir,
		None => fail!("creation of temporary directory"),
	};

	//let p = dir.path();
	let p = Path::new(".");

	let mut manager = buffer::BufferManager::new(1024, p.clone());
	let mut seg = schema::SPSegment {id: 1, manager: &mut manager};

	let name = schema::Column::new(~"name", schema::Varchar(128), vec!(schema::NotNull));
	let age = schema::Column::new(~"age", schema::Integer, vec!(schema::NotNull));
	let mut relation = schema::Relation::new(~"Person");
	relation.add_column(name);
	relation.add_column(age);
	relation.insert(&mut seg, vec!(schema::Record::from_str(~"Alice"), schema::Record::from_int(20)));
	relation.insert(&mut seg, vec!(schema::Record::from_str(~"Bob"), schema::Record::from_int(40)));

	{
		let mut ts = TableScan::new(relation.clone(), &mut seg);
		for tuple in ts {
			println!("Got entry {}", tuple);
		}
	}

	let mut ts = TableScan::new(relation, &mut seg);
	let mut mw = MemWriter::new();
	{
		let mut pr = Print::new(ts, &mut mw);
		// force write by iterating, strange API
		for _ in pr {}
	}
	println!("Saved: {}", from_utf8(mw.unwrap()).unwrap());

	assert!(false);
}
<commit_msg>Printing integers works<commit_after>use std::io::{TempDir, MemWriter};
use std::str::from_utf8;
use schema;
use buffer;

#[deriving(Show, Eq, Hash)]
struct Register {
	record: schema::Record,
	datatype: schema::SqlType,
}

impl Register {
	fn new(rec: schema::Record, typ: schema::SqlType) -> Register {
		Register {
			record: rec,
			datatype: typ,
		}
	}

	fn set_int(&mut self, val: int) {
		// TODO
	}

	fn get_int(&self) -> int {
		self.record.to_int()
	}

	fn set_str(&mut self) {
		// TODO
	}

	fn get_str(&self) -> ~str {
		// TODO
		~"TODO"
	}
}

impl Ord for Register {
	fn lt(&self, other: &Register) -> bool {
		// not the most robust implementation
		self.get_int() < other.get_int()
	}
}

trait Operatorish<T>: Iterator<T> {
	//fn open();
	//fn close(&self);
}

struct TableScan<'a, 'b> {
	relation: schema::Relation,
	segment: &'a mut schema::SPSegment<'b>,
	current: uint,
}

impl<'a, 'b> TableScan<'a, 'b> {
	fn new(rel: schema::Relation, seg: &'a mut schema::SPSegment<'b>) -> TableScan<'a, 'b> {
		TableScan {
			relation: rel,
			segment: seg,
			current: 0,
		}
	}
}

impl<'a, 'b> Operatorish<Vec<Register>> for TableScan<'a, 'b> {
}

impl<'a, 'b> Iterator<Vec<Register>> for TableScan<'a, 'b> {
	fn next(&mut self) -> Option<Vec<Register>> {
		if (self.current as u64) < self.relation.inserted {
			let tup = self.relation.get(self.segment, self.current);
			let mut res = tup.move_iter().map(|(v, t)| Register::new(v, t)).
				collect::<Vec<Register>>();
			println!("res: {}", res);
			self.current += 1;
			Some(res)
		} else {
			None
		}
	}
}

struct Print<'a, T, V> {
	input: T,
	output: &'a mut V,
}

impl<'a, T: Operatorish<Vec<Register>>, V: Writer> Print<'a, T, V> {
	fn new(input: T, output: &'a mut V) -> Print<'a, T, V> {
		Print {
			input: input,
			output: output
		}
	}
}

impl<'a, T: Operatorish<Vec<Register>>, V: Writer> Iterator<Vec<Register>> for Print<'a, T, V> {
	fn next(&mut self) -> Option<Vec<Register>> {
		let cur = self.input.next();
		match cur {
			Some(reg) => {
				for item in reg.iter() {
					// TODO: construct string from result
					match item.datatype {
						schema::Varchar(_) => self.output.write(item.get_str().as_bytes()),
						schema::Integer => self.output.write(
							format!("{}", item.get_int()).as_bytes())
					};
					self.output.write(", ".as_bytes());
				}
				self.output.write("\n".as_bytes());
				Some(reg)
			},
			None => None,
		}
	}
}

#[test]
fn simple_tablescan() {
	let dir = match TempDir::new("tablescan") {
		Some(temp_dir) => temp_dir,
		None => fail!("creation of temporary directory"),
	};

	//let p = dir.path();
	let p = Path::new(".");

	let mut manager = buffer::BufferManager::new(1024, p.clone());
	let mut seg = schema::SPSegment {id: 1, manager: &mut manager};

	let name = schema::Column::new(~"name", schema::Varchar(128), vec!(schema::NotNull));
	let age = schema::Column::new(~"age", schema::Integer, vec!(schema::NotNull));
	let mut relation = schema::Relation::new(~"Person");
	relation.add_column(name);
	relation.add_column(age);
	relation.insert(&mut seg, vec!(schema::Record::from_str(~"Alice"), schema::Record::from_int(20)));
	relation.insert(&mut seg, vec!(schema::Record::from_str(~"Bob"), schema::Record::from_int(40)));

	{
		let mut ts = TableScan::new(relation.clone(), &mut seg);
		for tuple in ts {
			println!("Got entry {}", tuple);
		}
	}

	let mut ts = TableScan::new(relation, &mut seg);
	let mut mw = MemWriter::new();
	{
		let mut pr = Print::new(ts, &mut mw);
		// force write by iterating, strange API
		for _ in pr {}
	}
	println!("Saved: {}", from_utf8(mw.unwrap()).unwrap());

	assert!(false);
}
<|endoftext|>