<commit_before>#![feature(slice_patterns)]
#![feature(path_ext)]
extern crate eve;
extern crate hyper;
extern crate cookie;
extern crate mime;
extern crate url;
extern crate websocket;
extern crate rustc_serialize;
extern crate conduit_mime_types;

use std::io::Read;
use std::io::Write;
use std::fs::File;
use std::error::Error;
use hyper::net::Fresh;
use hyper::server::{Server, Request, Response};
use hyper::uri::RequestUri;
use hyper::Url;
use hyper::header::{Headers,ContentType,Location,SetCookie};
use cookie::Cookie;
use mime::Mime;
use url::SchemeData::Relative;
use rustc_serialize::json;
use websocket::{Message, Sender};
use std::path::Path;
use std::fs::PathExt;
use conduit_mime_types::Types;
use std::str::FromStr;

use eve::client::*;
use eve::server;
use eve::value::Value;

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
struct Session {
	client: String,
	id: String,
	user_id: String,
	object: String,
	created_at: f64,
	expires_at: f64,
	ip: String,
	user: User,
}

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
struct User {
	custom: Custom,
	id: String,
	realm_id: String,
	username: String,
	state: String,
	user_type: String,
	reference: Option<String>,
	name: String,
	email: String,
	object: String,
	last_login_at: f64,
	last_login_on: f64,
	created_at: f64,
	first_name: Option<String>,
	last_name: Option<String>,
	credentials: Vec<Credential>,
	membership_count: f64,
}

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
struct Custom;

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
struct Credential {
	id: String,
	credential_type: String,
	object: String,
}

fn main() {

    // TODO high thread-count is a workaround for https://github.com/hyperium/hyper/issues/368
	Server::http("0.0.0.0:8080").unwrap().handle_threads(login, 100).unwrap();
}

fn read_file_bytes(filename: &str) -> Vec<u8> {
    let mut file = File::open(&filename).unwrap();
    let mut contents: Vec<u8> = Vec::new();
	file.read_to_end(&mut contents).unwrap();
	contents
}

fn file_exists(path: &str) -> bool {
	let path_obj = Path::new(path);
	path_obj.is_file() && path_obj.exists()
}

fn serve_local_or_file(mut res: Response<Fresh>, path: &Vec<String>, default_file: &str) {
	let mime_types = Types::new().unwrap();
	let local_path = path[1..].iter().fold("../ui".to_owned(), |end, cur| end + "/" + cur);
	let file;
	let file_path: &str;
	if file_exists(&local_path) {
		file = read_file_bytes(&local_path);
		file_path = &local_path;
	} else {
		let content = read_file_bytes(default_file);
		//@HACK, @TODO: absolutize the html file so that it looks in the right place
		//this allows us to use file:/// locally, while still doing the right thing
		//when we're hooked up to the server
		let mut str = String::from_utf8(content).unwrap();
		str = str.replace("href=\"", "href=\"/app/");
		str = str.replace("src=\"", "src=\"/app/");
		str = str.replace("/app/http", "http");
		file = str.as_bytes().to_owned();
		file_path = default_file;
	}
	let mime: Mime = Mime::from_str(mime_types.mime_for_path(Path::new(&file_path))).unwrap();
	res.headers_mut().set(ContentType(mime));
	let mut res = res.start().unwrap();
	res.write_all(&file).unwrap();
	res.end().unwrap();
}

fn login(req: Request, mut res: Response<Fresh>) {

	match (&req.method.clone(), &req.uri.clone()) {
		(&hyper::Get, &RequestUri::AbsolutePath(ref relative_path)) => {

			// Form a url from the path
			let absolute_path = "http://localhost".to_string() + relative_path;
			let url = Url::parse(&*absolute_path).unwrap();

			// Get the file name
			let scheme_data = &url.scheme_data;

			let requested_file = match scheme_data {
				&Relative(ref rsd) => rsd.path[0].clone(),
				_ => panic!("Expected relative path"),
			};
			let path_info = match scheme_data {
				&Relative(ref rsd) => rsd,
				_ => panic!("Expected relative path"),
			};

			// Parse the query string
			let query_pairs = &url.query_pairs();

			// Handle login
			match &*requested_file {
				"app.html" | "app" => {
					serve_local_or_file(res, &path_info.path, "../ui/app.html");
				},
				"editor.html" | "editor" => {
					serve_local_or_file(res, &path_info.path, "../ui/editor.html");
				},
				"login.html" => {
					println!("Authenticating User");
					let pairs = query_pairs.clone().unwrap();
					match &pairs[..] {
						[(_ , ref page), (ref token_type, ref token), ..] if token_type.clone() == "token".to_string() => {

							// We have a login token, now to authenticate
							let client = hyper::client::Client::new();
							let api_call = "https://api-e1.authrocket.com/v1/sessions/".to_string() + token;
							let req = client.request(hyper::method::Method::Get,&*api_call);

							// Set the appropriate headers for authorocket
							let mut headers = Headers::new();
							let json: Mime = "application/json".parse().unwrap();
							let content_type = ContentType(json);
							headers.set_raw("X-Authrocket-Account",vec!["org_0vC7wPw9XphPGQnSqYB6bz".to_string().into_bytes()]);
							headers.set_raw("X-Authrocket-Api-Key",vec!["key_jtnCRWxQvDD0p5HATR9RBIe4WnxnwV6pWNzwmZQLnSZ".to_string().into_bytes()]);
							headers.set_raw("X-Authrocket-Realm",vec!["rl_0vC7wd03CqwhpK7kT8fvAc".to_string().into_bytes()]);
							headers.set_raw("Accept",vec!["application/json".to_string().into_bytes()]);
							headers.set(content_type);

							// Send the request and receive a response with session data
							let mut client_res = req.headers(headers).send().unwrap();

							match client_res.status_raw() {

								&hyper::http::RawStatus(200,_) => {

									let mut body = String::new();
									client_res.read_to_string(&mut body).unwrap();
									let session_data: Session = json::decode(&body).unwrap();
									println!("Welcome to Eve, {:?}!",session_data.user.username);
									println!("Login Successful. Redirecting to user area.");

									// Connect to the Eve runtime and add the user to the eveusers table
									let ws_result = open_websocket("ws://0.0.0.0:2794");
									match ws_result {
										// If things went okay, redirect to the Eve UI
										Ok(mut sender) => {
											// Form the response
											*res.status_mut() = hyper::status::StatusCode::PermanentRedirect;

											// Form the response headers
											let mut headers = Headers::new();
											let location = Location("/".to_string() + page);
											let user_cookie = Cookie::new("userid".to_string(),session_data.user.id.clone());
											let cookies = SetCookie(vec![user_cookie]);
											headers.set(location);
											headers.set(cookies);
											*res.headers_mut() = headers;

											// Create eveusers table and insert the new user
											let table_name = "eveusers";
											let table_fields = vec!["id","username"];

											let row_data = vec![
																Value::String(session_data.user.id.clone()),
																Value::String(session_data.user.username.clone())
														   	   ];
											let insert_user = insert_fact(&table_name,&table_fields,&row_data,None);
											send_event(&insert_user,&mut sender);
											let _ = sender.send_message(Message::Close(None));
										}
										// Otherwise, throw an error... maybe redirect to a special page.
										Err(e) => {
											println!("ERROR: Had trouble connecting to the Eve runtime: {}. Is the server running?",e);
											*res.status_mut() = hyper::status::StatusCode::NotFound;
											panic!("Oh no!");
											//serve_file("404.html",res);
										}
									}

									println!("Login complete.");
								}
								_ => {
									println!("ERROR: Could not authenticate user with token {}",token);
									*res.status_mut() = hyper::status::StatusCode::Forbidden;
									panic!("Oh no!");
									//serve_file("404.html",res);
								}
							};
						},
						_ => panic!("Oh no!"), //serve_file("404.html",res),
					}
				},
				"logout.html" => {
					println!("Logging out...");
					let user_id = server::get_user_id(req.headers.get::<hyper::header::Cookie>());
                	println!("{:?}",user_id);
				},
				"favicon.ico" => (),
				other => panic!("Cannot serve {}",other), //serve_file(&*requested_file,res),
			};
		}
		_ => panic!("Oh no!"),
	}
}<commit_msg>Redirect the user to the correct address whether the server is running local or behind a webserver.<commit_after>#![feature(slice_patterns)]
#![feature(path_ext)]
extern crate eve;
extern crate hyper;
extern crate cookie;
extern crate mime;
extern crate url;
extern crate websocket;
extern crate rustc_serialize;
extern crate conduit_mime_types;

use std::io::Read;
use std::io::Write;
use std::fs::File;
use std::error::Error;
use hyper::net::Fresh;
use hyper::server::{Server, Request, Response};
use hyper::uri::RequestUri;
use hyper::Url;
use hyper::header::{Headers,ContentType,Location,SetCookie};
use cookie::Cookie;
use mime::Mime;
use url::SchemeData::Relative;
use rustc_serialize::json;
use websocket::{Message, Sender};
use std::path::Path;
use std::fs::PathExt;
use conduit_mime_types::Types;
use std::str::FromStr;
use std::env;

use eve::client::*;
use eve::server;
use eve::value::Value;

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
struct Session {
	client: String,
	id: String,
	user_id: String,
	object: String,
	created_at: f64,
	expires_at: f64,
	ip: String,
	user: User,
}

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
struct User {
	custom: Custom,
	id: String,
	realm_id: String,
	username: String,
	state: String,
	user_type: String,
	reference: Option<String>,
	name: String,
	email: String,
	object: String,
	last_login_at: f64,
	last_login_on: f64,
	created_at: f64,
	first_name: Option<String>,
	last_name: Option<String>,
	credentials: Vec<Credential>,
	membership_count: f64,
}

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
struct Custom;

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
struct Credential {
	id: String,
	credential_type: String,
	object: String,
}

fn main() {

    // TODO high thread-count is a workaround for https://github.com/hyperium/hyper/issues/368
	Server::http("0.0.0.0:8080").unwrap().handle_threads(login, 100).unwrap();
}

fn read_file_bytes(filename: &str) -> Vec<u8> {
    let mut file = File::open(&filename).unwrap();
    let mut contents: Vec<u8> = Vec::new();
	file.read_to_end(&mut contents).unwrap();
	contents
}

fn file_exists(path: &str) -> bool {
	let path_obj = Path::new(path);
	path_obj.is_file() && path_obj.exists()
}

fn serve_local_or_file(mut res: Response<Fresh>, path: &Vec<String>, default_file: &str) {
	let mime_types = Types::new().unwrap();
	let local_path = path[1..].iter().fold("../ui".to_owned(), |end, cur| end + "/" + cur);
	let file;
	let file_path: &str;
	if file_exists(&local_path) {
		file = read_file_bytes(&local_path);
		file_path = &local_path;
	} else {
		let content = read_file_bytes(default_file);
		//@HACK, @TODO: absolutize the html file so that it looks in the right place
		//this allows us to use file:/// locally, while still doing the right thing
		//when we're hooked up to the server
		let mut str = String::from_utf8(content).unwrap();
		str = str.replace("href=\"", "href=\"/app/");
		str = str.replace("src=\"", "src=\"/app/");
		str = str.replace("/app/http", "http");
		file = str.as_bytes().to_owned();
		file_path = default_file;
	}
	let mime: Mime = Mime::from_str(mime_types.mime_for_path(Path::new(&file_path))).unwrap();
	res.headers_mut().set(ContentType(mime));
	let mut res = res.start().unwrap();
	res.write_all(&file).unwrap();
	res.end().unwrap();
}

fn login(req: Request, mut res: Response<Fresh>) {

	// Don't use a port if we're running in local mode
	let mut port = ":8000";
	for argument in env::args() {
    	match &*argument {
    		"local" => {
    			port = "";
    		},
    		_ => continue,
    	}
	}

	match (&req.method.clone(), &req.uri.clone()) {
		(&hyper::Get, &RequestUri::AbsolutePath(ref relative_path)) => {

			// Form a url from the path
			let absolute_path = "http://localhost".to_string() + relative_path;
			let url = Url::parse(&*absolute_path).unwrap();

			// Get the file name
			let scheme_data = &url.scheme_data;

			let requested_file = match scheme_data {
				&Relative(ref rsd) => rsd.path[0].clone(),
				_ => panic!("Expected relative path"),
			};
			let path_info = match scheme_data {
				&Relative(ref rsd) => rsd,
				_ => panic!("Expected relative path"),
			};

			// Parse the query string
			let query_pairs = &url.query_pairs();

			// Handle login
			match &*requested_file {
				"app.html" | "app" => {
					serve_local_or_file(res, &path_info.path, "../ui/app.html");
				},
				"editor.html" | "editor" => {
					serve_local_or_file(res, &path_info.path, "../ui/editor.html");
				},
				"login.html" => {
					println!("Authenticating User");

					let referer = format!("{}",req.headers.get::<hyper::header::Referer>().unwrap());
					let referer_url = Url::parse(&*referer).unwrap();

					let pairs = query_pairs.clone().unwrap();
					match &pairs[..] {
						[(_ , ref page), (ref token_type, ref token), ..] if token_type.clone() == "token".to_string() => {

							// We have a login token, now to authenticate
							let client = hyper::client::Client::new();
							let api_call = "https://api-e1.authrocket.com/v1/sessions/".to_string() + token;
							let req = client.request(hyper::method::Method::Get,&*api_call);

							// Set the appropriate headers for authorocket
							let mut headers = Headers::new();
							let json: Mime = "application/json".parse().unwrap();
							let content_type = ContentType(json);
							headers.set_raw("X-Authrocket-Account",vec!["org_0vC7wPw9XphPGQnSqYB6bz".to_string().into_bytes()]);
							headers.set_raw("X-Authrocket-Api-Key",vec!["key_jtnCRWxQvDD0p5HATR9RBIe4WnxnwV6pWNzwmZQLnSZ".to_string().into_bytes()]);
							headers.set_raw("X-Authrocket-Realm",vec!["rl_0vC7wd03CqwhpK7kT8fvAc".to_string().into_bytes()]);
							headers.set_raw("Accept",vec!["application/json".to_string().into_bytes()]);
							headers.set(content_type);

							// Send the request and receive a response with session data
							let mut client_res = req.headers(headers).send().unwrap();

							match client_res.status_raw() {

								&hyper::http::RawStatus(200,_) => {

									let mut body = String::new();
									client_res.read_to_string(&mut body).unwrap();
									let session_data: Session = json::decode(&body).unwrap();
									println!("Welcome to Eve, {:?}!",session_data.user.username);
									println!("Login Successful. Redirecting to user area.");

									// Connect to the Eve runtime and add the user to the eveusers table
									let ws_result = open_websocket("ws://0.0.0.0:2794");
									match ws_result {
										// If things went okay, redirect to the Eve UI
										Ok(mut sender) => {
											// Form the response
											*res.status_mut() = hyper::status::StatusCode::PermanentRedirect;

											// Form the response headers
											let mut headers = Headers::new();
														//let foo = req.headers.get::<hyper::header::Host>();
											let redirect_url = referer_url.scheme.clone() + "://" + referer_url.domain().unwrap().clone() + port + "/" + page;
											let location = Location(redirect_url);
											//let location = Location("http://192.168.106.142:8000/editor".to_owned());
											//headers.set(Host{hostname:"192.168.106.142".to_owned(),port:Some(8000)});
											let user_cookie = Cookie::new("userid".to_string(),session_data.user.id.clone());
											let cookies = SetCookie(vec![user_cookie]);
											headers.set(location);
											headers.set(cookies);
											*res.headers_mut() = headers;

											// Create eveusers table and insert the new user
											let table_name = "eveusers";
											let table_fields = vec!["id","username"];

											let row_data = vec![
																Value::String(session_data.user.id.clone()),
																Value::String(session_data.user.username.clone())
														   	   ];
											let insert_user = insert_fact(&table_name,&table_fields,&row_data,None);
											send_event(&insert_user,&mut sender);
											let _ = sender.send_message(Message::Close(None));
										}
										// Otherwise, throw an error... maybe redirect to a special page.
										Err(e) => {
											println!("ERROR: Had trouble connecting to the Eve runtime: {}. Is the server running?",e);
											*res.status_mut() = hyper::status::StatusCode::NotFound;
											panic!("Oh no!");
											//serve_file("404.html",res);
										}
									}

									println!("Login complete.");
								}
								_ => {
									println!("ERROR: Could not authenticate user with token {}",token);
									*res.status_mut() = hyper::status::StatusCode::Forbidden;
									panic!("Oh no!");
									//serve_file("404.html",res);
								}
							};
						},
						_ => panic!("Oh no!"), //serve_file("404.html",res),
					}
				},
				"logout.html" => {
					println!("Logging out...");
					let user_id = server::get_user_id(req.headers.get::<hyper::header::Cookie>());
                	println!("{:?}",user_id);
				},
				"favicon.ico" => (),
				other => panic!("Cannot serve {}",other), //serve_file(&*requested_file,res),
			};
		}
		_ => panic!("Oh no!"),
	}
}<|endoftext|>


<commit_before>/*
Rust Hello World
Copyright 2016, Sjors van Gelderen
 */

fn main() {
    println!("Hello, world!");
}
<commit_msg>Delete main.rs<commit_after><|endoftext|>


<commit_before> #![feature(augmented_assignments)]

extern crate cgmath;
extern crate docopt;
#[macro_use]
extern crate glium;
extern crate rand;
extern crate rayon;
extern crate rustc_serialize;
extern crate time;

use docopt::Docopt;
use rand::{SeedableRng, XorShiftRng};

mod nbody;
mod visualize;
use self::visualize::visualize_benchmarks;
use self::nbody::NBodyBenchmark;

const USAGE: &'static str = "
Usage: nbody bench [--mode MODE --bodies N --ticks N]
       nbody visualize [--mode MODE --bodies N]
       nbody --help

Commands:
    bench              Run the benchmark and print the timings.
    visualize          Show the graphical visualizer.

Options:
    -h, --help         Show this message.
    --mode MODE        Execution mode for the benchmark/visualizer.
    --bodies N         Use N bodies [default: 4000].
    --ticks N          Simulate for N ticks [default: 100].
";

#[derive(Copy, Clone, PartialEq, Eq, RustcDecodable)]
pub enum ExecutionMode {
    Par,
    ParReduce,
    Seq,
}

#[derive(RustcDecodable)]
pub struct Args {
    cmd_bench: bool,
    cmd_visualize: bool,
    flag_mode: Option<ExecutionMode>,
    flag_bodies: usize,
    flag_ticks: usize,
}

fn main() {
    let args: Args =
        Docopt::new(USAGE)
            .and_then(|d| d.decode())
            .unwrap_or_else(|e| e.exit());

    if args.cmd_bench {
        run_benchmarks(args.flag_mode, args.flag_bodies, args.flag_ticks);
    }

    if args.cmd_visualize {
        visualize_benchmarks(args.flag_bodies,
                             args.flag_mode.unwrap_or(ExecutionMode::Par));
    }
}

fn run_benchmarks(mode: Option<ExecutionMode>, bodies: usize, ticks: usize) {
    let run_par = mode.map(|m| m == ExecutionMode::Par).unwrap_or(true);
    let run_par_reduce = mode.map(|m| m == ExecutionMode::ParReduce).unwrap_or(true);
    let run_seq = mode.map(|m| m == ExecutionMode::Seq).unwrap_or(true);

    let par_time = if run_par {
        let mut rng = XorShiftRng::from_seed([0, 1, 2, 3]);
        let mut benchmark = NBodyBenchmark::new(bodies, &mut rng);
        let par_start = time::precise_time_ns();

        for _ in 0..ticks {
            benchmark.tick_par();
        }

        let par_time = time::precise_time_ns() - par_start;
        println!("Parallel time   : {}", par_time);

        Some(par_time)
    } else {
        None
    };

    let par_reduce_time = if run_par_reduce {
        let mut rng = XorShiftRng::from_seed([0, 1, 2, 3]);
        let mut benchmark = NBodyBenchmark::new(bodies, &mut rng);
        let par_start = time::precise_time_ns();

        for _ in 0..ticks {
            benchmark.tick_par_reduce();
        }

        let par_time = time::precise_time_ns() - par_start;
        println!("ParReduce time  : {}", par_time);

        Some(par_time)
    } else {
        None
    };

    let seq_time = if run_seq {
        let mut rng = XorShiftRng::from_seed([0, 1, 2, 3]);
        let mut benchmark = NBodyBenchmark::new(bodies, &mut rng);
        let seq_start = time::precise_time_ns();

        for _ in 0..ticks {
            benchmark.tick_seq();
        }

        let seq_time = time::precise_time_ns() - seq_start;
        println!("Sequential time : {}", seq_time);

        Some(seq_time)
    } else {
        None
    };

    if let (Some(pt), Some(st)) = (par_time, seq_time) {
        println!("Parallel speedup: {}", (st as f32) / (pt as f32));
    }

    if let (Some(pt), Some(st)) = (par_reduce_time, seq_time) {
        println!("Parallel reduce speedup: {}", (st as f32) / (pt as f32));
    }
}
<commit_msg>Make the colons line up in benchmark output<commit_after> #![feature(augmented_assignments)]

extern crate cgmath;
extern crate docopt;
#[macro_use]
extern crate glium;
extern crate rand;
extern crate rayon;
extern crate rustc_serialize;
extern crate time;

use docopt::Docopt;
use rand::{SeedableRng, XorShiftRng};

mod nbody;
mod visualize;
use self::visualize::visualize_benchmarks;
use self::nbody::NBodyBenchmark;

const USAGE: &'static str = "
Usage: nbody bench [--mode MODE --bodies N --ticks N]
       nbody visualize [--mode MODE --bodies N]
       nbody --help

Commands:
    bench              Run the benchmark and print the timings.
    visualize          Show the graphical visualizer.

Options:
    -h, --help         Show this message.
    --mode MODE        Execution mode for the benchmark/visualizer.
    --bodies N         Use N bodies [default: 4000].
    --ticks N          Simulate for N ticks [default: 100].
";

#[derive(Copy, Clone, PartialEq, Eq, RustcDecodable)]
pub enum ExecutionMode {
    Par,
    ParReduce,
    Seq,
}

#[derive(RustcDecodable)]
pub struct Args {
    cmd_bench: bool,
    cmd_visualize: bool,
    flag_mode: Option<ExecutionMode>,
    flag_bodies: usize,
    flag_ticks: usize,
}

fn main() {
    let args: Args =
        Docopt::new(USAGE)
            .and_then(|d| d.decode())
            .unwrap_or_else(|e| e.exit());

    if args.cmd_bench {
        run_benchmarks(args.flag_mode, args.flag_bodies, args.flag_ticks);
    }

    if args.cmd_visualize {
        visualize_benchmarks(args.flag_bodies,
                             args.flag_mode.unwrap_or(ExecutionMode::Par));
    }
}

fn run_benchmarks(mode: Option<ExecutionMode>, bodies: usize, ticks: usize) {
    let run_par = mode.map(|m| m == ExecutionMode::Par).unwrap_or(true);
    let run_par_reduce = mode.map(|m| m == ExecutionMode::ParReduce).unwrap_or(true);
    let run_seq = mode.map(|m| m == ExecutionMode::Seq).unwrap_or(true);

    let par_time = if run_par {
        let mut rng = XorShiftRng::from_seed([0, 1, 2, 3]);
        let mut benchmark = NBodyBenchmark::new(bodies, &mut rng);
        let par_start = time::precise_time_ns();

        for _ in 0..ticks {
            benchmark.tick_par();
        }

        let par_time = time::precise_time_ns() - par_start;
        println!("Parallel time    : {}", par_time);

        Some(par_time)
    } else {
        None
    };

    let par_reduce_time = if run_par_reduce {
        let mut rng = XorShiftRng::from_seed([0, 1, 2, 3]);
        let mut benchmark = NBodyBenchmark::new(bodies, &mut rng);
        let par_start = time::precise_time_ns();

        for _ in 0..ticks {
            benchmark.tick_par_reduce();
        }

        let par_time = time::precise_time_ns() - par_start;
        println!("ParReduce time   : {}", par_time);

        Some(par_time)
    } else {
        None
    };

    let seq_time = if run_seq {
        let mut rng = XorShiftRng::from_seed([0, 1, 2, 3]);
        let mut benchmark = NBodyBenchmark::new(bodies, &mut rng);
        let seq_start = time::precise_time_ns();

        for _ in 0..ticks {
            benchmark.tick_seq();
        }

        let seq_time = time::precise_time_ns() - seq_start;
        println!("Sequential time  : {}", seq_time);

        Some(seq_time)
    } else {
        None
    };

    if let (Some(pt), Some(st)) = (par_time, seq_time) {
        println!("Parallel speedup : {}", (st as f32) / (pt as f32));
    }

    if let (Some(pt), Some(st)) = (par_reduce_time, seq_time) {
        println!("ParReduce speedup: {}", (st as f32) / (pt as f32));
    }
}
<|endoftext|>


<commit_before>/// TextStyle holds the displayed attributes flags.
#[derive(Debug, Default, Hash, Clone, Copy, Eq, PartialEq)]
pub struct TextStyle {
    /// The character should blink.
    pub is_blinking: bool,
    /// The character is a part of a selection.
    pub is_selected: bool,
    /// The fg/bg attributes are reversed (used to simulate cursors/marks).
    pub is_inverse: bool,
    /// The character should be displayed as bold.
    pub is_bold: bool,
    /// The character should be displayed in italic.
    pub is_italic: bool,
    /// rbg tuple for foreground color
    pub color: (u8, u8, u8), // RGB
    /// rbg tuple for background color
    pub bg_color: (u8, u8, u8), // RGB
}

impl TextStyle {
    pub fn new() -> Self {
        TextStyle {
            is_blinking: false,
            is_selected: false,
            is_inverse: false,
            is_bold: false,
            is_italic: false,
            color: Self::default_color(),
            bg_color: Self::default_bg_color(),
        }
    }

    pub fn default_color() -> (u8, u8, u8) {
        // (192, 192, 192) // White
        // (128, 128, 128)    // Gray
        //(177, 177, 177)

        // (160, 160, 160)

        // (180, 180, 180)

        (199, 199, 199)
    }

    pub fn default_bg_color() -> (u8, u8, u8) {
        // (40, 44, 52) // soft grey
        // (11, 16, 39) // deep blue
        (35, 35, 35)    // black
    }

    pub fn title_color() -> (u8, u8, u8) {
        Self::default_bg_color()
    }

    pub fn title_bg_color() -> (u8, u8, u8) {
        Self::default_color()
    }

    pub fn default_selected_bg_color() -> (u8, u8, u8) {
        Self::default_mark_line_bg_color()
    }

    pub fn default_mark_line_bg_color() -> (u8, u8, u8) {
        let sbg = Self::default_bg_color();

        let add = 20;
        (
            sbg.0.saturating_add(add),
            sbg.1.saturating_add(add),
            sbg.2.saturating_add(add),
        )

        // let sub = 7;
        // (sbg.0.saturating_sub(sub), sbg.1.saturating_sub(sub), sbg.2.saturating_sub(sub))
    }
}

/// A CodepointInfo contains displayed character attributes.

/// The displayed screen is composed of LineCell(s), that contain CodepointInfo(s).
#[derive(Hash, Default, Debug, Clone, Copy, Eq, PartialEq)]
pub struct CodepointInfo {
    /// Ignore this CodepointInfo if set to false.
    pub used: bool, // rename into ignore ?
    /// The CodepointInfo is some part metadata.

    /// When set to true offset must be set to None
    pub metadata: bool, // TODO(ceg): prefer enum use enum { Normal, Eof, ... }
    /// The real codepoint found on storage
    pub cp: char,
    /// The codepoint to display
    pub displayed_cp: char,
    /// Storage offset
    pub offset: Option<u64>,
    /// Storage size in bytes
    pub size: usize,
    /// Hints for render
    pub skip_render: bool,
    /// Style to apply when rendering
    pub style: TextStyle,
}

impl CodepointInfo {
    pub fn new() -> Self {
        CodepointInfo {
            used: false,
            metadata: true,
            cp: ' ',
            displayed_cp: ' ',
            offset: None,
            size: 0,
            skip_render: false,
            //
            style: TextStyle::new(),
        }
    }
}

/*
Logical Color	Terminal Color	RGB Value Used by SGD
Black	0 0 0
Light_red	255 0 0
Light_green	0 255 0
Yellow	255 255 0
Light_blue	0 0 255
Light_magenta	255 0 255
Light_cyan	    0 255 255
High_white	    255 255 255
Gray	    128 128 128
Red	    128 0 0
Green	0 128 0
Brown	128 128 0
Blue	0 0 128
Magenta	128 0 128
Cyan	0 128 128
White	192 192 192
*/
<commit_msg>work on colors<commit_after>/// TextStyle holds the displayed attributes flags.
#[derive(Debug, Default, Hash, Clone, Copy, Eq, PartialEq)]
pub struct TextStyle {
    /// The character should blink.
    pub is_blinking: bool,
    /// The character is a part of a selection.
    pub is_selected: bool,
    /// The fg/bg attributes are reversed (used to simulate cursors/marks).
    pub is_inverse: bool,
    /// The character should be displayed as bold.
    pub is_bold: bool,
    /// The character should be displayed in italic.
    pub is_italic: bool,
    /// rbg tuple for foreground color
    pub color: (u8, u8, u8), // RGB
    /// rbg tuple for background color
    pub bg_color: (u8, u8, u8), // RGB
}

impl TextStyle {
    pub fn new() -> Self {
        TextStyle {
            is_blinking: false,
            is_selected: false,
            is_inverse: false,
            is_bold: false,
            is_italic: false,
            color: Self::default_color(),
            bg_color: Self::default_bg_color(),
        }
    }

    pub fn default_color() -> (u8, u8, u8) {
        // (192, 192, 192) // White
        // (128, 128, 128)    // Gray
        //(177, 177, 177)

        // (160, 160, 160)

        // (180, 180, 180)

        (199, 199, 199)
    }

    pub fn default_bg_color() -> (u8, u8, u8) {
        // (40, 44, 52) // soft grey
        (11, 16, 39) // deep blue
        // (35, 35, 35)    // black
    }

    pub fn title_color() -> (u8, u8, u8) {
        Self::default_bg_color()
    }

    pub fn title_bg_color() -> (u8, u8, u8) {
        Self::default_color()
    }

    pub fn default_selected_bg_color() -> (u8, u8, u8) {
        let c = Self::default_mark_line_bg_color();

        let add_r = 50;
        let add_g = 5;
        let add_b = 35;

        (
            c.0.saturating_add(add_r),
            c.1.saturating_add(add_g),
            c.2.saturating_add(add_b),
        )
    }

    pub fn default_mark_line_bg_color() -> (u8, u8, u8) {
        let sbg = Self::default_bg_color();

        let add = 20;
        (
            sbg.0.saturating_add(add),
            sbg.1.saturating_add(add),
            sbg.2.saturating_add(add),
        )

        // let sub = 7;
        // (sbg.0.saturating_sub(sub), sbg.1.saturating_sub(sub), sbg.2.saturating_sub(sub))
    }
}

/// A CodepointInfo contains displayed character attributes.

/// The displayed screen is composed of LineCell(s), that contain CodepointInfo(s).
#[derive(Hash, Default, Debug, Clone, Copy, Eq, PartialEq)]
pub struct CodepointInfo {
    /// Ignore this CodepointInfo if set to false.
    pub used: bool, // rename into ignore ?
    /// The CodepointInfo is some part metadata.

    /// When set to true offset must be set to None
    pub metadata: bool, // TODO(ceg): prefer enum use enum { Normal, Eof, ... }
    /// The real codepoint found on storage
    pub cp: char,
    /// The codepoint to display
    pub displayed_cp: char,
    /// Storage offset
    pub offset: Option<u64>,
    /// Storage size in bytes
    pub size: usize,
    /// Hints for render
    pub skip_render: bool,
    /// Style to apply when rendering
    pub style: TextStyle,
}

impl CodepointInfo {
    pub fn new() -> Self {
        CodepointInfo {
            used: false,
            metadata: true,
            cp: ' ',
            displayed_cp: ' ',
            offset: None,
            size: 0,
            skip_render: false,
            //
            style: TextStyle::new(),
        }
    }
}

/*
Logical Color	Terminal Color	RGB Value Used by SGD
Black	0 0 0
Light_red	255 0 0
Light_green	0 255 0
Yellow	255 255 0
Light_blue	0 0 255
Light_magenta	255 0 255
Light_cyan	    0 255 255
High_white	    255 255 255
Gray	    128 128 128
Red	    128 0 0
Green	0 128 0
Brown	128 128 0
Blue	0 0 128
Magenta	128 0 128
Cyan	0 128 128
White	192 192 192
*/
<|endoftext|>


<commit_before>#![crate_name = "fold"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Arcterus <arcterus@mail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

#![feature(macro_rules)]

extern crate getopts;
extern crate libc;

use std::io;
use std::io::fs::File;
use std::io::BufferedReader;

#[path = "../common/util.rs"]
mod util;

static NAME: &'static str = "fold";
static VERSION: &'static str = "1.0.0";

pub fn uumain(args: Vec<String>) -> int {
    let (args, obs_width) = handle_obsolete(args.as_slice());
    let program = args[0].clone();

    let opts = [
        getopts::optflag("b", "bytes", "count using bytes rather than columns (meaning control characters such as newline are not treated specially)"),
        getopts::optflag("s", "spaces", "break lines at word boundaries rather than a hard cut-off"),
        getopts::optopt("w", "width", "set WIDTH as the maximum line width rather than 80", "WIDTH"),
        getopts::optflag("h", "help", "display this help and exit"),
        getopts::optflag("V", "version", "output version information and exit")
    ];

    let matches = match getopts::getopts(args.tail(), &opts) {
        Ok(m) => m,
        Err(f) => crash!(1, "{}", f)
    };

    if matches.opt_present("h") {
        println!("{} v{}", NAME, VERSION);
        println!("");
        println!("Usage:");
        println!("  {} [OPTION]... [FILE]...", program);
        println!("");
        print!("{}", getopts::usage("Writes each file (or standard input if no files are given) to standard output whilst breaking long lines", &opts));
    } else if matches.opt_present("V") {
        println!("{} v{}", NAME, VERSION);
    } else {
        let bytes = matches.opt_present("b");
        let spaces = matches.opt_present("s");
        let poss_width =
            if matches.opt_present("w") {
                matches.opt_str("w")
            } else {
                match obs_width {
                    Some(v) => Some(v.to_string()),
                    None => None,
                }
            };
        let width = match poss_width {
            Some(inp_width) => match from_str(inp_width.as_slice()) {
                Some(width) => width,
                None => crash!(1, "illegal width value (\"{}\")", inp_width)
            },
            None => 80
        };
        let files = if matches.free.is_empty() {
            vec!("-".to_string())
        } else {
            matches.free
        };
        fold(files, bytes, spaces, width);
    }

    0
}

fn handle_obsolete(args: &[String]) -> (Vec<String>, Option<String>) {
    for (i, arg) in args.iter().enumerate() {
        let slice = arg.as_slice();
        if slice.char_at(0) == '-' && slice.len() > 1 && slice.char_at(1).is_digit(10) {
            return (args.slice_to(i).to_vec() + args.slice_from(i + 1),
                    Some(slice.slice_from(1).to_string()));
        }
    }
    (args.to_vec(), None)
}

#[inline]
fn fold(filenames: Vec<String>, bytes: bool, spaces: bool, width: uint) {
    for filename in filenames.iter() {
        let filename: &str = filename.as_slice();
        let mut stdin_buf;
        let mut file_buf;
        let buffer = BufferedReader::new(
            if filename == "-" {
                stdin_buf = io::stdio::stdin_raw();
                &mut stdin_buf as &mut Reader
            } else {
                file_buf = safe_unwrap!(File::open(&Path::new(filename)));
                &mut file_buf as &mut Reader
            }
        );
        fold_file(buffer, bytes, spaces, width);
    }
}

#[inline]
fn fold_file<T: io::Reader>(file: BufferedReader<T>, bytes: bool, spaces: bool, width: uint) {
    let mut file = file;
    for line in file.lines() {
        let line_string = safe_unwrap!(line);
        let mut line = line_string.as_slice();
        if bytes {
            let len = line.len();
            let mut i = 0;
            while i < len {
                let width = if len - i >= width { width } else { len - i };
                let slice = {
                    let slice = line.slice(i, i + width);
                    if spaces && i + width < len {
                        match slice.rfind(|ch: char| ch.is_whitespace()) {
                            Some(m) => slice.slice_to(m + 1),
                            None => slice
                        }
                    } else {
                        slice
                    }
                };
                print!("{}", slice);
                i += slice.len();
            }
        } else {
            let mut len = line.char_len();
            let newline = line.ends_with("\n");
            if newline {
                line = line.slice_to(line.len() - 1);
                len -= 1;
            }
            let mut output = String::new();
            let mut count = 0;
            for (i, ch) in line.chars().enumerate() {
                if count >= width {
                    let (val, ncount) = {
                        let slice = output.as_slice();
                        let (out, val, ncount) =
                            if spaces && i + 1 < len {
                                match rfind_whitespace(slice) {
                                    Some(m) => {
                                        let routput = slice.slice_chars(m + 1, slice.char_len());
                                        let ncount = routput.chars().fold(0u, |out, ch: char| {
                                            out + match ch {
                                                '\t' => 8,
                                                '\x08' => if out > 0 { -1 } else { 0 },
                                                '\r' => return 0,
                                                _ => 1
                                            }
                                        });
                                        (slice.slice_chars(0, m + 1), routput, ncount)
                                    },
                                    None => (slice, "", 0)
                                }
                            } else {
                                (slice, "", 0)
                            };
                        println!("{}", out);
                        (val.into_string(), ncount)
                    };
                    output = val;
                    count = ncount;
                }
                match ch {
                    '\t' => {
                        count += 8;
                        if count > width {
                            println!("{}", output);
                            output.truncate(0);
                            count = 8;
                        }
                    }
                    '\x08' => {
                        if count > 0 {
                            count -= 1;
                            let len = output.len() - 1;
                            output.truncate(len);
                        }
                        continue;
                    }
                    '\r' => {
                        output.truncate(0);
                        count = 0;
                        continue;
                    }
                    _ => count += 1
                };
                output.push(ch);
            }
            if count > 0 {
                if newline {
                    println!("{}", output);
                } else {
                    print!("{}", output);
                }
            }
        }
    }
}

#[inline]
fn rfind_whitespace(slice: &str) -> Option<uint> {
    for (i, ch) in slice.chars().rev().enumerate() {
        if ch.is_whitespace() {
            return Some(slice.char_len() - (i + 1));
        }
    }
    None
}
<commit_msg>fold: actually print out empty lines<commit_after>#![crate_name = "fold"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Arcterus <arcterus@mail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

#![feature(macro_rules)]

extern crate getopts;
extern crate libc;

use std::io;
use std::io::fs::File;
use std::io::BufferedReader;

#[path = "../common/util.rs"]
mod util;

static NAME: &'static str = "fold";
static VERSION: &'static str = "1.0.0";

pub fn uumain(args: Vec<String>) -> int {
    let (args, obs_width) = handle_obsolete(args.as_slice());
    let program = args[0].clone();

    let opts = [
        getopts::optflag("b", "bytes", "count using bytes rather than columns (meaning control characters such as newline are not treated specially)"),
        getopts::optflag("s", "spaces", "break lines at word boundaries rather than a hard cut-off"),
        getopts::optopt("w", "width", "set WIDTH as the maximum line width rather than 80", "WIDTH"),
        getopts::optflag("h", "help", "display this help and exit"),
        getopts::optflag("V", "version", "output version information and exit")
    ];

    let matches = match getopts::getopts(args.tail(), &opts) {
        Ok(m) => m,
        Err(f) => crash!(1, "{}", f)
    };

    if matches.opt_present("h") {
        println!("{} v{}", NAME, VERSION);
        println!("");
        println!("Usage:");
        println!("  {} [OPTION]... [FILE]...", program);
        println!("");
        print!("{}", getopts::usage("Writes each file (or standard input if no files are given) to standard output whilst breaking long lines", &opts));
    } else if matches.opt_present("V") {
        println!("{} v{}", NAME, VERSION);
    } else {
        let bytes = matches.opt_present("b");
        let spaces = matches.opt_present("s");
        let poss_width =
            if matches.opt_present("w") {
                matches.opt_str("w")
            } else {
                match obs_width {
                    Some(v) => Some(v.to_string()),
                    None => None,
                }
            };
        let width = match poss_width {
            Some(inp_width) => match from_str(inp_width.as_slice()) {
                Some(width) => width,
                None => crash!(1, "illegal width value (\"{}\")", inp_width)
            },
            None => 80
        };
        let files = if matches.free.is_empty() {
            vec!("-".to_string())
        } else {
            matches.free
        };
        fold(files, bytes, spaces, width);
    }

    0
}

fn handle_obsolete(args: &[String]) -> (Vec<String>, Option<String>) {
    for (i, arg) in args.iter().enumerate() {
        let slice = arg.as_slice();
        if slice.char_at(0) == '-' && slice.len() > 1 && slice.char_at(1).is_digit(10) {
            return (args.slice_to(i).to_vec() + args.slice_from(i + 1),
                    Some(slice.slice_from(1).to_string()));
        }
    }
    (args.to_vec(), None)
}

#[inline]
fn fold(filenames: Vec<String>, bytes: bool, spaces: bool, width: uint) {
    for filename in filenames.iter() {
        let filename: &str = filename.as_slice();
        let mut stdin_buf;
        let mut file_buf;
        let buffer = BufferedReader::new(
            if filename == "-" {
                stdin_buf = io::stdio::stdin_raw();
                &mut stdin_buf as &mut Reader
            } else {
                file_buf = safe_unwrap!(File::open(&Path::new(filename)));
                &mut file_buf as &mut Reader
            }
        );
        fold_file(buffer, bytes, spaces, width);
    }
}

#[inline]
fn fold_file<T: io::Reader>(file: BufferedReader<T>, bytes: bool, spaces: bool, width: uint) {
    let mut file = file;
    for line in file.lines() {
        let line_string = safe_unwrap!(line);
        let mut line = line_string.as_slice();
        if bytes {
            let len = line.len();
            let mut i = 0;
            while i < len {
                let width = if len - i >= width { width } else { len - i };
                let slice = {
                    let slice = line.slice(i, i + width);
                    if spaces && i + width < len {
                        match slice.rfind(|ch: char| ch.is_whitespace()) {
                            Some(m) => slice.slice_to(m + 1),
                            None => slice
                        }
                    } else {
                        slice
                    }
                };
                print!("{}", slice);
                i += slice.len();
            }
        } else {
            let mut len = line.char_len();
            let newline = line.ends_with("\n");
            if newline {
                if len == 1 {
                    println!("");
                    continue;
                }
                line = line.slice_to(line.len() - 1);
                len -= 1;
            }
            let mut output = String::new();
            let mut count = 0;
            for (i, ch) in line.chars().enumerate() {
                if count >= width {
                    let (val, ncount) = {
                        let slice = output.as_slice();
                        let (out, val, ncount) =
                            if spaces && i + 1 < len {
                                match rfind_whitespace(slice) {
                                    Some(m) => {
                                        let routput = slice.slice_chars(m + 1, slice.char_len());
                                        let ncount = routput.chars().fold(0u, |out, ch: char| {
                                            out + match ch {
                                                '\t' => 8,
                                                '\x08' => if out > 0 { -1 } else { 0 },
                                                '\r' => return 0,
                                                _ => 1
                                            }
                                        });
                                        (slice.slice_chars(0, m + 1), routput, ncount)
                                    },
                                    None => (slice, "", 0)
                                }
                            } else {
                                (slice, "", 0)
                            };
                        println!("{}", out);
                        (val.into_string(), ncount)
                    };
                    output = val;
                    count = ncount;
                }
                match ch {
                    '\t' => {
                        count += 8;
                        if count > width {
                            println!("{}", output);
                            output.truncate(0);
                            count = 8;
                        }
                    }
                    '\x08' => {
                        if count > 0 {
                            count -= 1;
                            let len = output.len() - 1;
                            output.truncate(len);
                        }
                        continue;
                    }
                    '\r' => {
                        output.truncate(0);
                        count = 0;
                        continue;
                    }
                    _ => count += 1
                };
                output.push(ch);
            }
            if count > 0 {
                if newline {
                    println!("{}", output);
                } else {
                    print!("{}", output);
                }
            }
        }
    }
}

#[inline]
fn rfind_whitespace(slice: &str) -> Option<uint> {
    for (i, ch) in slice.chars().rev().enumerate() {
        if ch.is_whitespace() {
            return Some(slice.char_len() - (i + 1));
        }
    }
    None
}
<|endoftext|>


<commit_before>use syntax::ast;
use syntax::ext::base::ExtCtxt;
use syntax::ext::build::AstBuilder;
use syntax::ptr::P;

use block::{Block, Describe, It, Bench};

pub trait Generate {
    fn generate(self, cx: &mut ExtCtxt, up: Option<&Describe>) -> P<ast::Item>;
}

impl Generate for Block {
    fn generate(self, cx: &mut ExtCtxt, up: Option<&Describe>) -> P<ast::Item> {
        match self {
            Block::Describe(describe) => describe.generate(cx, up),
            Block::It(it) => it.generate(cx, up),
            Block::Bench(bench) => bench.generate(cx, up)
        }
    }
}

impl Generate for Describe {
    fn generate(mut self,
                cx: &mut ExtCtxt,
                up: Option<&Describe>) -> P<ast::Item> {
        let name = cx.ident_of(&self.name);

        if let Some(ref up) = up {
            self.before = up.before.iter()
                .chain(self.before.iter())
                .cloned()
                .collect();
            self.after = self.after.iter()
                .chain(up.after.iter())
                .cloned()
                .collect();
        }

        let items = self.blocks.iter().map(|block| {
            block.clone().generate(cx, Some(&self))
        }).collect::<Vec<_>>();

        quote_item!(cx, mod $name {
            pub use super::*;
            $items
        }).unwrap()
    }
}

impl Generate for It {
    fn generate(self, cx: &mut ExtCtxt, up: Option<&Describe>) -> P<ast::Item> {
        let name = cx.ident_of(&self.name);

        let block = if let Some(ref up) = up {
            up.before.iter()
                .chain(Some(self.block).iter())
                .chain(up.after.iter())
                .cloned().collect()
        } else {
            vec![self.block]
        };

        let mut block = block.into_iter();
        let head = block.next().unwrap();
        let block = block.fold(head, merge_blocks);

        quote_item!(cx, #[test] fn $name() { $block }).unwrap()
    }
}

impl Generate for Bench {
    fn generate(self, cx: &mut ExtCtxt, up: Option<&Describe>) -> P<ast::Item> {
        let name = cx.ident_of(&self.name);

        let block = if let Some(ref up) = up {
            up.before.iter()
                .chain(Some(self.block).iter())
                .chain(up.after.iter())
                .cloned().collect()
        } else {
            vec![self.block]
        };

        let mut block = block.into_iter();
        let head = block.next().unwrap();
        let block = block.fold(head, merge_blocks);

        let ident = self.ident;
        quote_item!(cx, #[bench] fn $name($ident: &mut ::test::Bencher) {
            $block
        }).unwrap()
    }
}

fn merge_blocks(left: P<ast::Block>, right: P<ast::Block>) -> P<ast::Block> {
    P(ast::Block {
        stmts: left.stmts.iter().chain(right.stmts.iter()).cloned().collect(),
        ..(*left).clone()
    })
}
<commit_msg>Refactor `Generate::generate` for `It` and `Bench`.<commit_after>use syntax::ast;
use syntax::ext::base::ExtCtxt;
use syntax::ext::build::AstBuilder;
use syntax::ptr::P;

use block::{Block, Describe, It, Bench};

pub trait Generate {
    fn generate(self, cx: &mut ExtCtxt, up: Option<&Describe>) -> P<ast::Item>;
}

impl Generate for Block {
    fn generate(self, cx: &mut ExtCtxt, up: Option<&Describe>) -> P<ast::Item> {
        match self {
            Block::Describe(describe) => describe.generate(cx, up),
            Block::It(it) => it.generate(cx, up),
            Block::Bench(bench) => bench.generate(cx, up)
        }
    }
}

impl Generate for Describe {
    fn generate(mut self,
                cx: &mut ExtCtxt,
                up: Option<&Describe>) -> P<ast::Item> {
        let name = cx.ident_of(&self.name);

        if let Some(ref up) = up {
            self.before = up.before.iter()
                .chain(self.before.iter())
                .cloned()
                .collect();
            self.after = self.after.iter()
                .chain(up.after.iter())
                .cloned()
                .collect();
        }

        let items = self.blocks.iter().map(|block| {
            block.clone().generate(cx, Some(&self))
        }).collect::<Vec<_>>();

        quote_item!(cx, mod $name {
            pub use super::*;
            $items
        }).unwrap()
    }
}

impl Generate for It {
    fn generate(self, cx: &mut ExtCtxt, up: Option<&Describe>) -> P<ast::Item> {
        let name = cx.ident_of(&self.name);

        let blocks = if let Some(ref up) = up {
            up.before.iter()
                .chain(Some(self.block).iter())
                .chain(up.after.iter())
                .cloned().collect()
        } else {
            vec![self.block]
        };

        let mut blocks = blocks.into_iter();
        let head = blocks.next().unwrap();
        let block = blocks.fold(head, merge_blocks);

        quote_item!(cx, #[test] fn $name() { $block }).unwrap()
    }
}

impl Generate for Bench {
    fn generate(self, cx: &mut ExtCtxt, up: Option<&Describe>) -> P<ast::Item> {
        let name = cx.ident_of(&self.name);

        let blocks = if let Some(ref up) = up {
            up.before.iter()
                .chain(Some(self.block).iter())
                .chain(up.after.iter())
                .cloned().collect()
        } else {
            vec![self.block]
        };

        let mut blocks = blocks.into_iter();
        let head = blocks.next().unwrap();
        let block = blocks.fold(head, merge_blocks);

        let ident = self.ident;
        quote_item!(cx, #[bench] fn $name($ident: &mut ::test::Bencher) {
            $block
        }).unwrap()
    }
}

fn merge_blocks(left: P<ast::Block>, right: P<ast::Block>) -> P<ast::Block> {
    P(ast::Block {
        stmts: left.stmts.iter().chain(right.stmts.iter()).cloned().collect(),
        ..(*left).clone()
    })
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate quote;
extern crate reqwest;
extern crate serde_json;
#[macro_use]
extern crate error_chain;
#[macro_use]
extern crate lazy_static;

use std::fs::File;
use serde_json::{ Value, Map };
use std::collections::{ HashSet, HashMap };
use quote::{ Tokens, Ident };

mod util;

use util::*;

mod errors {
    error_chain! {
        types {
            Error, ErrorKind, ResultExt, Result;
        }

        links {
        }

        foreign_links {
            ReqwestError(::reqwest::Error);
            JsonError(::serde_json::Error);
            IoError(::std::io::Error);
        }

        errors {
            MissingSource {
                description("No source for sample specified")
            }
            ExistingType(t: String) {
                display("No code generated, JSON matches existing type {}", t)
            }
        }
    }
}

pub use errors::*;

const RUST_KEYWORDS_ARR: &'static [&'static str] = &["abstract", "alignof", "as", "become", "box",
    "break", "const", "continue", "crate", "do", "else", "enum", "extern", "false", "final", "fn",
    "for", "if", "impl", "in", "let", "loop", "macro", "match", "mod", "move", "mut", "offsetof",
    "override", "priv", "proc", "pub", "pure", "ref", "return", "Self", "self", "sizeof", "static",
    "struct", "super", "trait", "true", "type", "typeof", "unsafe", "unsized", "use", "virtual",
    "where", "while", "yield"];

lazy_static! {
    static ref RUST_KEYWORDS: HashSet<&'static str> = {
        RUST_KEYWORDS_ARR.iter().cloned().collect()
    };
}

pub enum SampleSource<'a> {
    Url(&'a str),
    File(&'a str),
    Text(&'a str),
}

pub struct Options {
    pub use_serde: bool,
    pub extern_crate: bool,
    pub runnable: bool
}

impl Default for Options {
    fn default() -> Options {
        Options {
            use_serde: true,
            extern_crate: false,
            runnable: false
        }
    }
}

struct Ctxt {
    options: Options
}

macro_rules! some_if {
    ($cond:expr, $then:expr) => ({
        if $cond {
            Some($then)
        } else {
            None
        }
    })
}

#[allow(dead_code)]
#[derive(Debug, PartialEq, Clone)]
enum InferredType {
    Null,
    Any,
    Bool,
    StringT,
    Integer,
    Floating,
    EmptyVec,
    VecT { elem_type: Box<InferredType> },
    Struct { fields: HashMap<String, InferredType> },
    Optional(Box<InferredType>)
}

#[allow(dead_code)]
fn unify(a: InferredType, b: InferredType) -> InferredType {
    if a == b {
        return a;
    }
    use InferredType::*;
    match (a, b) {
        (Integer, Floating) |
        (Floating, Integer) => Floating,
        (a, Null) | (Null, a) => make_optional(a),
        (a, Optional(b)) | (Optional(b), a) => make_optional(unify(a, *b)),
        (EmptyVec, VecT { elem_type: e }) |
        (VecT { elem_type: e }, EmptyVec) => VecT { elem_type: e },
        (VecT { elem_type: e1 }, VecT { elem_type: e2 }) => {
            VecT { elem_type: Box::new(unify(*e1, *e2)) }
        }
        (Struct { fields: f1 }, Struct { fields: f2 }) => {
            Struct { fields: unify_struct_fields(f1, f2) }
        }
        _ => Any,
    }
}

fn make_optional(a: InferredType) -> InferredType {
    use InferredType::*;
    match a {
        Null | Any | Optional(_) => a,
        non_nullable => Optional(Box::new(non_nullable)),
    }
}

fn unify_struct_fields(mut f1: HashMap<String, InferredType>,
                       mut f2: HashMap<String, InferredType>)
                       -> HashMap<String, InferredType> {
    if f1 == f2 {
        return f1;
    }
    let mut unified = HashMap::new();
    for (key, val) in f1.drain() {
        match f2.remove(&key) {
            Some(val2) => {
                unified.insert(key, unify(val, val2));
            },
            None => {
                unified.insert(key, make_optional(val));
            }
        }
    }
    for (key, val) in f2.drain() {
        unified.insert(key, make_optional(val));
    }
    unified
}

#[allow(dead_code)]
fn infer_type_from_value(ctxt: &mut Ctxt, value: &Value) -> InferredType {
    match *value {
        Value::Null => InferredType::Null,
        Value::Bool(_) => InferredType::Bool,
        Value::Number(ref n) => {
            if n.is_i64() {
                InferredType::Integer
            } else {
                InferredType::Floating
            }
        },
        Value::String(_) => InferredType::StringT,
        Value::Array(ref values) => {
            infer_type_for_array(ctxt, values)
        },
        Value::Object(ref map) => {
            InferredType::Struct { fields: infer_types_for_fields(ctxt, map) }
        }
    }
}

#[allow(dead_code)]
fn infer_type_for_array(ctxt: &mut Ctxt, values: &[Value]) -> InferredType {
    match values.split_first() {
        None => InferredType::EmptyVec,
        Some((first, rest)) => {
            let first_type = infer_type_from_value(ctxt, first);
            let inner = rest.iter().fold(first_type, |typ, val| {
                let new_type = infer_type_from_value(ctxt, val);
                unify(typ, new_type)
            });
            InferredType::VecT { elem_type: Box::new(inner) }
        }
    }
}

#[allow(dead_code)]
fn infer_types_for_fields(ctxt: &mut Ctxt, map: &Map<String, Value>) -> HashMap<String, InferredType> {
    map.iter()
        .map(|(name, value)| (name.clone(), infer_type_from_value(ctxt, value)))
        .collect()
}

pub fn from_str_with_defaults(name: &str, json: &str) -> Result<Tokens> {
    codegen(name, &SampleSource::Text(json), Options::default())
}

pub fn codegen(name: &str, source: &SampleSource, options: Options) -> Result<Tokens> {
    let sample = get_and_parse_sample(source)?;
    let mut ctxt = Ctxt {
        options: options
    };
    let (type_name, type_def) = generate_type_from_value(&mut ctxt, name, &sample);

    let example = some_if!(ctxt.options.runnable, {
        ctxt.options.extern_crate = true;
        usage_example(&type_name)
    });

    let crates = some_if!(ctxt.options.extern_crate, quote! {
        #[macro_use]
        extern crate serde_derive;
        extern crate serde_json;
    });

    if type_def.is_none() && !ctxt.options.runnable {
        return Err(ErrorKind::ExistingType(String::from(type_name.as_str())).into());
    }

    Ok(quote! {
        #crates

        #type_def

        #example
    })
}

fn usage_example(type_id: &Tokens) -> Tokens {
    let var_id = Ident::from(snake_case(type_id.as_str()));

    quote! {
        fn main() {
            let #var_id: #type_id = Default::default();

            let serialized = serde_json::to_string(&#var_id).unwrap();

            println!("serialized = {}", serialized);

            let deserialized: #type_id = serde_json::from_str(&serialized).unwrap();

            println!("deserialized = {:?}", deserialized);
        }
    }
}

fn generate_type_from_value(ctxt: &mut Ctxt, path: &str, value: &Value) -> (Tokens, Option<Tokens>) {
    match *value {
        Value::Null => (quote! { Option<::serde_json::Value> }, None),
        Value::Bool(_) => (quote! { bool }, None),
        Value::Number(ref n) => {
            if n.is_i64() {
                (quote! { i64 }, None)
            } else {
                (quote! { f64 }, None)
            }
        },
        Value::String(_) => (quote! { String }, None),
        Value::Array(ref values) => {
            generate_type_for_array(ctxt, path, values)
        },
        Value::Object(ref map) => {
            generate_struct_from_object(ctxt, path, map)
        }
    }
}

fn generate_type_for_array(ctxt: &mut Ctxt, path: &str, values: &[Value]) -> (Tokens, Option<Tokens>) {
    let mut defs = Vec::new();
    let mut types = HashSet::new();

    for value in values.iter() {
        let (elemtype, elemtype_def) = generate_type_from_value(ctxt, path, value);
        types.insert(elemtype.into_string());
        if let Some(def) = elemtype_def {
            defs.push(def);
        }
    }

    if types.len() == 1 {
        let ident = Ident::new(types.into_iter().next().unwrap());
        (quote! { Vec<#ident> }, defs.into_iter().next())
    } else {
        (quote! { Vec<::serde_json::Value> }, None)
    }
}

fn generate_struct_from_object(ctxt: &mut Ctxt, path: &str, map: &Map<String, Value>) -> (Tokens, Option<Tokens>) {
    let type_name = type_case(path);
    let ident = Ident::from(type_name);
    let mut defs = Vec::new();

    let fields: Vec<Tokens> = map.iter()
        .map(|(name, value)| {
            let mut field_name = snake_case(name);
            if RUST_KEYWORDS.contains::<str>(&field_name) {
                field_name.push_str("_field")
            }
            let rename = some_if!(&field_name != name,
                quote! { #[serde(rename = #name)] });

            let field_ident = Ident::from(field_name);
            let (fieldtype, fieldtype_def) = generate_type_from_value(ctxt, name, value);
            if let Some(def) = fieldtype_def {
                defs.push(def);
            }
            quote! {
                #rename
                #field_ident: #fieldtype
            }
        })
        .collect();

    let derives = if ctxt.options.use_serde {
        quote! { #[derive(Default, Debug, Clone, Serialize, Deserialize)] }
    } else {
        quote! { #[derive(Default, Debug, Clone)] }
    };

    let code = quote! {
        #derives
        struct #ident {
            #(#fields),*
        }

        #(#defs)*
    };

    (quote! { #ident }, Some(code))
}

pub fn infer_source_type(s: &str) -> SampleSource {
    let s = s.trim();
    if s.starts_with('{') || s.starts_with('[') {
        return SampleSource::Text(s);
    }
    if s.starts_with("http://") || s.starts_with("https://") {
        return SampleSource::Url(s);
    }
    SampleSource::File(s)
}

fn get_and_parse_sample(source: &SampleSource) -> Result<Value> {
    let parse_result = match *source {
        SampleSource::Url(url) => serde_json::de::from_reader(reqwest::get(url)?),
        SampleSource::File(path) => serde_json::de::from_reader(File::open(path)?),
        SampleSource::Text(text) => serde_json::from_str(text),
    };
    Ok(parse_result.chain_err(|| "Unable to parse JSON sample")?)
}

#[test]
fn test_unify() {
    use InferredType::*;
    assert_eq!(unify(Bool, Bool), Bool);
    assert_eq!(unify(Bool, Integer), Any);
    assert_eq!(unify(Integer, Floating), Floating);
    assert_eq!(unify(Null, Any), Any);
    assert_eq!(unify(Null, Bool), Optional(Box::new(Bool)));
    assert_eq!(unify(Null, Optional(Box::new(Integer))), Optional(Box::new(Integer)));
    assert_eq!(unify(Any, Optional(Box::new(Integer))), Any);
    assert_eq!(unify(Any, Optional(Box::new(Integer))), Any);
    assert_eq!(unify(Optional(Box::new(Integer)), Optional(Box::new(Floating))),
               Optional(Box::new(Floating)));
    assert_eq!(unify(Optional(Box::new(StringT)), Optional(Box::new(Integer))), Any);
}

// based on hashmap! macro from maplit crate
macro_rules! string_hashmap {
    ($($key:expr => $value:expr,)+) => { string_hashmap!($($key => $value),+) };
    ($($key:expr => $value:expr),*) => {
        {
            let mut _map = ::std::collections::HashMap::new();
            $(
                _map.insert($key.to_string(), $value);
            )*
            _map
        }
    };
}

#[test]
fn test_unify_struct_fields() {
    use InferredType::*;
    {
        let f1 = string_hashmap!{
            "a" => Integer,
            "b" => Bool,
            "c" => Integer,
            "d" => StringT,
        };
        let f2 = string_hashmap!{
            "a" => Integer,
            "c" => Floating,
            "d" => Null,
            "e" => Any,
        };
        assert_eq!(unify_struct_fields(f1, f2), string_hashmap!{
            "a" => Integer,
            "b" => Optional(Box::new(Bool)),
            "c" => Floating,
            "d" => Optional(Box::new(StringT)),
            "e" => Any,
        });
    }
}
<commit_msg>shared: Complete switch to inferred types<commit_after>#[macro_use]
extern crate quote;
extern crate reqwest;
extern crate serde_json;
#[macro_use]
extern crate error_chain;
#[macro_use]
extern crate lazy_static;

use std::fs::File;
use serde_json::{ Value, Map };
use std::collections::{ HashSet, HashMap };
use quote::{ Tokens, Ident };
use std::ascii::AsciiExt;

mod util;

use util::*;

mod errors {
    error_chain! {
        types {
            Error, ErrorKind, ResultExt, Result;
        }

        links {
        }

        foreign_links {
            ReqwestError(::reqwest::Error);
            JsonError(::serde_json::Error);
            IoError(::std::io::Error);
        }

        errors {
            MissingSource {
                description("No source for sample specified")
            }
            ExistingType(t: String) {
                display("No code generated, JSON matches existing type {}", t)
            }
        }
    }
}

pub use errors::*;

const RUST_KEYWORDS_ARR: &'static [&'static str] = &["abstract", "alignof", "as", "become", "box",
    "break", "const", "continue", "crate", "do", "else", "enum", "extern", "false", "final", "fn",
    "for", "if", "impl", "in", "let", "loop", "macro", "match", "mod", "move", "mut", "offsetof",
    "override", "priv", "proc", "pub", "pure", "ref", "return", "Self", "self", "sizeof", "static",
    "struct", "super", "trait", "true", "type", "typeof", "unsafe", "unsized", "use", "virtual",
    "where", "while", "yield"];

lazy_static! {
    static ref RUST_KEYWORDS: HashSet<&'static str> = {
        RUST_KEYWORDS_ARR.iter().cloned().collect()
    };
}

pub enum SampleSource<'a> {
    Url(&'a str),
    File(&'a str),
    Text(&'a str),
}

pub struct Options {
    pub extern_crate: bool,
    pub runnable: bool,
}

impl Default for Options {
    fn default() -> Options {
        Options {
            extern_crate: false,
            runnable: false,
        }
    }
}

struct Ctxt {
    options: Options,
    type_names: HashSet<String>,
    types: Vec<Tokens>,
}

macro_rules! some_if {
    ($cond:expr, $then:expr) => ({
        if $cond {
            Some($then)
        } else {
            None
        }
    })
}

#[derive(Debug, PartialEq, Clone)]
enum InferredType {
    Null,
    Any,
    Bool,
    StringT,
    Integer,
    Floating,
    EmptyVec,
    VecT { elem_type: Box<InferredType> },
    Struct { fields: HashMap<String, InferredType> },
    Optional(Box<InferredType>)
}

fn unify(a: InferredType, b: InferredType) -> InferredType {
    if a == b {
        return a;
    }
    use InferredType::*;
    match (a, b) {
        (Integer, Floating) |
        (Floating, Integer) => Floating,
        (a, Null) | (Null, a) => make_optional(a),
        (a, Optional(b)) | (Optional(b), a) => make_optional(unify(a, *b)),
        (EmptyVec, VecT { elem_type: e }) |
        (VecT { elem_type: e }, EmptyVec) => VecT { elem_type: e },
        (VecT { elem_type: e1 }, VecT { elem_type: e2 }) => {
            VecT { elem_type: Box::new(unify(*e1, *e2)) }
        }
        (Struct { fields: f1 }, Struct { fields: f2 }) => {
            Struct { fields: unify_struct_fields(f1, f2) }
        }
        _ => Any,
    }
}

fn make_optional(a: InferredType) -> InferredType {
    use InferredType::*;
    match a {
        Null | Any | Optional(_) => a,
        non_nullable => Optional(Box::new(non_nullable)),
    }
}

fn unify_struct_fields(mut f1: HashMap<String, InferredType>,
                       mut f2: HashMap<String, InferredType>)
                       -> HashMap<String, InferredType> {
    if f1 == f2 {
        return f1;
    }
    let mut unified = HashMap::new();
    for (key, val) in f1.drain() {
        match f2.remove(&key) {
            Some(val2) => {
                unified.insert(key, unify(val, val2));
            },
            None => {
                unified.insert(key, make_optional(val));
            }
        }
    }
    for (key, val) in f2.drain() {
        unified.insert(key, make_optional(val));
    }
    unified
}

fn infer_type_from_value(ctxt: &mut Ctxt, value: &Value) -> InferredType {
    match *value {
        Value::Null => InferredType::Null,
        Value::Bool(_) => InferredType::Bool,
        Value::Number(ref n) => {
            if n.is_i64() {
                InferredType::Integer
            } else {
                InferredType::Floating
            }
        },
        Value::String(_) => InferredType::StringT,
        Value::Array(ref values) => {
            infer_type_for_array(ctxt, values)
        },
        Value::Object(ref map) => {
            InferredType::Struct { fields: infer_types_for_fields(ctxt, map) }
        }
    }
}

fn infer_type_for_array(ctxt: &mut Ctxt, values: &[Value]) -> InferredType {
    match values.split_first() {
        None => InferredType::EmptyVec,
        Some((first, rest)) => {
            let first_type = infer_type_from_value(ctxt, first);
            let inner = rest.iter().fold(first_type, |typ, val| {
                let new_type = infer_type_from_value(ctxt, val);
                unify(typ, new_type)
            });
            InferredType::VecT { elem_type: Box::new(inner) }
        }
    }
}

fn infer_types_for_fields(ctxt: &mut Ctxt, map: &Map<String, Value>) -> HashMap<String, InferredType> {
    map.iter()
        .map(|(name, value)| (name.clone(), infer_type_from_value(ctxt, value)))
        .collect()
}

pub fn from_str_with_defaults(name: &str, json: &str) -> Result<Tokens> {
    codegen(name, &SampleSource::Text(json), Options::default())
}

pub fn codegen(name: &str, source: &SampleSource, options: Options) -> Result<Tokens> {
    let sample = get_and_parse_sample(source)?;
    let mut ctxt = Ctxt {
        options: options,
        type_names: HashSet::new(),
        types: Vec::new(),
    };
    let inferred = infer_type_from_value(&mut ctxt, &sample);
    let type_name = generate_type_from_inferred(&mut ctxt, name, &inferred);

    let example = some_if!(ctxt.options.runnable, {
        ctxt.options.extern_crate = true;
        usage_example(&type_name)
    });

    let crates = some_if!(ctxt.options.extern_crate, quote! {
        #[macro_use]
        extern crate serde_derive;
        extern crate serde_json;
    });

    let defs = &ctxt.types;

    Ok(quote! {
        #crates

        #(#defs)*

        #example
    })
}

fn usage_example(type_id: &Tokens) -> Tokens {
    let var_id = Ident::from(snake_case(type_id.as_str()));

    quote! {
        fn main() {
            let #var_id: #type_id = Default::default();

            let serialized = serde_json::to_string(&#var_id).unwrap();

            println!("serialized = {}", serialized);

            let deserialized: #type_id = serde_json::from_str(&serialized).unwrap();

            println!("deserialized = {:?}", deserialized);
        }
    }
}

fn generate_type_from_inferred(ctxt: &mut Ctxt, path: &str, inferred: &InferredType) -> Tokens {
    use InferredType::*;
    match *inferred {
        Null | Any => quote! { ::serde_json::Value },
        Bool => quote! { bool },
        StringT => quote! { String },
        Integer => quote! { i64 },
        Floating => quote! { f64 },
        EmptyVec => quote! { Vec<::serde_json::Value> },
        VecT { elem_type: ref e } => {
            // TODO: Depluralize path
            let inner = generate_type_from_inferred(ctxt, path, e);
            quote! { Vec<#inner> }
        }
        Struct { fields: ref map } => {
            generate_struct_from_inferred_fields(ctxt, path, map)
        }
        Optional(ref e) => {
            let inner = generate_type_from_inferred(ctxt, path, e);
            quote! { Option<#inner> }
        }
    }
}

fn field_name(name: &str, _type: &InferredType, used_names: &HashSet<String>) -> String {
    let name = name.trim();
    if let Some(c) = name.chars().next() {
        if c.is_ascii() && c.is_numeric() {
            let temp = String::from("n") + name;
            return snake_case(&temp);
        }
    }
    let mut field_name = snake_case(name);
    if RUST_KEYWORDS.contains::<str>(&field_name) {
        field_name.push_str("_field");
    }
    if field_name == "" {
        // TODO: Use type to get nicer name
        field_name.push_str("field");
    }
    if !used_names.contains(&field_name) {
        return field_name;
    }
    for n in 1.. {
        let temp = format!("{}{}", field_name, n);
        if !used_names.contains(&temp) {
            return temp;
        }
    }
    unreachable!()
}

fn generate_struct_from_inferred_fields(
        ctxt: &mut Ctxt,
        path: &str,
        map: &HashMap<String, InferredType>) -> Tokens {
    // TODO: Avoid type name collisions
    let type_name = type_case(path);
    let ident = Ident::from(type_name);

    let mut field_names = HashSet::new();

    let fields: Vec<Tokens> = map.iter()
        .map(|(name, typ)| {
            let field_name = field_name(name, typ, &field_names);
            field_names.insert(field_name.clone());
            let rename = some_if!(&field_name != name,
                quote! { #[serde(rename = #name)] });
            let field_ident = Ident::from(field_name);
            let field_type = generate_type_from_inferred(ctxt, name, typ);
            quote! {
                #rename
                #field_ident: #field_type
            }
        })
        .collect();

    let derives = quote! { #[derive(Default, Debug, Clone, Serialize, Deserialize)] };

    let code = quote! {
        #derives
        struct #ident {
            #(#fields),*
        }
    };

    ctxt.types.push(code);
    quote! { #ident }
}

pub fn infer_source_type(s: &str) -> SampleSource {
    let s = s.trim();
    if s.starts_with('{') || s.starts_with('[') {
        return SampleSource::Text(s);
    }
    if s.starts_with("http://") || s.starts_with("https://") {
        return SampleSource::Url(s);
    }
    SampleSource::File(s)
}

fn get_and_parse_sample(source: &SampleSource) -> Result<Value> {
    let parse_result = match *source {
        SampleSource::Url(url) => serde_json::de::from_reader(reqwest::get(url)?),
        SampleSource::File(path) => serde_json::de::from_reader(File::open(path)?),
        SampleSource::Text(text) => serde_json::from_str(text),
    };
    Ok(parse_result.chain_err(|| "Unable to parse JSON sample")?)
}

#[test]
fn test_unify() {
    use InferredType::*;
    assert_eq!(unify(Bool, Bool), Bool);
    assert_eq!(unify(Bool, Integer), Any);
    assert_eq!(unify(Integer, Floating), Floating);
    assert_eq!(unify(Null, Any), Any);
    assert_eq!(unify(Null, Bool), Optional(Box::new(Bool)));
    assert_eq!(unify(Null, Optional(Box::new(Integer))), Optional(Box::new(Integer)));
    assert_eq!(unify(Any, Optional(Box::new(Integer))), Any);
    assert_eq!(unify(Any, Optional(Box::new(Integer))), Any);
    assert_eq!(unify(Optional(Box::new(Integer)), Optional(Box::new(Floating))),
               Optional(Box::new(Floating)));
    assert_eq!(unify(Optional(Box::new(StringT)), Optional(Box::new(Integer))), Any);
}

// based on hashmap! macro from maplit crate
macro_rules! string_hashmap {
    ($($key:expr => $value:expr,)+) => { string_hashmap!($($key => $value),+) };
    ($($key:expr => $value:expr),*) => {
        {
            let mut _map = ::std::collections::HashMap::new();
            $(
                _map.insert($key.to_string(), $value);
            )*
            _map
        }
    };
}

#[test]
fn test_unify_struct_fields() {
    use InferredType::*;
    {
        let f1 = string_hashmap!{
            "a" => Integer,
            "b" => Bool,
            "c" => Integer,
            "d" => StringT,
        };
        let f2 = string_hashmap!{
            "a" => Integer,
            "c" => Floating,
            "d" => Null,
            "e" => Any,
        };
        assert_eq!(unify_struct_fields(f1, f2), string_hashmap!{
            "a" => Integer,
            "b" => Optional(Box::new(Bool)),
            "c" => Floating,
            "d" => Optional(Box::new(StringT)),
            "e" => Any,
        });
    }
}
<|endoftext|>


<commit_before>
use ndarray::*;
use ndarray_linalg::*;
use super::traits::*;

pub struct TimeSeries<'a, TEO, S, D>
    where S: DataMut,
          D: Dimension,
          TEO: TimeEvolutionBase<S, D> + 'a
{
    state: ArrayBase<S, D>,
    teo: &'a TEO,
}

pub fn time_series<'a, TEO, S, D>(x0: ArrayBase<S, D>, teo: &'a TEO) -> TimeSeries<'a, TEO, S, D>
    where S: DataMut,
          D: Dimension,
          TEO: TimeEvolutionBase<S, D>
{
    TimeSeries {
        state: x0,
        teo: teo,
    }
}

impl<'a, TEO, S, D> TimeSeries<'a, TEO, S, D>
    where S: DataMut + DataClone,
          D: Dimension,
          TEO: TimeEvolutionBase<S, D>
{
    pub fn iterate(&mut self) {
        self.teo.iterate(&mut self.state);
    }
}

impl<'a, TEO, S, D> Iterator for TimeSeries<'a, TEO, S, D>
    where S: DataMut + DataClone,
          D: Dimension,
          TEO: TimeEvolutionBase<S, D>
{
    type Item = ArrayBase<S, D>;
    fn next(&mut self) -> Option<Self::Item> {
        self.iterate();
        Some(self.state.clone())
    }
}

#[derive(new)]
pub struct NStep<TEO> {
    teo: TEO,
    n: usize,
}

impl<TEO, D> ModelSize<D> for NStep<TEO>
    where TEO: ModelSize<D>,
          D: Dimension
{
    fn model_size(&self) -> D::Pattern {
        self.teo.model_size()
    }
}

impl<TEO> TimeStep for NStep<TEO>
    where TEO: TimeStep
{
    type Time = TEO::Time;

    fn get_dt(&self) -> Self::Time {
        self.teo.get_dt() * into_scalar(self.n as f64)
    }

    fn set_dt(&mut self, dt: Self::Time) {
        self.teo.set_dt(dt / into_scalar(self.n as f64));
    }
}

impl<TEO, S, D> TimeEvolutionBase<S, D> for NStep<TEO>
    where TEO: TimeEvolutionBase<S, D>,
          S: DataMut,
          D: Dimension
{
    type Scalar = TEO::Scalar;
    type Time = TEO::Time;

    fn iterate<'a>(&self, x: &'a mut ArrayBase<S, D>) -> &'a mut ArrayBase<S, D> {
        for _ in 0..self.n {
            self.teo.iterate(x);
        }
        x
    }
}
<commit_msg>Add doctest<commit_after>
use ndarray::*;
use ndarray_linalg::*;
use super::traits::*;

pub struct TimeSeries<'a, TEO, S, D>
    where S: DataMut,
          D: Dimension,
          TEO: TimeEvolutionBase<S, D> + 'a
{
    state: ArrayBase<S, D>,
    teo: &'a TEO,
}

pub fn time_series<'a, TEO, S, D>(x0: ArrayBase<S, D>, teo: &'a TEO) -> TimeSeries<'a, TEO, S, D>
    where S: DataMut,
          D: Dimension,
          TEO: TimeEvolutionBase<S, D>
{
    TimeSeries {
        state: x0,
        teo: teo,
    }
}

impl<'a, TEO, S, D> TimeSeries<'a, TEO, S, D>
    where S: DataMut + DataClone,
          D: Dimension,
          TEO: TimeEvolutionBase<S, D>
{
    pub fn iterate(&mut self) {
        self.teo.iterate(&mut self.state);
    }
}

impl<'a, TEO, S, D> Iterator for TimeSeries<'a, TEO, S, D>
    where S: DataMut + DataClone,
          D: Dimension,
          TEO: TimeEvolutionBase<S, D>
{
    type Item = ArrayBase<S, D>;
    fn next(&mut self) -> Option<Self::Item> {
        self.iterate();
        Some(self.state.clone())
    }
}

/// N-step adaptor
///
/// ```rust
/// use ndarray_odeint::*;
/// let teo = explicit::rk4(model::Lorenz63::default(), 0.01);
/// let nstep = nstep(teo, 10);
/// ```
pub struct NStep<TEO> {
    teo: TEO,
    n: usize,
}

pub fn nstep<TEO>(teo: TEO, n: usize) -> NStep<TEO> {
    NStep { teo, n }
}

impl<TEO, D> ModelSize<D> for NStep<TEO>
    where TEO: ModelSize<D>,
          D: Dimension
{
    fn model_size(&self) -> D::Pattern {
        self.teo.model_size()
    }
}

impl<TEO> TimeStep for NStep<TEO>
    where TEO: TimeStep
{
    type Time = TEO::Time;

    fn get_dt(&self) -> Self::Time {
        self.teo.get_dt() * into_scalar(self.n as f64)
    }

    fn set_dt(&mut self, dt: Self::Time) {
        self.teo.set_dt(dt / into_scalar(self.n as f64));
    }
}

impl<TEO, S, D> TimeEvolutionBase<S, D> for NStep<TEO>
    where TEO: TimeEvolutionBase<S, D>,
          S: DataMut,
          D: Dimension
{
    type Scalar = TEO::Scalar;
    type Time = TEO::Time;

    fn iterate<'a>(&self, x: &'a mut ArrayBase<S, D>) -> &'a mut ArrayBase<S, D> {
        for _ in 0..self.n {
            self.teo.iterate(x);
        }
        x
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2014 The 6502-rs Developers
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.
// 3. Neither the names of the copyright holders nor the names of any
//    contributors may be used to endorse or promote products derived from this
//    software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

// The idea here is that it doesn't make sense to add two addresses, but it
// does make sense to add an address and an "address-difference". (If this
// is too annoying to work with we should let it go.)
#[deriving(Copy, PartialEq, Eq, PartialOrd, Ord, Show)]
pub struct AddressDiff(pub i32);

#[deriving(Copy, PartialEq, Eq, PartialOrd, Ord, Show)]
pub struct Address(pub u16);

impl Add<AddressDiff, Address> for Address {
    fn add(self, AddressDiff(rhs): AddressDiff) -> Address {
        let Address(lhs) = self;

        // TODO akeeton: Do a checked cast.
        Address(((lhs as i32) + rhs) as u16)
    }
}

impl Add<AddressDiff, AddressDiff> for AddressDiff {
    fn add(self, AddressDiff(rhs): AddressDiff) -> AddressDiff {
        let AddressDiff(lhs) = self;
        AddressDiff(lhs + rhs)
    }
}

// rustc doesn't seem to like having multiple implementations of Add for
// Address. I believe this is a Rust bug (possibly resolved by "associated
// types" RFC?). Or I wrote it wrong. Anyway, here's some living dead code:
/*
#[deriving(PartialEq, Eq, PartialOrd, Ord)]
pub struct CheckedAddressDiff(u16);

impl Add<CheckedAddressDiff, Address> for Address {
    fn add(&self, &CheckedAddressDiff(rhs): &CheckedAddressDiff) -> Address {
        let &Address(lhs) = self;

        // We probably don't want to overflow when doing arithmetic in our own
        // code.
        debug_assert!({
            match lhs.checked_add(&rhs) {
                None => false,
                _ => true
            }
        });

        Address(lhs + rhs)
    }
}
*/

impl Address {
    pub fn to_u16(&self) -> u16 {
        match *self {
            Address(address_) => address_
        }
    }

    pub fn to_uint(&self) -> uint {
        self.to_u16() as uint
    }

    pub fn get_page_number(&self) -> u8 {
        (self.to_u16() & 0xff00 >> 8) as u8
    }

    pub fn get_offset(&self) -> u8 {
        (self.to_u16() & 0x00ff) as u8
    }
}

<commit_msg>Reintroduce CheckedAddressDiff now that multidispatch works<commit_after>// Copyright (C) 2014 The 6502-rs Developers
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.
// 3. Neither the names of the copyright holders nor the names of any
//    contributors may be used to endorse or promote products derived from this
//    software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

use std::num::Int;

// The idea here is that it doesn't make sense to add two addresses, but it
// does make sense to add an address and an "address-difference". (If this
// is too annoying to work with we should let it go.)
#[deriving(Copy, PartialEq, Eq, PartialOrd, Ord, Show)]
pub struct AddressDiff(pub i32);

#[deriving(Copy, PartialEq, Eq, PartialOrd, Ord, Show)]
pub struct Address(pub u16);

impl Add<AddressDiff, Address> for Address {
    fn add(self, AddressDiff(rhs): AddressDiff) -> Address {
        let Address(lhs) = self;

        // TODO akeeton: Do a checked cast.
        Address(((lhs as i32) + rhs) as u16)
    }
}

impl Add<AddressDiff, AddressDiff> for AddressDiff {
    fn add(self, AddressDiff(rhs): AddressDiff) -> AddressDiff {
        let AddressDiff(lhs) = self;
        AddressDiff(lhs + rhs)
    }
}

#[deriving(Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct CheckedAddressDiff(u16);

impl Add<CheckedAddressDiff, Address> for Address {
    fn add(self, CheckedAddressDiff(rhs): CheckedAddressDiff) -> Address {
        let Address(lhs) = self;

        // We probably don't want to overflow when doing arithmetic in our own
        // code.
        debug_assert!(lhs.checked_add(rhs).is_some());

        Address(lhs + rhs)
    }
}

impl Address {
    pub fn to_u16(&self) -> u16 {
        match *self {
            Address(address_) => address_
        }
    }

    pub fn to_uint(&self) -> uint {
        self.to_u16() as uint
    }

    pub fn get_page_number(&self) -> u8 {
        (self.to_u16() & 0xff00 >> 8) as u8
    }

    pub fn get_offset(&self) -> u8 {
        (self.to_u16() & 0x00ff) as u8
    }
}

<|endoftext|>


<commit_before>#![deny(warnings)]

extern crate extra;

use std::env;
use std::io::{stdout, stderr, Write};
use extra::io::WriteExt;
use extra::option::OptionalExt;

const MAN_PAGE: &'static str = /* @MANSTART{yes} */ r#"
NAME
    yes - print the letter y or a given word, forever.

SYNOPSIS
    yes [ [ -h | --help ] | [ word ] ]

DESCRIPTION
    The yes utility prints the word passed as an operand, forever. If no operand is passed, then
    it defaults to the letter 'y'.

OPTIONS
    -h
    --help
        Print this manual page.
"#; /* @MANEND */

fn main() {
    let stdout = stdout();
    let mut stdout = stdout.lock();
    let mut stderr = stderr();

    if env::args().count() == 2 {
        if let Some(arg) = env::args().nth(1) {
            if arg == "--help" || arg == "-h" {
                stdout.write_all(MAN_PAGE.as_bytes()).try(&mut stderr);
                stdout.flush().try(&mut stderr);
                return;
            }
        }
    }

    if env::args().count() >= 2 {
        let answer = env::args().skip(1).collect::<Vec<_>>().join(" ");
        let print = answer.as_bytes();
        loop {
            stdout.writeln(print).try(&mut stderr);
        }
    } else {
        loop {
            stdout.writeln(b"y").try(&mut stderr);
        }
    };
}
<commit_msg>Update yes.rs with `ArgParser`<commit_after>#![deny(warnings)]

extern crate coreutils;
extern crate extra;

use std::env;
use std::io::{stdout, stderr, Write};
use coreutils::{ArgParser, Flag};
use extra::io::WriteExt;
use extra::option::OptionalExt;

const MAN_PAGE: &'static str = /* @MANSTART{yes} */ r#"
NAME
    yes - print the letter y or a given word, forever.

SYNOPSIS
    yes [ [ -h | --help ] | [ word ] ]

DESCRIPTION
    The yes utility prints the word passed as an operand, forever. If no operand is passed, then
    it defaults to the letter 'y'.

OPTIONS
    -h
    --help
        Print this manual page.
"#; /* @MANEND */

fn main() {
    let stdout = stdout();
    let mut stdout = stdout.lock();
    let mut stderr = stderr();
    let mut parser = ArgParser::new(1)
        .add_flag("h", "help");
    parser.initialize(env::args());

    if parser.enabled_flag(Flag::Long("help")) {
        stdout.write_all(MAN_PAGE.as_bytes()).try(&mut stderr);
        stdout.flush().try(&mut stderr);
        return;
    }

    if parser.args.is_empty() {
        loop {
            stdout.writeln(b"y").try(&mut stderr);
        }
    }
    else {
        let answer = parser.args.join(" ");
        let print = answer.as_bytes();
        loop {
            stdout.writeln(print).try(&mut stderr);
        }
    }
}
<|endoftext|>


<commit_before>use std::num::Wrapping;
use basetypes::*;

// Useful square-sets
pub const UNIVERSAL_SET: u64 = 0xffffffffffffffff;
pub const EMPTY_SET: u64 = 0;

#[inline(always)]
pub fn ls1b(x: u64) -> u64 {
    (x as i64 & (Wrapping(0) - Wrapping(x as i64)).0) as u64
}

#[inline(always)]
pub fn clear_ls1b(x: &mut u64) {
    *x &= (Wrapping(*x) - Wrapping(1)).0;
}

#[inline(always)]
pub fn above_ls1b_mask(x: u64) -> u64 {
    assert!(x != 0);
    (x as i64 ^ (Wrapping(0) - Wrapping(x as i64)).0) as u64
}

#[inline(always)]
pub fn below_lsb1_mask_including(x: u64) -> u64 {
    assert!(x != 0);
    x ^ (x - 1)
}

#[inline(always)]
pub fn below_lsb1_mask(x: u64) -> u64 {
    assert!(x != 0);
    !x & (x - 1)
}

#[inline(always)]
pub fn smeared_ls1b_up(x: u64) -> u64 {
    assert!(x != 0);
    ((x as i64) | (Wrapping(0) - Wrapping(x as i64)).0) as u64
}

#[inline(always)]
pub fn smeared_ls1b_down(x: u64) -> u64 {
    assert!(x != 0);
    x | (x - 1)
}

#[inline]
pub fn bitscan_forward(b: u64) -> Square {
    const DEBRUIJN64: Wrapping<u64> = Wrapping(0x03f79d71b4cb0a89);
    static INDEX64: [Square; 64] = [0, 1, 48, 2, 57, 49, 28, 3, 61, 58, 50, 42, 38, 29, 17, 4, 62,
                                    55, 59, 36, 53, 51, 43, 22, 45, 39, 33, 30, 24, 18, 12, 5, 63,
                                    47, 56, 27, 60, 41, 37, 16, 54, 35, 52, 21, 44, 32, 23, 11,
                                    46, 26, 40, 15, 34, 20, 31, 10, 25, 14, 19, 9, 13, 8, 7, 6];
    assert!(b != 0);
    INDEX64[((Wrapping(ls1b(b)) * DEBRUIJN64).0 >> 58) as usize]
}

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

    #[test]
    fn test_ls1b_functions() {
        assert_eq!(ls1b(0x100100), 0x100);
        assert_eq!(ls1b(0x8000000000000000), 0x8000000000000000);
        assert_eq!(ls1b(0xf800000000000000), 0x0800000000000000);
        assert_eq!(ls1b(0), 0);
        let mut x = 0x100100u64;
        clear_ls1b(&mut x);
        assert_eq!(x, 0x100000);
        clear_ls1b(&mut x);
        assert_eq!(x, 0);
        clear_ls1b(&mut x);
        assert_eq!(x, 0);
        assert_eq!(above_ls1b_mask(0b11101000), 0xfffffffffffffff0);
        assert_eq!(above_ls1b_mask(0x8000000000000000), 0);
        assert_eq!(below_lsb1_mask_including(0b11101000), 0b1111);
        assert_eq!(below_lsb1_mask(0b11101000), 0b111);
        assert_eq!(smeared_ls1b_up(0b1010000), 0xfffffffffffffff0);
        assert_eq!(smeared_ls1b_up(0x8000000000000000), 0x8000000000000000);
        assert_eq!(smeared_ls1b_down(0b1010000), 0b1011111);
    }

    #[test]
    fn test_bitscan() {
        assert_eq!(bitscan_forward(0b1001101), 0);
        assert_eq!(bitscan_forward(0b1001000), 3);
        assert_eq!(bitscan_forward(0xf000000000000000), 60);
    }

}
<commit_msg>Added bitscan_and_clear().<commit_after>use std::num::Wrapping;
use basetypes::*;

// Useful square-sets
pub const UNIVERSAL_SET: u64 = 0xffffffffffffffff;
pub const EMPTY_SET: u64 = 0;

#[inline(always)]
pub fn ls1b(x: u64) -> u64 {
    (x as i64 & (Wrapping(0) - Wrapping(x as i64)).0) as u64
}

#[inline(always)]
pub fn clear_ls1b(x: &mut u64) {
    *x &= (Wrapping(*x) - Wrapping(1)).0;
}

#[inline(always)]
pub fn above_ls1b_mask(x: u64) -> u64 {
    assert!(x != 0);
    (x as i64 ^ (Wrapping(0) - Wrapping(x as i64)).0) as u64
}

#[inline(always)]
pub fn below_lsb1_mask_including(x: u64) -> u64 {
    assert!(x != 0);
    x ^ (x - 1)
}

#[inline(always)]
pub fn below_lsb1_mask(x: u64) -> u64 {
    assert!(x != 0);
    !x & (x - 1)
}

#[inline(always)]
pub fn smeared_ls1b_up(x: u64) -> u64 {
    assert!(x != 0);
    ((x as i64) | (Wrapping(0) - Wrapping(x as i64)).0) as u64
}

#[inline(always)]
pub fn smeared_ls1b_down(x: u64) -> u64 {
    assert!(x != 0);
    x | (x - 1)
}

const DEBRUIJN64: Wrapping<u64> = Wrapping(0x03f79d71b4cb0a89);
static INDEX64: [Square; 64] = [0, 1, 48, 2, 57, 49, 28, 3, 61, 58, 50, 42, 38, 29, 17, 4, 62,
                                55, 59, 36, 53, 51, 43, 22, 45, 39, 33, 30, 24, 18, 12, 5, 63,
                                47, 56, 27, 60, 41, 37, 16, 54, 35, 52, 21, 44, 32, 23, 11,
                                46, 26, 40, 15, 34, 20, 31, 10, 25, 14, 19, 9, 13, 8, 7, 6];
#[inline]
pub fn bitscan_forward(b: u64) -> Square {
    assert!(b != 0);
    INDEX64[((Wrapping(ls1b(b)) * DEBRUIJN64).0 >> 58) as usize]
}

#[inline]
pub fn bitscan_and_clear(b: &mut u64) -> Square {
    assert!(*b != 0);
    let ls1b = ls1b(*b);
    *b &= !ls1b;
    INDEX64[((Wrapping(ls1b) * DEBRUIJN64).0 >> 58) as usize]
}

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

    #[test]
    fn test_ls1b_functions() {
        assert_eq!(ls1b(0x100100), 0x100);
        assert_eq!(ls1b(0x8000000000000000), 0x8000000000000000);
        assert_eq!(ls1b(0xf800000000000000), 0x0800000000000000);
        assert_eq!(ls1b(0), 0);
        let mut x = 0x100100u64;
        clear_ls1b(&mut x);
        assert_eq!(x, 0x100000);
        clear_ls1b(&mut x);
        assert_eq!(x, 0);
        clear_ls1b(&mut x);
        assert_eq!(x, 0);
        assert_eq!(above_ls1b_mask(0b11101000), 0xfffffffffffffff0);
        assert_eq!(above_ls1b_mask(0x8000000000000000), 0);
        assert_eq!(below_lsb1_mask_including(0b11101000), 0b1111);
        assert_eq!(below_lsb1_mask(0b11101000), 0b111);
        assert_eq!(smeared_ls1b_up(0b1010000), 0xfffffffffffffff0);
        assert_eq!(smeared_ls1b_up(0x8000000000000000), 0x8000000000000000);
        assert_eq!(smeared_ls1b_down(0b1010000), 0b1011111);
    }

    #[test]
    fn test_bitscan() {
        assert_eq!(bitscan_forward(0b1001101), 0);
        assert_eq!(bitscan_forward(0b1001000), 3);
        assert_eq!(bitscan_forward(0xf000000000000000), 60);
        let mut b = 0b1100100;
        assert_eq!(bitscan_and_clear(&mut b), 2);
        assert_eq!(b, 0b1100000);
    }

}
<|endoftext|>